Skip to content

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
One line per dispatch: the profile, and the model the harness reported.

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.

  1. bottega new

    Worktree, branch, and a task.md holding your request verbatim.

  2. bottega plan

    One planner dispatch. Answer its questions in task.md and plan again.

  3. bottega approve the human gate

    The gate. Plan hash, roles and cap recorded.

  4. bottega run

    Rounds up to the cap, then the judge. Exit 0 done, 3 stopped.

  5. bottega pr

    Commit if needed, push to origin, open the pull request.

  6. 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 run refuses, 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.

  1. dispatch-failed

    The harness failed to start, exited non-zero, reported an error or left no final message: stop.

  2. identity-mismatch

    The reported model is neither the one requested nor an alias: stop.

  3. role-modified-worktree

    A planner, reviewer or judge changed a tracked file or HEAD: stop.

  4. implementer done

    The reviewer is next. A commit is a warning, not a stop.

  5. reviewer signals

    ready: the judge, or done. blocked: stop. needs-work or no signal: the next round, or cap-reached.

  6. 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. 1

    planner

    Reads the repository. Writes the plan or asks questions.

    may change
    nothing

    its product
    the plan in task.md

    no signal

  2. 2

    implementer

    Works the to-do items, adds tests, ticks boxes.

    may change
    the worktree and task.md boxes; never commits or pushes

    its product
    a summary, in the receipt

    no signal

  3. 3

    reviewer

    Checks every ticked item, runs the tests and the manual QA.

    may change
    nothing: a changed tracked file stops the task

    its product
    Review Findings in task.md

    readyneeds-workblocked

  4. 4

    judge

    Optional. Reads the plan and the diff, says whether to merge.

    may change
    nothing

    its product
    Verdict in task.md

    readyneeds-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.

Get started → The process Changelog

Terminal

npx bottega-kit
bottega init
bottega doctor