Local coding-agent loop · Claude Code + Codex
You approve the plan. The agents do the rounds.
A planner writes the plan. You approve it once. Implementer and reviewer take the rounds, up to a cap; a judge says whether to merge. Then a pull request. Every dispatch leaves a receipt.
Get started → Watch a task run ↓
$ bottega plan dry-run-flag001 planner fable claude-fable-5-1 → planned (2m41s)$ bottega approve dry-run-flagapproved 20261017-0930-add-a-dry-run-flag planner fable (claude, claude-fable-5-1, effort max) implementer opus-builder (claude, claude-opus-5-5, effort high) reviewer opus-reviewer (claude, claude-opus-5-5, effort high) judge fable (claude, claude-fable-5-1, effort max)rounds 3plan sha256 9c1e4b7d02aato-do 7 item(s), T1..T7; 7 new id(s)next: bottega run 20261017-0930-add-a-dry-run-flag$ bottega run dry-run-flag002 implementer opus-builder claude-opus-5-5 → done (6m02s)003 reviewer opus-reviewer claude-opus-5-5 → needs-work (2m14s)004 implementer opus-builder claude-opus-5-5 → done (3m40s)005 reviewer opus-reviewer claude-opus-5-5 → ready (1m55s)006 judge fable claude-fable-5-1 → ready (48s)$ bottega pr dry-run-flaghttps://github.com/you/your-repo/pull/42 01
Six commands
Six commands. Nothing runs in the background.
A round is one implementer pass and one reviewer pass. The cap is 3 unless you change it.
-
bottega new
Worktree, branch, and a
task.mdholding your request verbatim. -
bottega plan
One planner dispatch. Answer its questions in
task.mdand plan again. -
bottega approve the human gate
The gate. Plan hash, roles and cap recorded.
-
bottega run
Rounds up to the cap, then the judge. Exit 0 done, 3 stopped.
-
bottega pr
Commit if needed, push to origin, open the pull request.
-
bottega resume
After a stop, with a fresh cap. The only retry.
02
The rules
Made to be left alone with a branch.
After approval, nobody asks you anything.
-
One gate: the plan.
Approval records the plan hash. Edit the plan afterwards and
runrefuses, exit 2. -
Reviewers review. They do not fix.
The worktree is hashed before and after every planner, reviewer and judge run. A changed tracked file stops the task.
-
No retries. No fallbacks. No model of its own.
A failed dispatch stops the task; you resume it. A different reported model stops it too.
-
Mix vendors, per role.
Fable plans, Codex builds, GLM reviews on Z.AI's endpoint, without your Anthropic credentials.
03
The loop
After every dispatch, the first rule that matches.
Nothing is retried or substituted.
- dispatch-failed
The harness failed to start, exited non-zero, reported an error or left no final message: stop.
- identity-mismatch
The reported model is neither the one requested nor an alias: stop.
- role-modified-worktree
A planner, reviewer or judge changed a tracked file or HEAD: stop.
- implementer done
The reviewer is next. A commit is a warning, not a stop.
- reviewer signals
ready: the judge, or done. blocked: stop. needs-work or no signal: the next round, or cap-reached.
- judge signals
ready: done. Anything else: stop, judge-needs-work.
Ctrl-C stops a task as interrupted; bottega resume continues it. The process, step by step →
04
The roles
Four roles. One document between them.
Agents share only task.md and report with bottega signal. The kit decides from that, never from prose.
-
1
planner
Reads the repository. Writes the plan or asks questions.
may change
nothingits product
the plan intask.mdno signal
-
2
implementer
Works the to-do items, adds tests, ticks boxes.
may change
the worktree andtask.mdboxes; never commits or pushesits product
a summary, in the receiptno signal
-
3
reviewer
Checks every ticked item, runs the tests and the manual QA.
may change
nothing: a changed tracked file stops the taskits product
Review Findings intask.mdreadyneeds-workblocked
-
4
judge
Optional. Reads the plan and the diff, says whether to merge.
may change
nothingits product
Verdict intask.mdreadyneeds-work
Bind each role to a profile.
A profile is a harness, a model and an effort. bottega init writes this starter when it finds both CLIs. Fable plans and judges, Opus builds and reviews. A Claude profile on another endpoint runs with 8 Anthropic variables removed. Every setting →
~/.config/bottega-kit/config.json
{
"schema_version": 1,
"profiles": {
"fable" {"harness": "claude", "model": "claude-fable-5-1", "effort": "max"},
"opus-builder" {"harness": "claude", "model": "claude-opus-5-5", "effort": "high"},
"opus-reviewer" {"harness": "claude", "model": "claude-opus-5-5", "effort": "high"},
"sol-builder" {"harness": "codex", "model": "gpt-5.6-sol", "effort": "high"}
},
"roles": {"planner": "fable", "implementer": "opus-builder", "reviewer": "opus-reviewer", "judge": "fable"},
"rounds": 3
} 05
The harnesses
Two harnesses, the narrowest permissions each offers.
Every flag in one table, pinned by a test. Shown: the implementer's command.
claude
Claude Code, headless. Read tools only for the planner; git push and gh denied to the implementer and reviewer.
Effort low · medium · high · xhigh · max.
implementer
claude -p --model <model> --effort <effort> --output-format stream-json --verbose --permission-prompts none --setting-sources '' --strict-mcp-config --mcp-config '{"mcpServers":{}}' --settings '{"disableAllHooks":true}' --disable-slash-commands --no-session-persistence --add-dir '<task dir>' --permission-mode acceptEdits --tools Read,Edit,Write,Glob,Grep,Bash --allowedTools Bash --disallowedTools 'Bash(git push *)' 'Bash(gh *)' codex
Codex CLI, exec. Read-only sandbox for the planner, workspace-write for the rest; network blocked by default. No model is reported, so the receipt says requested-only.
Effort none · minimal · low · medium · high · xhigh · max.
implementer
codex exec -m <model> -c 'model_reasoning_effort="<effort>"' -c 'approval_policy="never"' -c 'mcp_servers={}' -c features.multi_agent=false --json -o '<run dir>/output.md' --ephemeral --color never -C <worktree> --sandbox workspace-write --add-dir '<task dir>' - Before each release a live run replaces the verified snapshot. What was verified for 0.1.0 →
06
The receipt
What every dispatch leaves behind.
One directory per dispatch, outside the repository, so it outlives the worktree. Variable names, never values. MIT; you pay your providers.
- prompt.md the prompt, exactly as sent
- output.md the final message
- events.jsonl the harness's raw output
- run.json requested and reported model, argv, timings, usage, cost
- error.json on failure: phase, reason, last stderr lines
- signal.json what the agent signalled, and when
07
Install
One command. Then bottega new.
You need git, gh, python3 3.9 or newer, and claude or codex, logged in. bottega-kit never handles their credentials. init writes a starter; doctor checks it.
Terminal
npx bottega-kit
bottega init
bottega doctor