CODING PLANNER

Documentation · AR Labs

System reference

Configuration

Every setting the coding planner reads, where it lives, who writes it, its default and which program reads it: manifest keys, bead metadata, environment variables and labels.

This section lists every setting the coding planner reads and where each one lives. Without it, the only way to answer "where is X configured?" is to read the scripts, and a value written where no reader looks is silently ignored: the run carries on with the default and nothing reports the mistake. The settings live in seven homes, each owned by a different file and changed by a different hand, so the list is one table split by home, with a short account of each home before its rows.

Every row has the same six columns. Setting is the key, variable or label. Home names the file that owns the setting. Scope says how much of the system one value governs. Written by is the verb or person that sets it. Default is what happens when it is unset; a dash means there is no default. Read by names the programs that act on it. Script names without a directory are in .claude/scripts/, hook names are in .claude/hooks/, and command files are in .claude/commands/coding-planner/.

The manifest

The manifest, .claude/pipelines/coding-pipeline.json, is the pipeline's policy: which steps exist, in what order, what each step dispatches and what must be proved before a node may leave it. One value governs every campaign run on this pipeline, because no script carries a step name of its own. A person changes it by editing and committing the file. An unattended session cannot, because guard-enforcement-surface.ts denies writes under .claude/pipelines/ in a dispatched session. Keys under steps.definitions are set per step, written below as <step>.<key>.

Setting Home Scope Written by Default Read by
pipeline (coding-planner) coding-pipeline.json The manifest's name; pipeline.name on a root records it A person, by commit — : --pipeline defaults to coding-planner, and a name no manifest declares escalates pipeline-transition.sh, pipeline-driver.sh (find the manifest file by this name)
steps.routes (root, compound, leaf) coding-pipeline.json Every node; a step's successor is its neighbour in its route A person, by commit — pipeline-transition.sh, pipeline-driver.sh, bd-pipeline-guard.ts (valid step names)
<step>.command coding-pipeline.json One step, on every node that reaches it A person, by commit null: nothing is dispatched, as on delegate pipeline-driver.sh, which hands the path to pipeline-executor.sh
<step>.gate coding-pipeline.json One step A person, by commit null: the step's floor settles it pipeline-driver.sh
<step>.verify (the floors) coding-pipeline.json One step A person, by commit []: no evidence check, so the driver never completes the step by itself pipeline-transition.sh (complete, integrate and deliver run them), pipeline-driver.sh
<step>.relaxable coding-pipeline.json One step A person, by commit false: an autonomy level naming the step escalates pipeline-driver.sh, pipeline-transition.sh
<step>.relax_requires coding-pipeline.json One step (integrate: integration-branch) A person, by commit Absent, null or "": no extra condition. The exact string integration-branch is the only value the scripts know; any other value, read by JSON type and exact text (so false, numbers and strings that differ only by whitespace count), never relaxes the step and never opens it on silence: the driver escalates every node under a level that names it and every node at the step itself, and complete refuses a dispatched session or an --on-silence caller pipeline-driver.sh, pipeline-transition.sh
<step>.resume coding-pipeline.json One step A person, by commit — : a dispatchable step without one escalates pipeline-driver.sh, which passes it to pipeline-executor.sh
<step>.waivable.label coding-pipeline.json generate-design (design:waived), create-prp (prp:waived) A person, by commit Absent: waive refuses the step pipeline-transition.sh (waive)
<step>.on_complete coding-pipeline.json One step A person, by commit [], which every step declares pipeline-transition.sh (complete)
review.fix_command coding-pipeline.json The review step A person, by commit — : a fix-owed refusal on a step without one escalates pipeline-driver.sh
review.fix_resume coding-pipeline.json The review step's fix dispatch A person, by commit — pipeline-driver.sh
review.fix_rounds coding-pipeline.json The review step; the cap on unattended fix rounds (1) A person, by commit — : a fix_command without a numeric cap escalates pipeline-driver.sh
autonomy.levels coding-pipeline.json Every node; names the human gates each level relaxes A person, by commit — : a level must name a row here pipeline-transition.sh (set-mode, init-task validate the name), pipeline-driver.sh
autonomy.licences coding-pipeline.json Every node; dispatch-fix for wave and deep A person, by commit With no table, no level holds a licence; a level missing from the table escalates pipeline-driver.sh
discovery.max_entries_per_tree coding-pipeline.json Every tree (a pipeline.discovery_root); how many beads discover may enter for it (3) A person, by commit — : discover escalates pipeline-transition.sh (discover)
autonomy.silence coding-pipeline.json Every node; seconds a held gate's proposal may go unanswered before the driver advances it (hitl 14400, wave and deep 7200, hold null) A person, by commit With no table, nothing advances on silence; a level missing from the table, or a value other than a non-negative number or null, escalates pipeline-driver.sh, pipeline-transition.sh (complete)
entry.entry_stage coding-pipeline.json Every campaign entering through init (create-prp) A person, by commit The first step on the root route pipeline-transition.sh (init)
entry.requires_artifact, entry.verify coding-pipeline.json Every campaign entering through init A person, by commit false: init escalates; [] pipeline-transition.sh (init)
state_keys coding-pipeline.json The schema of every pipeline.* key A person, by commit — No script; it is the authoritative list pipeline-driver.sh points to
<step>.artifact.glob, <step>.enforced, <step>.display, waivable.requires_ruling, display_name, version, state_source, entry.pre_pipeline_command coding-pipeline.json Declarative A person, by commit — No script in this repository; waive requires --ruling whatever requires_ruling says

Bead metadata

Bead metadata is the key-value store each issue in the tracker carries; an issue is a bead. The pipeline keeps all its state there under the reserved pipeline. prefix, and pipeline-transition.sh is its only writer: bd-pipeline-guard.ts denies a direct bd update --set-metadata pipeline.* unless a person prefixes the command with VOX_PIPELINE_OVERRIDE=1. Most of these keys record where a node is, but some are per-campaign facts that change behaviour, such as the integration branch, the delivery mode, the dial and the integrate floor's suite command. The authoritative list is the manifest's state_keys block, which names each key's writing verb; the header of pipeline-transition.sh gives every verb's contract. A key scoped to the campaign root is read only there, by an ancestor walk, so a copy written on any other bead is never read. The landing floor also stamps the bead's own external_ref field with the pull request it proved; that is a tracker field, not metadata.

Setting Home Scope Written by Default Read by
pipeline.name Bead metadata (state_keys) Campaign or task root; carrying it is rootness init, init-task, adopt --as-root Absent: not a root pipeline-transition.sh, pipeline-driver.sh, pipeline-executor.sh
pipeline.stage Bead metadata (state_keys) Every node; the step it is at init, init-task, complete, waive, set-step Unset: the pipeline does not manage the bead pipeline-transition.sh, pipeline-driver.sh, bd-pipeline-guard.ts
pipeline.entry_artifact Bead metadata (state_keys) Root init (the brief), init-task --prp, adopt --as-root --prp Absent pipeline-transition.sh, pipeline-executor.sh (the run's authority document)
pipeline.init_operation Bead metadata (state_keys) Root init, init-task Absent pipeline-transition.sh (retry idempotency)
pipeline.entry_route Bead metadata (state_keys) Task root (task) init-task Absent: grill campaign behaviour pipeline-transition.sh, pipeline-driver.sh
pipeline.adopted Bead metadata (state_keys) A tree root and its descendants adopt (a person) Absent: the managed-tree checks apply pipeline-transition.sh
pipeline.artifact Bead metadata (state_keys) Node; the pending proposal propose; cleared by complete and waive Absent: no work done, no gate pending pipeline-transition.sh, pipeline-driver.sh
pipeline.proposed Bead metadata (state_keys) Node; step=<s> date=<iso>, when the pending proposal was recorded propose --artifact Absent: the proposal predates the key and never advances on silence pipeline-transition.sh (complete), pipeline-driver.sh (the silence window)
pipeline.scenarios Bead metadata (state_keys) Node; root holds the whole set set-scenarios Absent pipeline-transition.sh (coverage, floors), pipeline-driver.sh
pipeline.fanout_verified Bead metadata (state_keys) Container; presence makes the node a container birth-facts Absent: not a container pipeline-transition.sh (kind), pipeline-driver.sh
pipeline.fanout_children Bead metadata (state_keys) Container birth-facts Absent: children_terminal skips the unchanged-set clause pipeline-transition.sh, pipeline-driver.sh
pipeline.integrated Bead metadata (state_keys) Container integrate Absent pipeline-transition.sh, pipeline-driver.sh
pipeline.reviewed Bead metadata (state_keys) Leaf complete --step review (the review_verdicts floor) Absent pipeline-transition.sh (deliver reads the reviewed commit)
pipeline.suite_cmd Bead metadata (state_keys) Campaign root set-config Unset: integrate escalates; init warns pipeline-transition.sh (integrated_acceptance)
pipeline.test_paths Bead metadata (state_keys) Campaign root set-config Unset: integrate escalates; init warns pipeline-transition.sh (integrated_acceptance)
pipeline.integration_branch Bead metadata (state_keys) Campaign root; presence is deep mode set-mode --integration-branch Unset: the target is main (wave mode) pipeline-transition.sh (target), so the executor's worktree cut, Gate B's base and Gate C
pipeline.delivery Bead metadata (state_keys) Campaign root set-mode --delivery, init-task Unset: pr pipeline-transition.sh (delivery), pipeline-executor.sh
pipeline.autonomy Bead metadata (state_keys) Any managed node, nearest ancestor wins set-mode --autonomy, init-task Unset: every human gate holds pipeline-transition.sh (autonomy, tree-facts), pipeline-driver.sh, pipeline-executor.sh
pipeline.discovered_from Bead metadata (state_keys) A bead discover entered; the finder discover Absent: not entered by discover Nothing yet; the record a run's discovered work is read from
pipeline.discovery_root Bead metadata (state_keys) A bead discover entered; the tree its entry counts against discover Absent pipeline-transition.sh (discover counts it against the cap; queue lists a run's discovered beads by it)
pipeline.queue_order Bead metadata (state_keys) An epic; the order a run takes its descendants in set-queue Absent: the queue has no recorded order pipeline-transition.sh (queue)
pipeline.lease Bead metadata (state_keys) Node; the claim record holder=<token> since=<iso>, which never expires claim, release (the holder), release --clear --reason (a person) Absent: unclaimed pipeline-transition.sh, pipeline-driver.sh
pipeline.exit_status Bead metadata (state_keys) Node record-exit Absent pipeline-driver.sh (including owed= and axes=)
pipeline.attempts Bead metadata (state_keys) Node, per step record-exit Absent: no failed attempts pipeline-transition.sh, pipeline-driver.sh
pipeline.dead_letter Bead metadata (state_keys) Node record-exit, at PIPELINE_MAX_ATTEMPTS Absent pipeline-driver.sh, which parks the node until a person clears it
pipeline.fix_rounds Bead metadata (state_keys) Node, per step record-exit --fix-round Absent: no rounds spent pipeline-driver.sh
pipeline.driver_last Bead metadata (state_keys) The scope root of a driver pass record-run Absent pipeline-driver.sh
pipeline.delivered Bead metadata (state_keys) Leaf deliver Absent pipeline-driver.sh
grill_brief Bead metadata (pipeline-transition.sh) Campaign handoff Absent pipeline-transition.sh (init matches the brief)
grill.session_id Bead metadata (pipeline-transition.sh) Campaign handoff Absent pipeline-transition.sh (init matches the producing session)
grill.autonomy Bead metadata (pipeline-transition.sh) Campaign; the staged dial handoff; cleared by set-mode --from-staged Absent pipeline-transition.sh; entry-context refuses while it sits unapplied
grill.delivery Bead metadata (pipeline-transition.sh) Campaign; the staged delivery mode handoff; cleared by set-mode --from-staged Absent pipeline-transition.sh; entry-context refuses while it sits unapplied
grill.init_operation Bead metadata (pipeline-transition.sh) Campaign, only while init is in flight init, which clears it on success Absent pipeline-transition.sh (init resumes an interrupted entry)
grill.init_artifact Bead metadata (pipeline-transition.sh) Campaign, only while init is in flight init, which clears it on success Absent pipeline-transition.sh (init resumes an interrupted entry)

The project's own repository

A codebase run through the pipeline carries a few committed files that describe it. The main one is the project overlay, .vox/project.json, which declares the codebase's identity; the two others prepare a fresh worktree. One value governs every bead whose project:<id> label names the codebase. Where the codebase sits on a given machine is not here; that is the machine configuration below. The lab's machine-configuration notes describe the split.

Setting Home Scope Written by Default Read by
schema_version .vox/project.json One codebase A person, by commit — : must be 1 or the resolver refuses project-resolver.ts
project_id .vox/project.json One codebase A person, by commit — : the resolver refuses a folder whose overlay is missing or names another id project-resolver.ts, pipeline-executor.sh (a path segment of the worktree), guard-worktree-edits.ts (the overlay's presence marks a primary checkout as guarded; the id names the project in a denial)
modules .vox/project.json One codebase A person, by commit {} Not the coding planner: vox/modules/beads/scripts/project-store.ts reads modules.beads.store
.worktreeinclude The codebase's root, committed Every new worktree of the codebase A person, by commit Absent: nothing is copied pipeline-executor.sh (copies the listed gitignored files from the primary checkout)
.vox/worktree-setup.sh The codebase, committed Every new worktree of the codebase A person, by commit Absent: no setup runs pipeline-executor.sh (runs it once per bead's worktree)

The worktree registry

The worktree registry, .claude/worktrees.json in the VOX repository, records each project's shared dev worktree: one long-lived worktree, with secrets and dependencies in place, that a dispatched bead takes when it is free. A project missing from it gets a fresh worktree per bead, and nothing else changes: guard-worktree-edits.ts, the hook that refuses edits in a project's primary checkout, protects the primary of every repository carrying a project overlay except VOX's, listed here or not. Registration only changes where its denial points: to the shared dev worktree rather than to the bead worktrees.

Setting Home Scope Written by Default Read by
worktreesRoot .claude/worktrees.json Every registered project A person, by commit — pipeline-executor.sh, guard-worktree-edits.ts
projects[] (label, primary, worktree) .claude/worktrees.json One project A person, by commit Absent: no shared worktree; the edit guard still protects the primary through its overlay pipeline-executor.sh, guard-worktree-edits.ts, bd-pipeline-guard.ts

The machine configuration

The machine configuration, ~/.vox/config.json, records where things are on one machine. It is never committed, so each machine keeps its own. Its normative definition is readUserConfig in project-resolver.ts, and the lab's machine-configuration notes explain each section. The Codex CLI's own per-machine file is listed here too, because when no model is passed the review and spec harnesses run on the default it names.

Setting Home Scope Written by Default Read by
schema_version ~/.vox/config.json One machine A person — : must be 1 project-resolver.ts
beads_stores.<name> (repo_root, beads_dir, database, project_id) ~/.vox/config.json One machine A person, copied from bd context --json — : the resolver needs exactly one store and refuses on any mismatch project-resolver.ts, vox/modules/beads/scripts/project-store.ts
project_roots.projects ~/.vox/config.json One machine A person <home>/CODE/projects project-resolver.ts
project_roots.worktrees ~/.vox/config.json One machine A person <home>/CODE/vox-worktrees pipeline-executor.sh (each bead's worktree is <worktrees>/<project-id>/<bead-id>); project-resolver.ts validates it; guard-worktree-edits.ts (names that location in a denial)
projects.<id>.root ~/.vox/config.json One codebase on one machine A person Absent: the codebase is at <project_roots.projects>/<id> project-resolver.ts
model ~/.codex/config.toml (Codex CLI) One machine A person Codex's built-in default The Codex CLI when review/vox-review.sh or spec/vox-spec.sh passes no model; both scripts read it back to label the artifact

Environment variables

An environment variable is a value the shell hands to every program it starts. Most of these variables are documented nowhere but in the scripts that read them, so the Home column names the script that applies the default. Some are set for every Claude Code session by the env block of .claude/settings.json, which pipeline-executor.sh loads explicitly into each dispatched session (--settings $VOX_ROOT/.claude/settings.json); some the executor sets itself for the session it spawns; the rest come from the shell of whoever starts a run.

Setting Home Scope Written by Default Read by
VOX_ROOT Environment; defaults in each reader Every script and hook .claude/settings.json env an absolute path to the lab's own checkout, hard-coded in the transition script, driver, executor, bd-pipeline-guard.ts and guard-enforcement-surface.ts; $HOME/CODE/VOX in review/vox-review.sh, spec/vox-spec.sh and guard-worktree-edits.ts pipeline-transition.sh, pipeline-driver.sh, pipeline-executor.sh, review/vox-review.sh, spec/vox-spec.sh, bd-pipeline-guard.ts, guard-enforcement-surface.ts, guard-worktree-edits.ts
VOX_DIR .claude/settings.json env Every session .claude/settings.json env — : if unset, the guard hooks' registrations (${VOX_DIR}/hooks/...) point nowhere and no guard runs The shell that runs each registered hook command
BEADS_DIR .claude/settings.json env Every bd call in a session .claude/settings.json env bd's own store discovery bd; project-resolver.ts strips it so a bead's labels come only from the configured store
VOX_REVIEW_MODEL Environment; defaulted in review/vox-review.sh Every Gate B review run under it, both rounds Today: "gpt-6-astra" in .claude/settings.json env, a stopgap (below) Unset: round 2 takes round 1's recorded model; round 1 takes the Codex default review/vox-review.sh, which outranks the round-2 pin with it
VOX_REVIEW_MAX_KB Environment; defaulted in review/vox-review.sh One review run The caller's shell 256 review/vox-review.sh
VOX_REVIEW_INLINE_KB Environment; defaulted in review/vox-review.sh One review run The caller's shell 12: a context document larger than this is named by path, not pasted review/vox-review.sh
VOX_REVIEW_SILENCE_MIN Environment; defaulted in review/vox-review.sh One review run The caller's shell 10: minutes without a new byte in the review's .partial or session log, after which the harness stops Codex, keeps the partial and ends no_review with reason=silence_<n>min (exit 3); fractions accepted review/vox-review.sh
VOX_REVIEW_MAX_MIN Environment; defaulted in review/vox-review.sh One review run The caller's shell 45: minutes after which any review still running is stopped the same way, reason=ceiling_<n>min; fractions accepted review/vox-review.sh
VOX_SPEC_MODEL Environment; defaulted in spec/vox-spec.sh One Codex spec run The caller's shell Unset: the Codex default spec/vox-spec.sh
VOX_SPEC_MAX_KB Environment; defaulted in spec/vox-spec.sh One Codex spec run The caller's shell 256 spec/vox-spec.sh
VOX_SPEC_CONTAINER_CAP Environment; defaulted in spec/vox-spec.sh One Codex spec run The caller's shell 60000 characters of the container spec spec/vox-spec.sh
VOX_SPEC_PRP_CAP Environment; defaulted in spec/vox-spec.sh One Codex spec run The caller's shell 60000 characters of the PRP spec/vox-spec.sh
CODEX_HOME Environment; defaulted in review/vox-review.sh, spec/vox-spec.sh One machine The caller's shell $HOME/.codex review/vox-review.sh, spec/vox-spec.sh (where to read the Codex default model)
PIPELINE_RUN_MAX_PASSES Environment; defaulted in pipeline-run.sh One headless run The caller's shell; --max-passes overrides 16 pipeline-run.sh
PIPELINE_RUN_MAX_BEADS Environment; defaulted in pipeline-run.sh One headless run with --queue The caller's shell; --max-beads overrides 16 pipeline-run.sh
PIPELINE_RUN_DRIVER, PIPELINE_RUN_TRANSITION Environment; read in pipeline-run.sh One headless run A test's stubs The driver and transition script beside pipeline-run.sh pipeline-run.sh
PIPELINE_DRIVER_DISPATCH Environment; set in pipeline-run.sh One driver invocation pipeline-run.sh (the executor beside it), unless already set Unset: dispatch actions are reported, not performed pipeline-driver.sh (set means an unattended host: a bead whose spec's file_scope lands on the enforcement surface rests attended-host instead of being dispatched)
PIPELINE_DRIVER_MAX_ACTIONS Environment; defaulted in pipeline-driver.sh One driver pass The caller's shell; --max-actions overrides 0: no cap pipeline-driver.sh
PIPELINE_DRIVER_MAX_CYCLES Environment; defaulted in pipeline-driver.sh One driver pass The caller's shell; --max-cycles overrides 8 pipeline-driver.sh
PIPELINE_ATTEMPT_RESULT Environment; set in pipeline-driver.sh One dispatch pipeline-driver.sh, a fresh file per dispatch <transcript>.result beside the executor's log pipeline-executor.sh, the dispatched session, review/vox-review-blocked.sh, spec/vox-spec-blocked.sh
PIPELINE_EXECUTOR_MODEL Environment; defaulted in pipeline-executor.sh Every dispatched session The caller's shell opus pipeline-executor.sh (--model)
PIPELINE_EXECUTOR_CLAUDE Environment; defaulted in pipeline-executor.sh Every dispatched session The caller's shell, or a test claude pipeline-executor.sh
PIPELINE_EXECUTOR_LOG_DIR Environment; defaulted in pipeline-executor.sh Every dispatched session The caller's shell /tmp pipeline-executor.sh
PIPELINE_EXECUTOR_RESOLVER Environment; defaulted in pipeline-executor.sh Every dispatch The caller's shell, or a test project-resolver.ts beside the executor pipeline-executor.sh
PIPELINE_MAX_ATTEMPTS Environment; defaulted in pipeline-transition.sh Every node The caller's shell 3 failed attempts, then dead-letter pipeline-transition.sh (record-exit)
PIPELINE_TRANSITION_LOCKS Environment; defaulted in pipeline-transition.sh One machine The caller's shell, or a test ${TMPDIR:-/tmp}/vox-pipeline-transition-locks pipeline-transition.sh (the claim mutex)
VOX_USER_CONFIG Environment; defaulted in project-resolver.ts One machine The caller's shell, or a test ~/.vox/config.json project-resolver.ts, pipeline-executor.sh, verify-machine.sh, guard-worktree-edits.ts
VOX_BD_BIN Environment; defaulted in project-resolver.ts One machine The caller's shell, or a test bd project-resolver.ts, verify-machine.sh
VOX_PROJECT_ROOT Environment; set in pipeline-executor.sh One dispatched session pipeline-executor.sh (the bead's worktree) — The dispatched session (afk-contract.md), .vox/worktree-setup.sh, guard-enforcement-surface.ts (expands it when judging a path)
VOX_PRIMARY_ROOT Environment; set in pipeline-executor.sh One worktree setup pipeline-executor.sh — .vox/worktree-setup.sh
VOX_BEAD Environment; set in pipeline-executor.sh One worktree setup pipeline-executor.sh — .vox/worktree-setup.sh
VOX_AFK Environment; set in pipeline-executor.sh One dispatched session pipeline-executor.sh (1) Unset: treated as attended guard-enforcement-surface.ts (denies, rather than audits, surface writes); pipeline-driver.sh (1 means an unattended host, as for PIPELINE_DRIVER_DISPATCH); pipeline-transition.sh (complete and integrate refuse a human gate the dial holds; release --clear refuses)
VOX_ENFORCEMENT_OVERRIDE Environment; read in guard-enforcement-surface.ts One session A person launching a maintenance session; pipeline-executor.sh blanks it Unset: the surface guard runs guard-enforcement-surface.ts
VOX_SURFACE_AUDIT_LOG Environment; defaulted in guard-enforcement-surface.ts One session The caller's shell, or a test $VOX_ROOT/.claude/logs/enforcement-surface-audit.log guard-enforcement-surface.ts
VOX_PIPELINE_OVERRIDE A command prefix; matched in bd-pipeline-guard.ts One command A person correcting bead state Absent: the guard denies direct writes to pipeline.* bd-pipeline-guard.ts, which matches the text VOX_PIPELINE_OVERRIDE=1 in the command rather than reading the environment

Other VOX_ names in .claude/scripts/ and .claude/hooks/ are not coding-planner settings and are left out: VOX_HOME belongs to setup.sh; VOX_BRIEFING_MODEL, VOX_SOURCE_APP and VOX_VOICE_SERVER_PORT belong to session hooks; VOX_BLOCK_STUB_* and VOX_SPEC_STUB_MODE are test stubs; and VOX_REVIEW_RESULT, VOX_SPEC_RESULT, VOX_REVIEW_BLOCKED and VOX_SPEC_BLOCKED are the prefixes of the harnesses' result lines, not variables.

The review model is a stopgap. The lab decided in October 2026 that Gate B reviews use the model gpt-6-astra: gpt-5.6-sol hung repeatedly, six times on one bead, and gpt-5.5 is refused for a Codex login through a ChatGPT account. To make dispatched sessions inherit the ruling, VOX_REVIEW_MODEL=gpt-6-astra was added to the env block of the primary checkout's .claude/settings.json, the copy the executor loads. It is a local edit there, not a committed setting, so another checkout or another machine reviews on its Codex default. Three things follow from where it sits. review.md names no model on purpose and calls VOX_REVIEW_MODEL an override "for a one-off comparison, not as a standing pin"; this entry is a standing pin, in a file nobody reading review.md would open. Because vox-review.sh ranks the variable above the model recorded in round 1's review, the entry also overrides the round-2 pin: a bead whose round 1 ran on another model is judged in round 2 by gpt-6-astra, a different judge that re-argues the whole change instead of adjudicating the fix, which is the failure the pin exists to prevent. And VOX_SPEC_MODEL is unset, so a spec:codex bead still drafts its spec on the Codex default; the ruling covers Gate B only.

Where this should live. The proposed home is the review step's definition in the manifest, as a key such as steps.definitions.review.model beside fix_rounds. The manifest is already the home of review policy, it is committed and travels to every machine, and an unattended session cannot change it. vox-review.sh reads nothing from the manifest, so the key needs wiring: the script, or the review command passing --model, would read it. A precedence that keeps the round-2 pin intact is --model, then VOX_REVIEW_MODEL, then round 1's recorded model for round 2, then the manifest's model, then the Codex default; the settings entry would then be removed, leaving the variable for one-off comparisons as review.md intends. The move runs against review.md's reason for naming no model: a pinned name once left a review path calling a model the account could not run. A manifest key is still a pinned name, so when the model is retired the review fails until someone edits that key, and review.md's paragraph would need rewriting to say where the name lives and why. Moving the setting and revising review.md are the owner's decision; this section records the proposal and changes neither.

Labels and agent definitions

A label is a tag on a bead, set with bd update --add-label. A few labels change what the pipeline does with the bead that carries them. The deterministic guard does not police labels, so apart from the two waiver labels the transition script writes and the execution: label the fan-out sets, nothing mechanical stops any session from setting one; that a person sets them is a convention. The agent definitions in .claude/agents/ pin the model and effort of the agents that author a step's artifacts. The fleet standard in afk-contract.md §9 requires spec, implement and review-orchestration agents to run the strongest implementation model at effort high and never inherit the session's model; these pins are where that holds when a step dispatches a named agent. The Gate B reviewer is not a local agent, and its model is the review model above.

Setting Home Scope Written by Default Read by
spec:codex / spec:claude Bead label (pipeline-transition.sh spec-author) Node, nearest ancestor wins A person Neither: Claude authors the spec; both on one node refuses pipeline-transition.sh (spec-author), generate-spec.md, afk-contract.md
spec:skip Bead label (implement.md) Node A person, before implement Absent: implement requires a spec implement.md (proceeds without a spec only on a person's in-session confirmation), afk-contract.md (an unattended run blocks instead)
review:skip Bead label (pipeline-transition.sh review_verdicts) Leaf A person Absent: Gate B runs pipeline-transition.sh (waives the floor and still records the reviewed commit), review/vox-review.sh (Evidence axis), implement.md, review.md, deliver.md
prp:waived Bead label (coding-pipeline.json create-prp.waivable) Root waive --ruling, init-task --waive-prp Absent: a PRP is required pipeline-transition.sh
design:waived Bead label (coding-pipeline.json generate-design.waivable) Root waive --ruling Absent pipeline-transition.sh
execution:afk / execution:hitl Bead label (.claude/skills/to-issues/SKILL.md) Each fan-out child The to-issues fan-out — : birth-facts refuses a child without exactly one pipeline-transition.sh (birth-facts), implement.md (lists ready execution:afk slices); the driver ignores it, since the autonomy dial decides unattended advance
project:<id> Bead label (project-resolver.ts) Node; not inherited from a parent A person — : the resolver refuses a bead with none or several project-resolver.ts, so pipeline-executor.sh placement
model: claude-opus-5-5, effort: high .claude/agents/architect.md Every dispatch of the architect agent A person, by commit Absent: the agent inherits the session's model The Claude Code harness, when generate-spec.md, create-prp.md or generate-design.md dispatches the architect
model: opus, effort: high .claude/agents/engineer.md Every dispatch of the engineer agent A person, by commit Absent: the agent inherits the session's model The Claude Code harness, when implement.md dispatches the engineer, including the attended fix round