Skip to content

Build master @ bc50cd5bunreleased — 31 commits past v1.282.0Last reviewed Last changed Grade fresh (aging >90d, stale >180d)Source / History

bob do reference ​

The machine for unstructured work (#2979, #2980). The engine is scripts/do/do.js, and the run's state is .claude/.do-state.json. For flags and exit codes see bob do in the CLI reference. For the steps see Run unstructured work with bob do, and for the reasoning see The bob do machine.

Phases and events ​

Every event except stop is evidence-fired. bob do transition <event> runs the phase's gate, and the event fires only when the gate passes. A bare engine transition is refused.

FromEventToPayload (--data)Gate
framingframedworking{"artifact":"<type>","question":"…"?}a one-line question and an artifact from the closed set
workingworkedlanding{"enough":"<why>"}the budget is spent, or a one-line reason is given
workingdiscarddiscarded{"decision":N}a decision issue naming the question (read back)
landinglandedrecordingsee Artifact evidencethe declared artifact exists (read back)
landingdiscarddiscarded{"decision":N}as above
recordingrecordeddone{"prompted_by":"#N" | "<path>" | "none"}the artifact and its prompt link each other (read back)

done and discarded are the terminals, and both exit 0. When the budget is spent, every bob do verb moves a run in working to landing with budget_exhausted: true. bob do stop removes the state file from any phase.

Artifact evidence ​

The table below is ARTIFACT_EVIDENCE in scripts/do/do.js, the one place the evidence is declared. The landed gate re-reads the forge or the tree at the moment of the transition and never trusts the state. A refusal names the artifact type and what is missing.

Artifactlanded requiresPayload
decisionan issue labelled decision whose title, body or comments name the question{"issue":N}
lessonan issue labelled lesson naming the question{"issue":N}
doca file under docs/ that exists, is committed with no uncommitted changes, and passes the docs check (the doc-keeper auditor scans it and reports no high-severity finding){"path":"docs/…"}
spikean issue labelled research naming the question, or a committed doc as for doc{"issue":N} or {"path":"docs/…"}
issue-setat least one issue labelled req, task or bug. Each one names the run by its question or its run_id{"issues":[N,…]}
discardthe decision issue a discard needs: labelled decision, naming the question{"issue":N}

"Names the question" means the question appears in the issue's title, body or comments, compared case-insensitively with whitespace collapsed.

prompted_by is what prompted the run:

ValueMeaningWhat is read back
#Nan issue: a brief, a session report, a bugits title, body and comments
<path>a file in the checkout, such as a briefthe file
noneno promptnothing. prompted_by: none is recorded explicitly

Both directions must hold. The artifact links the prompt: every artifact issue mentions #N (or /issues/N), or the doc contains the prompt's path. The prompt links the artifact: it mentions every artifact issue, or the doc's path. A refusal names each direction that is missing.

State fields (bob-do/1) ​

bob do status --json prints these at the top level. The same values live under data in the state file.

FieldSet atValue
run_idstartdo-<UTC timestamp>
question, artifactframingthe one-line question and the artifact type
budget, budget_use, budget_exhaustedstart / working{kind: minutes | tokens, value, source}, usage so far, and whether the budget ended the phase
enoughworkingthe declared reason, or null
artifact_reflanding (or discard){kind: issue | issue-set | doc, issues?, path?, url?}
decisiondiscard{number, url}
prompted_byrecording#N, a path, or none
outcomethe terminaldone or discarded. Together with artifact_ref this is the run's last result, which the session row of #2978 reads
refusalany refused gate{gate, reason, detail, at}, cleared when an event fires