machine #
A Pi extension and Letta Code mod for parametric learning.
Tag the last turn as a good or bad example, reconstruct the full user → tool-call → result → answer trajectory, and run Tinker SFT.
Install #
Pi #
Install Machine from Tangled:
pi install git:tangled.org/cameron.stream/machine
To use a local checkout instead, run this command from the repository root:
pi install .
Start Pi after installation. If Pi is already running, run /reload.
Machine now includes the Tinker provider and /tinker commands. Uninstall
pi-tinker if it is still listed in Pi packages, or /tinker will be
registered twice.
Letta Code #
From the repository root, create a regular mod file that re-exports the local
Machine mod. Letta Code skips symlinks in ~/.letta/mods.
mkdir -p ~/.letta/mods
printf 'export { default } from "%s/mods/machine.ts";\n' "$PWD" \
> ~/.letta/mods/machine.ts
Then /reload in Letta Code. The same store and commands are used on both hosts.
To chat as Inkling from Letta (not only train through Python), also install
the local Tinker provider. Static provider-mod model ids cannot contain /,
so the catalog is published from listModels:
printf 'export { default } from "%s/mods/tinker-provider.ts";\n' "$PWD" \
> ~/.letta/mods/tinker.ts
Set TINKER_API_KEY, /reload, then /machine student. Chat handles:
/machine student thinkingmachines/Inkling-Small:peft:262144
/machine student Qwen/Qwen3.8-27B:peft:262144
This is local-agent only; it does not add Tinker to Letta Cloud.
Python 3.11+ is required for Tinker/Inkling. From this repo:
uv venv --python 3.12 .venv
uv pip install -p .venv/bin/python -U tinker-cookbook tml-renderers
/train uses .venv/bin/python from the machine package or the current project if it exists.
Commands #
/good
/good --as "The exact answer you want the model to learn."
/good --trace
/machine auto on
/machine data
/machine fork use Julia, not Python
/machine correction --id c0ffee123456 use Julia, not Python
/machine student
/machine work
/bad too terse
/tagged
| Command | Writes | What is saved |
|---|---|---|
/good |
Machine store train.jsonl |
Last user + last spoken assistant answer |
/good --trace |
Machine store traces.jsonl |
Full last-turn trajectory, explicitly judged good |
/bad |
Machine store rejected.jsonl |
Same shape as /good, kept out of SFT |
/tagged |
— | Lists recent rows |
/machine auto |
Machine store observed.jsonl |
Unlabeled compact-boundary and finished -p/JSON runs (off by default) |
/machine data |
— | Shows this project's store, files, row counts, and auto-capture setting |
/machine fork |
— | Retriggers the latest observed headless run with an optional correction via pi -p |
/machine correction --id |
— | Retriggers a specific observed/traces/train row via pi -p |
Options:
| Option | Meaning |
|---|---|
leftover args / --note |
Why this turn was tagged |
--as / --rewrite |
Override the final assistant text |
--trace / --trajectory |
Reconstruct tool calls and results |
--reasoning |
Keep thinking blocks in the trajectory |
--out |
Write somewhere else |
/good is for tone / final-answer SFT. /good --trace is for behavior
cloning. Train traces with TrainOnWhat.ALL_ASSISTANT_MESSAGES so tool
results stay in context and are not the loss target.
Data storage #
Machine keeps captured conversations outside the working tree. Each project gets a directory named from the project and a hash of its absolute path:
| Platform | Default base directory |
|---|---|
| All | ~/.machine |
Run /machine data to see the exact directory. Set MACHINE_DATA_DIR to override the base; Machine still creates a separate subdirectory for each project. On POSIX systems, Machine creates directories with mode 0700 and files with mode 0600.
Automatic capture is off until you run /machine auto on. The setting persists per project. Automatic rows use tag: "observed"; finishing a run or reaching compaction does not mark the behavior good. Only /good creates positive training examples. Full trajectories can contain tool output, source text, and other private material, so inspect them before training or copying them elsewhere.
After a batch of headless pi -p runs, review or correct the latest observation without treating it as /good:
machine data
machine observed
machine fork use the existing helper instead of rewriting it
machine fork (and /machine fork) builds a follow-up prompt from the latest auto-headless/observed user turn and assistant answer plus your correction, then execs pi -p with MACHINE_FORK=1 when pi is on PATH. Otherwise it prints the prompt and the command. Install the CLI from this package (npm link / npm install -g, or run scripts/machine-cli.mjs).
Versions before 0.2.0 wrote under the working tree's data/ directory. Machine does not move those files automatically. Review them, then pass an old path explicitly or copy only the rows you want into the new store.
Training #
/train validate
/train sft --force
/train smoke --yes
/train eval init --force
/train eval baseline --yes
Without a path, /train validate and /train sft use the explicitly judged train.jsonl in the Machine store. Pass another path only when you intend to train from a different reviewed dataset. /train sft writes train_sft.py and tinker.yaml pointed at the selected JSONL.
/train smoke runs two training steps. API-using commands need --yes.
The trajectory field on a --trace row is a Letta-style record list
(user / assistant / assistant+tool_calls / tool). See
https://www.letta.com/blog/trajectory/
Behavior releases #
Machine treats checkpoint activation as a release decision rather than a
training side effect. BR-001
preregisters the first project-local candidate: reliable Pi file repair with
fixed training bounds, frozen regression gates, external holdouts, and an
explicit trial before default-student eligibility.
Examples #
examples/project-euler/— sequential multilingual Project Euler agents with Docker-confined Pi evaluation, correlated mutation/execution scoring, frozen transfer tasks, hidden parameterized variants, bounded tool RL, mastery gates, and receipts.examples/minimal-sft/— the smallest complete loop: a self-authored corpus,/train validate→sft→smoke→eval, and a measured baseline-vs-checkpoint delta on a strict answer style.
Example corpora, answer keys, rollouts, and checkpoints are not bundled. Each example documents its own provenance, license, setup, metrics, and limitations.
Files #
extensions/machine.ts Pi: /good, /bad, /tagged, /machine
extensions/train.ts Pi: /train validate, sft, smoke, eval
extensions/tinker.ts Pi: Tinker provider + /tinker (use, sft, inkling, …)
mods/machine.ts Letta Code: same commands via getHistory() + events
mods/tinker-provider.ts Letta Code: local Tinker chat provider
lib/cli.ts shared arg parsing and JSONL helpers
lib/examples.ts tagged JSONL rows, short ids, lookup
lib/fork.ts machine CLI: data, observed, fork, correction --id
scripts/machine-cli.mjs machine binary
lib/report.ts Pi report rendering
lib/storage.ts private per-project data paths and settings
lib/statusline.ts Pi footer: last-turn nudge and dataset counts
lib/tinker-catalog.ts shared Tinker chat catalog (Inkling, Qwen, checkpoints)
lib/trajectory.ts Pi session → trajectory reconstruction
lib/letta-trajectory.ts Letta getHistory() → trajectory reconstruction
lib/python.ts platform-specific virtual-environment lookup
skills/ Tinker research and debug skills
templates/ generated Python
scripts/machine-cli.mjs `machine` CLI (help, data, observed, fork)
docs/commands.md Command reference
docs/tinker/ /tinker command and coding-agent docs
CHANGELOG.md release notes
- TypeScript 78%
- JavaScript 16%
- Python 6%