Configuration Cookbook

On this page

Everything in the distribution is tuned with small JSON files. This page is recipes: find the one that matches what you want, copy it, adjust, restart pi.

Where your settings live:

File What it controls

~/.pi/agent/gadhs-pi-modes.json

Your personal overlay on the modes system — models, rules, the judge, guards. Merges over the package defaults (rules can only get stricter).

~/.pi/agent/vertex-models.json

Your model catalog for Vertex — Claude, Gemini and the MaaS models: which models, which publisher kind, which regions, thinking budgets, auth-retry behaviour.

~/.pi/agent/gadhs-pi-workflow.json

Operational knobs for the workflow guards: the reflection review’s time bound, the review-context caps and the reviewer’s snapshot caps. Optional; the guards' decisions are not tunable.

~/.pi/agent/gadhs-pi-agents.json

A different model per seeded helper (Explore, Research, Verify). Optional; the file stays managed and keeps receiving prompt updates — only the model: line is yours.

~/.pi/agent/settings.json

Ordinary pi settings — including your theme.

<repo>/.pi/gadhs-guidance.md

Project-specific guidance injected for everyone working in that repo.

After editing, restart pi (mode and model changes need a fresh session).

Back to the package defaults

Package upgrades never touch the files above, which is also how tuning drifts: an overlay written for one preference keeps applying long after the reason is forgotten. /gadhs-reset lists the local tuning in force - each file, what it changes in your terms (the modes overlay’s carve-outs, the helper model overrides, the catalog entries) - and /gadhs-reset --apply, after a confirm, moves each file to a dated .bak beside it. Nothing is deleted; restart pi and the packages re-seed the agents and the permission config and read their packaged defaults. Two things it will not move: a file reached through an environment variable (GADHS_PI_MODES_CONFIG, VERTEX_CONFIG) - it names the variable and leaves the file, since moving it would leave the variable pointing at nothing - and a seeded agent file that still carries its gadhs_managed marker, which the package updates already. The files are found by name (gadhs-pi-<package>.json, the catalog override, agent files without the marker, the seeded permission config), not by asking each package; a new package’s tuning file joins the list by following the name.

Modes

Change which model a mode uses

You prefer Sonnet for everyday work in auto mode:

{
  "modes": [
    { "id": "auto", "label": "Auto",
      "model": "vertex-anthropic/claude-sonnet-4-6", "effort": "medium" }
  ]
}

Only the fields you set change; everything else about auto (its rules, judge, guards) comes from the package.

Start every session in plan mode, applied immediately

{
  "applyOnStartup": true,
  "cycle": ["plan", "auto", "manual", "yolo"]
}

The first entry in cycle is the startup mode. With applyOnStartup off (the default) a fresh session keeps whatever model you had; a mode you were in when you closed pi is always restored either way.

Keep your chosen model when switching modes

By default a mode applies its declared model — plan pairs deep reasoning with read-only investigation, and that pairing is part of what the mode is. The switch is announced, never silent — to you as a notice, and to the model as a message in its context (gadhs-mode-change, naming both modes and any model swap), because a model cannot tell a recomposed system prompt from its own assumptions and once insisted it was still in plan mode after a /mode auto. Startup is the exception: the mode a session opens in is applied quietly. If you would rather a model you chose in-session survive mode switches:

{ "stickyModel": true }

With sticky on, a model you picked (with /model, or your configured pi default) rides through mode switches, and the notice tells you what the mode default would have been. A model that a mode itself set still gives way to the next mode’s default — sticky protects choices, not defaults.

Change or remove the mode-cycling shortcut

{ "cycleShortcut": "alt+m" }

Set it to null to have no shortcut. (Shift+Tab is taken by pi itself.)

Add your own mode

A "demo" mode: fast model, no thinking, judge on a short leash:

{
  "cycle": ["auto", "demo", "plan", "manual", "yolo"],
  "modes": [
    {
      "id": "demo", "label": "Demo",
      "model": "vertex-anthropic/claude-haiku-4-5", "effort": "off",
      "systemPrompt": "Demo mode: prefer short answers and visible steps.",
      "workspaceWrites": "allow",
      "judge": { "model": "vertex-anthropic/claude-haiku-4-5", "authority": "deny-only" }
    }
  ]
}

Remember to add the new id to cycle, or /mode next will skip it.

The high-consequence list

Name the actions that should always stop and ask you — before any model gets an opinion. This list is empty by default because every team’s is different: a team that ships on merge has a different list from one that ships on tags.

{
  "modes": [
    { "id": "auto", "label": "Auto",
      "highConsequence": [
        "git push*main*",
        "git push*master*",
        "glab mr merge*",
        "npm publish*",
        "*terraform apply*",
        "*production*"
      ] }
  ]
}

Patterns are simple globs (* matches anything) tested against the whole command and against file paths. A match is never refused outright — it just becomes a question for you.

Permission rules

Block something outright in auto mode

Your team never wants the agent touching Kubernetes:

{
  "modes": [
    { "id": "auto", "label": "Auto",
      "permission": { "bash": { "kubectl *": "deny", "helm *": "deny" } } }
  ]
}

deny is instant and final — no model, no prompt. The agent is told why.

Send something to the judge instead of allowing it

ask means "let the judge look at it" (or you, in manual mode):

{
  "modes": [
    { "id": "auto", "label": "Auto",
      "permission": { "bash": { "docker *": "ask" } } }
  ]
}

Carve an exception out of a shipped rule

Rules are matched most-specific-wins, so a longer pattern can carve an exception out of a shorter one. The shipped rules refuse reads under /.ssh/; this lets the harmless known_hosts file through while keys stay refused:

{
  "modes": [
    { "id": "auto", "label": "Auto",
      "permission": { "read": { "*/.ssh/known_hosts": "allow" } } }
  ]
}
NOTE
Where your pattern and a shipped pattern are the same, the stricter action wins — an overlay cannot loosen policy head-on. An exception works only by being more specific than the rule it carves into (verified: with the recipe above, known_hosts reads allow and id_ed25519 reads still deny). Such a carve-out is a loosening of the baseline, by your choice, and the session says so: at start it lists each overlay pattern that narrows a shipped rule to allow something the shipped rule would refuse (modes overlay carves 1 exception into the baseline: auto: read "/.ssh/known_hosts" allow inside "/.ssh/*" deny). The detection covers that refinement shape only — write exceptions as refinements, not as sibling globs (*known_hosts would carve the same hole and go unreported). If the list ever names something you did not mean, the overlay has drifted.

Two rules for authoring patterns:

  • A pattern containing a pipe can never fire. Bash rules match the decomposed units of a command (echo x | sh is two units), and no unit ever contains a pipe. Match the sink (sh), not the pipeline.

  • Extend allowlists from evidence, not guesswork. node tools/task.mjs verdicts shows what the judge was actually asked; the entries worth allowing are the routine ones that dominate that list.

The judge

Use a different judge model

The shipped judge is Sonnet 4.6 at low; Haiku 4.5 reads within three verdicts of it on the battery’s corpus and is what shipped before #102, so it is the natural alternative. A judge block replaces the mode’s whole judge, so name every field you want kept.

{
  "modes": [
    { "id": "auto", "label": "Auto",
      "judge": { "model": "vertex-anthropic/claude-haiku-4-5", "effort": "low", "authority": "advise" } }
  ]
}

Make the judge stricter (it can refuse, never approve)

{ "modes": [ { "id": "auto", "label": "Auto",
    "judge": { "model": "vertex-anthropic/claude-sonnet-4-6", "effort": "low", "authority": "deny-only" } } ] }

With deny-only, anything the judge would have approved comes to you instead. Good while you are building trust in a new setup.

Give the judge your own rubric

{ "modes": [ { "id": "auto", "label": "Auto",
    "judge": { "model": "vertex-anthropic/claude-sonnet-4-6", "effort": "low",
               "prompt": "/home/me/.pi/agent/my-rubric.md" } } ] }

The prompt can be a file path or inline text. Keep it short and mechanical — rubric attention is finite, and a verbose clause spends it on the wrong cases: we have measured a five-line addition to one bullet flipping the verdict on an unrelated case, and halving the wording removing the regression. After any rubric change, re-run the whole corpus (task eval --repeat 3), not just the cases you were aiming at.

Keep certain actions interactive even in yolo

{ "safetyValve": ["*publish*", "git push --force*", "*deploy*"] }

Valve patterns stay interactive in every mode, including yolo. The shipped list covers force pushes, pushes to main, tags, publishes, merges, and --no-verify.

Tune the denial-loop guard

If the agent gets refused 3 times in a row (or 20 in a session), everything starts coming to you instead — a sign something is off. Adjust or disable:

{ "modes": [ { "id": "auto", "label": "Auto",
    "judge": { "model": "vertex-anthropic/claude-sonnet-4-6", "effort": "low",
               "maxConsecutiveDenials": 5, "maxTotalDenials": 0 } } ] }

(0 disables that limit.)

Models on Vertex

Full reference: Models on Vertex AI. The highlights:

What is there out of the box

Three provider ids from one package, one config file, the same ADC, no login: vertex-anthropic/… (Claude), vertex-gemini/… (Gemini 3.8, 3.7, 3.5 Flash, 3.1 Pro Preview, 2.5 Pro) and vertex-maas/… (gpt-oss 120B, Grok 4.20, Kimi K2 Thinking, Qwen3 Coder, Qwen3-Next Thinking, Qwen3 235B, MiniMax M2). /model lists them all on install. A model’s publisher kind in the catalog decides which id it lives under; you never configure Gemini one way and Claude another.

Point at your own GCP project

export ANTHROPIC_VERTEX_PROJECT_ID=my-team-project
gcloud auth application-default login

Switching models mid-session

Any model, any time — with one rule: the context has to fit. Switching a long session into a model with a smaller window gets a warning with the numbers and an offer to compact where you came from first; /new is the clean slate. Details: modes.adoc#_switching_to_a_model_the_context_does_not_fit.

Add or remove models, change regions

~/.pi/agent/vertex-models.json replaces the catalog. Run node probe.mjs (ships with the package; --publisher google|maas|anthropic for one kind) to discover which models your project can actually reach, and in which regions — it prints a ready-to-use catalog with the publisher kind filled in. An entry for a Gemini or MaaS model is three lines:

{ "id": "gemini-3.8-flash", "publisher": "google", "region": "us",
  "cost": { "input": 0.75, "output": 3.75, "cacheRead": 0.075, "cacheWrite": 0 } }

(That one moves 3.8 Flash from global to the us multi-region, which it also answers from — a US-residency posture in one edit.)

Give thinking levels bigger budgets

{ "thinkingBudgets": { "medium": 16384, "high": 32768 } }

Auth expiry: how long to wait for you to re-login

When your Google session expires mid-task, pi does not fail the task — it tells you to run gcloud auth application-default login and retries on a timer until you have, for as long as the turn is alive; pressing escape is what ends it. Tune the poll, cap the wait, or disable:

{ "adcRetry": { "intervalMs": 30000, "maxWaitMs": 600000 } }

(Defaults: every 60 s, no cap. maxWaitMs is opt-in: set, the turn ends on the original error after that long and the notice says it gave up. intervalMs: 0 disables.)

Headless hosts: how long a host gets to answer

Under pi --mode rpc — an IDE plugin, pi-web-ui, a daemon, the pivot client — there may be no one to answer a dialog, or someone on a phone who needs a minute. Two waits, in the modes overlay (~/.pi/agent/gadhs-pi-modes.json or GADHS_PI_MODES_CONFIG):

{ "unattended": { "gateTimeoutMs": 30000, "dialogTimeoutMs": 600000 } }

gateTimeoutMs (default 30 s) is how long the host gets to confirm a permission ask the gate deferred; silence denies. dialogTimeoutMs (default 10 min) is how long it gets to approve a plan or answer ask; silence refuses. Either at 0 means do not ask at all - the gate denies without the confirm, the approval and ask refuse without the dialog (pi itself would read a zero timeout as none). Neither applies in the terminal, where a human is at the keyboard and dialogs do not time out. See what changes at a headless host.

Compaction: the summarizer of last resort

When the session’s provider refuses the summarization request - a policy classifier blocking it, not a model failing; Anthropic’s has done this to a long session full of quoted model output - retrying there is futile, and pi’s default compaction is the same call. The summary is then written once on a fallback from another provider family:

{ "compaction": { "fallbackModel": "vertex-gemini/gemini-3.8-flash" } }

That is the default. null turns the fallback off; the warning then names the way out by hand (/model to another provider, /compact, /model back). Any provider/model the registry knows is accepted; the session’s own model is never used as its own fallback. A transport error or a length stop is not a refusal and does not reach this. See when the provider refuses the request.

The pivot client (/remote-control)

One file, ~/.pi/agent/gadhs-pi-remote.json:

{ "relay": "wss://pivot.dhs.example/ws", "boxName": "chris-laptop" }

relay (or the GADHS_PIVOT_RELAY environment variable, which wins) is the DHS relay’s WebSocket URL; it must be wss:// except for a localhost relay in tests. boxName is what the phone shows for this machine and defaults to the hostname. Nothing else is tunable: the pairing window is the relay’s two minutes, the reconnect ladder is 1 s doubling to 30 s, and the waits a phone gets at a headless host are the unattended ones above. The identity and the trusted devices live beside it in ~/.pi/agent/gadhs-pi-remote/; edit neither by hand — /remote-control forget is the way to drop a device. GADHS_PI_REMOTE_DEBUG=/path.jsonl writes a diagnostic trail (routing ids and reasons, never a token).

The workflow guards

The guards themselves are not configurable — they run in every mode and cannot be opted out of. A few operational knobs are, in ~/.pi/agent/gadhs-pi-workflow.json. The file is optional; a key the package does not recognise is reported at session start and the file is ignored (defaults apply), so a typo cannot quietly change what a guard does.

Give the reflection reviewer more (or less) time

The cold review is an upper-bounded call. The default bound is ten minutes — a backstop against a dead connection, not a budget: a reviewer thinking hard over a large diff is doing its job, and a model with a real problem returns an error rather than hanging. If the bound ever fires, the commit proceeds with no cold read (the block message says so), which is why the default is generous. Milliseconds, positive integer:

{ "reviewTimeoutMs": 1200000 }

Every review logs its duration and outcome (git_guard.reflection_done in the debug log), so tune from evidence: if reviews of your typical diffs take three minutes, the bound should not be four.

While a review runs you can see it: a notice when it starts ("Cold review: plan draft + 8 files (180 KB) by claude-fable-5-1 — bound 10 min"), the working row and the footer carrying the same while it runs, and a notice with the verdict and the elapsed time when it lands. Pressing escape ends the review at once; nothing is decided, no attempt is spent, and the next commit or exit_plan_mode reviews in full.

Answer a flagged review in the commit message

When the cold review returns FLAGS and you re-run the same commit, the message must carry the disposition of each flagged question (#96):

fix: bound the retry budget

Body as usual.

Review-Response: J3 disputed - the branch at limiter.ts:40 is covered by the existing case
Review-Response: J5 accepted - the doc comment overstates; #77 filed
Review-Context: test/limiter.test.ts

One line per question; disputed or accepted; the reason after a dash or colon, never empty. Write it in the message body (-m, or -F on a file) — not with git’s --trailer, and not in an editor the guard cannot read. fixed is not an answer here: change the diff, and the fresh review says whether it is fixed. The lines are stripped before the review key is hashed and before the reviewer reads the message, so adding them does not cost a second review; they land in git history with the commit.

Size the review context to your repository

Review-Context: (commits) and reviewPaths (plans) let the author hand the reviewer unchanged files. The guard caps that list, and the shipped caps were sized against a few thousand lines of TypeScript. A million-line Rust tree is not that: its files are bigger and it takes more of them to explain a change. All three caps are yours.

{
  "reviewContextMaxFileBytes": 400000,
  "reviewContextMaxTotalBytes": 1500000,
  "reviewContextMaxFiles": 40
}

(Defaults: 80 000 bytes per file, 200 000 total, 12 files. Each is a positive integer; a refusal always quotes your number, not the default.)

What raising them costs. The reviewer’s input context is finite. Past some size the provider refuses the call, or the reviewer’s answer stops before its VERDICT: line. Neither is silent: both become an unreviewed outcome with the reason attached, the attempt is counted, and the commit or plan is told it has no cold read. So a cap set too high buys a visible non-review rather than an invisible bad one — raise it, watch reflection_done, and lower it if reviews start coming back unreviewed.

Size the reviewer’s own reads

Beyond the declared files the reviewer may read the candidate snapshot itself (#97) — read_file, grep, list_files over the index, the worktree under -a, or the disk for a plan. Two caps bound it per review; the per-result cap is reviewContextMaxFileBytes.

{
  "reviewSnapshotMaxCalls": 24,
  "reviewSnapshotMaxBytes": 600000
}

(Defaults: 12 calls, 200 000 bytes. Positive integers.) Past the budget every call answers "budget exhausted … answer from what you have"; a reviewer that keeps asking is stopped two rounds later and the pause is unreviewed with that reason. reflection_done and plan_review.done carry snapshotCalls and snapshotBytes: a repository whose reviews routinely exhaust the calls wants a higher cap; one whose reviewer reads nothing wants none. Each read is a provider round trip on top of the review’s own, so the calls cap is also a latency cap.

Guidance

Add project-specific guidance for everyone in a repo

Create <repo>/.pi/gadhs-guidance.md:

## This repo
- The API layer is generated; edit the OpenAPI spec, never src/api/.
- Integration tests need the docker compose stack up.

It is injected into the system prompt for anyone working in that repo with the package installed (trusted repos only).

Replace the agency-wide guidance digest

{ "guidance": { "global": "Our department's rules: ..." } }

This replaces the packaged digest wholesale — most teams should add a project block instead and leave the global one alone.

Scaffold a new repo

In a repo with no AGENTS.md yet:

/gadhs-init

creates the standard skeleton (tech stack, build commands, architecture notes, project overrides). It refuses to overwrite an existing file.

Appearance

Use the agency theme

/settings → Theme → gadhs-human-services-dark (or -light, or the gadhs-foundation-* pair). To follow your terminal’s light/dark automatically, put this in ~/.pi/agent/settings.json:

{ "theme": "gadhs-human-services-light/gadhs-human-services-dark" }
WARNING
A top-level themes array in settings.json is inert: the key validates but pi’s resource loader never reads it, so it silently does nothing. Themes load only from packages (pi.themes in package.json), the --theme CLI flag, and the scanned directories (~/.pi/agent/themes, .pi/themes).

Subagents

Restrict which helpers a mode may launch

{ "modes": [ { "id": "auto", "label": "Auto",
    "canSpawn": ["Explore", "Verify"] } ] }

An empty (or missing) list means no delegation at all in that mode.

Run a helper on a different model

The seeded helpers ship with Explore and Verify on Gemini 3.8 Flash (both argued on the model-battery page) and Research on Sonnet. To run one elsewhere without owning its file, name the model in ~/.pi/agent/gadhs-pi-agents.json:

{ "models": { "Explore": "vertex-anthropic/claude-haiku-4-5",
              "Research": "vertex-gemini/gemini-3.8-flash" } }

The seed is rendered with your model in place of the packaged one; the file keeps its gadhs_managed marker, so the next package update still lands its prompt and only the model: line is yours. Remove the entry and the packaged model comes back on the next start. Keys must name packaged helpers and values must be provider/model; a malformed file, or a key naming a helper the package does not ship, is reported at start and the whole file ignored — never obeyed in part.

Why you might: the read-heavy helpers want a large window and adequate reasoning, not adversarial rigour, and Gemini 3.8 Flash offers a 1M-token window at Flash prices. It measured Sonnet-class on the agency’s review corpus and is not used for the reviewer or the auto-mode judge — see Reviewer evaluation: does a second vendor add value? for the numbers and the reasons.

There is nothing to configure for the model itself: vertex-gemini is the agency’s own Vertex provider, on the same ADC and project as Claude, and its models are in /model from the first start (Models on Vertex AI (@gadhs/pi-vertex)).

One thing to know about the fallback: pi-subagents resolves a helper’s model against the models available in the session and, when it cannot, runs the helper on the session’s own model without saying so. The seeding extension checks every configured model at session start and warns by name — "Explore is configured for vertex-gemini/gemini-3.8-flash, which is not available in this session" — so a missing project or expired login is a visible line, not a quiet bill on the frontier model.

Make a helper’s results machine-checkable

In the helper’s definition file (<repo>/.pi/agents/Verify.md), declare what its final answer must look like:

output_schema:
  {"type": "object", "required": ["passed", "evidence"],
   "properties": {"passed": {"type": "boolean"}, "evidence": {"type": "string"}}}

If the helper’s answer does not match, you are told the result is unverified — instead of silently trusting a confident-sounding summary.

Overriding an agency helper in your repo (a .pi/agents/Verify.md of your own) replaces its prompt and its model, but not its contract unless you declare one: leave output_schema out and the agency’s schema still applies, and any violation message tells you that and which file to change.

Memory

The distribution remembers small, local facts — scoped to this repo, this machine, and you — and injects them leanly (hard budget, visible contents, loud failure). Work state belongs in issues and repo truths in AGENTS.md; memory is for what has no better home.

/remember the integration suite needs the docker stack up   # repo-scoped
/remember box: docker compose needs sudo here               # this machine
/remember dev: I prefer tables over prose                   # you, everywhere
/memory                                                     # list + budget
/memory promote [<id>]   # confirm an agent proposal
/memory forget [<id>]    # remove (archived, never vanished)

Nobody copies a hash by hand: typing /memory promote ` completes the pending proposals in place (id, text, scope, age, hits — the same completion `/model gives you), and a bare /memory promote or /memory forget opens a list to scroll and pick from. Dismissing the list changes nothing. Scopes are literal: a dev: note is keyed to your git identity and follows you into every repo; repo is keyed to the origin URL; box to the hostname — so a note that is really about one repository belongs at repo scope, whichever session proposed it.

Agents can propose memories with their remember tool; proposals are labelled unconfirmed, capped at 10, expire after 7 days, and never become permanent without your /memory promote. Everything evicted or expired goes to ~/.pi/agent/gadhs-memory-archive.jsonl, not oblivion.

The store is one file, ~/.pi/agent/gadhs-memory.json, shared by every pi session on the box. Each command and each prompt reads it fresh and each write replaces it whole by rename (#158), so two sessions open at once see each other’s memories on their next turn, and a write in one no longer drops what the other stored since it started - the only way to lose one is two sessions writing in the same instant, a window of one command rather than a session, and there is no lock closing it. A crash mid-write leaves the previous store, never a torn one. A file that is unreadable disables memory for the session, loudly, and is not written over.

Seeing what happened

node tools/task.mjs verdicts 20 --why   # recent decisions, with the ask and the reason
node tools/task.mjs policy-diff         # has your permission seed drifted from the default?
node tools/task.mjs gitlab-check ID     # which GitLab identity is actually in effect
GADHS_PI_MODES_DEBUG=/tmp/d.jsonl pi    # low-level diagnostics for a session

Troubleshooting quick hits

Symptom Likely cause and fix

"The user denied this call" but you didn’t

A policy or the judge decided. The sentence is the permission system’s and opens the same way for every authorizer; the Reason: that follows is ours and names the decider: [decided by gadhs-mode-judge (a model), not the human] … or [decided by gadhs mode policy, not the human] …. The inline trace above it says the same, and verdicts --why shows the reason.

Model reverts after restart

Fixed in current versions — resumed sessions continue on the model they left on. Update the package.

Everything suddenly needs your approval

The denial-loop guard tripped (3 refusals in a row). The status line shows DENIAL LOOP. Usually means the agent is stuck on something a rule forbids — scroll up to the trace.

glab blocked: "GITLAB_TOKEN is not set"

Export GITLAB_TOKEN in your shell before starting pi. Without it, glab silently uses whatever identity is in ~/.config/glab-cli — on a shared machine, possibly not yours.

Google auth expired mid-task

Run gcloud auth application-default login in another terminal; the task resumes by itself within a minute.

Commit blocked with a review of your diff

That is the reflection pause: an independent model read your staged diff cold and answered the J1–J8 checklist, citing file and line. Address what you agree with (or say why you disagree), then run the same commit again — the identical diff passes on retry, and staging any fix earns a fresh review. Every commit gets exactly one review attempt; it advises, it does not veto.

Commit blocked saying the reviewer "could not be reached"

The reviewer call failed (provider error, or the time bound). That is not a review, so re-running the same commit tries the reviewer again. The message says which attempt it was: after two consecutive failures on the same diff, the next run proceeds on your own J1–J8 pass. A fresh staged change starts the count over.

Commit or exit_plan_mode refused: "Review context path … is outside the workspace root / not a regular file / exceeds …"

The author declared a file for the reviewer (a Review-Context: trailer or reviewPaths) that the guard cannot admit. Paths are relative to the workspace root; only regular files under it; and within the caps, which the message quotes because they are yours to set (defaults 80 KB per file, 200 KB total, 12 files — see “Size the review context to your repository”). Fix the list, or the caps, and run the same command again — nothing was spent, the review had not started.

exit_plan_mode came back with a review of the plan instead of a dialog

That is the plan draft’s cold-review pause (P1–P4), the same one commits get. The agent should address material findings by editing the draft and calling exit_plan_mode again; an edited draft is reviewed afresh, an unchanged one reaches your dialog. You see the findings in the transcript either way.

Commit refused because it stages and commits at once

Run the staging and the commit as two separate commands. The review runs before your command does, so combined staging would let the reviewer see the wrong diff.

A new file gained a license header you didn’t type

Working as intended — new source files get the SPDX header automatically.

Edit this page · latest