Imported from mrap/boi (
AGENTS.md). Install upstream withnpx skills add mrap/boi. Copyright stays with the author.
AGENTS.md — BOI
Single-binary Rust harness that orchestrates LLM-powered software-engineering tasks:
you hand it a spec (a TOML file of tasks), it runs each task through a phase pipeline
in an isolated git worktree, verifies, and merges. This file is the cold-start map for
an agent working in this repo. It is canonical for commands and spec format —
where it disagrees with docs/, trust this file and boi --help.
This checkout is the canonical BOI engine (TOML specs, control-socket daemon,
~/.boi/v2/boi.db; version: boi --version / Cargo.toml).
Start here
| To understand… | Read |
|---|---|
| The whole crate's shape | src/lib.rs (the //! — Layered Domain Architecture) |
| Why it's built this way | docs/design/2026-05-16-design.md (locked) |
| One subsystem | that module's //! doc (every src/*/mod.rs and most files carry one — e.g. src/runtime/goose.rs is the exemplar) |
| Domain terms | docs/agents/glossary.md |
| Trust model / what workers can touch | docs/security.md |
Build, test, verify (run these)
cargo build --locked # full build (bundled DuckDB needs a C compiler)
cargo check --no-default-features # fast dev loop, skips DuckDB
just check # fmt + clippy -D warnings + test + doc (the gate)
just ci # just check + the LDA/script lint suite
just lint-scripts # the architecture/guardrail check suite (scripts/checks/)
- CI runs
just check+just lint-scriptsPLUS jobs those don't cover: a Cargo.lock-stability check (no diff after a fresh resolve), an MSRV (1.85) build, acargo check --no-default-featuresbuild, andcargo audit(.github/workflows/ci.yml). - The
repolayer usessqlx::query!macros verified at compile time against a committed.sqlx/cache; CI builds withSQLX_OFFLINE=true. Regenerate the cache only when aquery!changes:just prep-sqlx(needssqlx-cli+ a.envwithDATABASE_URL=sqlite://.dev.db). Commit the.sqlx/delta with the query change. cargo testis unit + integration. Real-gooseruns are Docker, out-of-band:just e2e(Ollama) /just e2e-openrouter— they need Docker + network, never injust ci.
Architecture (one rule)
src/types → src/config → src/repo → src/service → src/runtime → src/cli
Forward-only dependencies, enforced by scripts/checks/module-dep-audit.sh. LLM phases
route through runtime::goose::GooseRuntime (goose run --recipe X.yaml); deterministic
phases (workspace verify, validate, commit, merge, teardown) are native Rust in
runtime::deterministic (DETERMINISTIC_PHASES + resolve()). Detail: docs/agents/conventions.md,
docs/agents/adding-features.md.
Each src/<layer>/ has its own AGENTS.md — a thin router for that layer (what it
owns, its boundary, the file map, local invariants) pointing to the module //! for
depth. Working inside a layer? Read that layer's AGENTS.md first.
CLI (authoritative — from boi --help)
| Command | Does |
|---|---|
boi dispatch <spec.toml> |
parse, validate, persist, and start a spec |
boi log <spec-id> |
phase-run history for one spec |
boi dashboard |
spec-observability TUI |
boi cancel <id> --reason "…" |
cancel a spec or a single task (reason mandatory) |
boi unblock <task-id> [--reset-counter] |
force a blocked task back to active (optionally zero its iteration counter) |
boi answer <task-id> "<guidance>" |
record operator guidance for a task; delivered once into its next propose_adjustment phase (blocked is the primary case; active is legal) |
boi reopen <spec-id> [--task <ref>[,…]] [--reason "…"] [--retry] [--dry-run] [--preserve-counters] |
re-arm a spec that a spec-level halt left failed with passing tasks (FIX-022): --task reopens named passing tasks for rework (Lane 2, follow with boi unblock); --retry re-runs a merge/teardown halt with no task touched (Lane 3); every apply and refusal is audited in spec_reopens |
boi resolve-conflict <task-id> |
resolve a task's merge conflict in an interactive shell (no --ai — deliberate) |
boi fail <spec-id> --reason … |
operator-marked failure |
boi clean <spec-id> [--force] [--phase-runs-older-than <duration>] |
delete a spec + cascade (retention); --force skips the terminal-state guard, --phase-runs-older-than <90d|2w|...> prunes only completed phase_runs rows instead of a full clean |
boi spec show <spec-id> |
dump the stored spec snapshot |
boi daemon <serve|start|stop|status|restart> |
service lifecycle; serve is the boot loop (the LaunchAgent rides this) |
boi traces / boi failures |
OTel queries (needs the duckdb build feature) |
boi completions <shell> |
emit a shell completion script |
boi mcp-serve |
one stdio MCP server bound to a single worker's phase run |
Run boi <cmd> --help for the exact signature. There is no top-level boi status in
v2 (boi daemon status exists for the service) — use boi dashboard or query
~/.boi/v2/boi.db.
Spec format (TOML)
[contract] + [[tasks]]; pipeline = "standard", delivery = "merge". The
canonical, runnable examples are tests/fixtures/specs/*.toml — read those rather
than a prose schema (start with 01_minimum.toml, then 02_multi_task_dag.toml).
Validate before dispatch: python3 -c "import tomllib; tomllib.load(open('s.toml','rb'))".
Branching & releases (GitFlow)
This repo uses GitFlow. Work lands on develop via PR with the required checks green;
main moves only by release/hotfix merges performed by the hex release cut
ceremony. Manual chore: bump version commits and hand-made tags are retired — the
ceremony owns the gate battery, the Cargo.toml version bump, the merge to main, the
tag, and the back-merge to develop. A push to main outside the ceremony is an
incident: remediation is to merge main into develop (restores the
main-is-ancestor-of-develop invariant), then re-run the cut.
| Namespace | Created by | Merges to |
|---|---|---|
feature/<slug>, fix/<slug> |
developers | develop (PR, required checks green) |
release/X.Y.Z |
hex release cut only |
main (tagged vX.Y.Z), back-merged to develop |
hotfix/* |
hex release cut --hotfix only |
main (tagged), back-merged to develop |
spec/<SpecId>/integration, spec/<SpecId>/<TaskId> |
BOI engine | engine-managed — never create by hand |
salvage/<SpecId> |
operator (manual rescue of stranded spec/* work) |
develop, never main |
Branch-policy marker: .boi-policy.toml at a workspace root declares the branch
model to the BOI engine — model = "gitflow" | "trunk"; protected lists branches the
engine must never deliver to (default ["main"] under gitflow, [] under trunk). The
engine reads the marker from the committed tree of the spec's base_branch
(checkout-independent), and refuses protected-branch deliveries. No marker = unmanaged =
pre-GitFlow behavior. A present-but-invalid marker is a hard, typed error — never
silently ignored.
Spec-author rule: BOI specs targeting this repo MUST set base_branch = "develop".
Critical invariants (full list with enforcement citations: docs/agents/invariants.md)
- Migrations are append-only — never edit an applied
migrations/NNNN_*.sql; add a new numbered file.sqlx::migrate!("./migrations")(src/repo/db.rs) tracks applied versions; there is no down migration. - DB pragmas (
src/repo/db.rs):journal_mode=WAL(concurrent reads during writes)foreign_keys=ON(every FK isON DELETE RESTRICT).
- Worktrees in
~/.boi/v2/worktrees/are ephemeral — never edit files there; they're destroyed on cleanup. - Verify commands must be idempotent — a worker may re-run verify on retry.
- Verification commands run with the shared
CARGO_TARGET_DIRinjected (~/.boi/v2/cargo-target, OBS-032) —cargoartifacts do NOT land in the worktree'starget/. A gate checking a build artifact must use${CARGO_TARGET_DIR:-target}/release/<bin>, never a baretarget/...path (that gate now fails deterministically). Never symlink a worktreetarget/to the shared dir — it holds other specs' binaries, sotest -xwould false-pass. - A malformed routing graph / phase config is a loud startup rejection, never a silent mid-run stall.
Docs map
| Where | What | When to read |
|---|---|---|
docs/agents/ |
adding-features, conventions, debugging, glossary, guardrails, invariants | working in this repo — task-specific, on demand |
docs/getting-started.md |
operator quickstart (build → secrets → daemon → first dispatch) | running BOI for the first time |
docs/security.md |
trust model — what workers can touch | before dispatching untrusted spec content |
docs/doc-maintenance.md |
doc routing map + per-claim checks + declined changes | doing a docs pass |
docs/design/, docs/plans/, docs/reviews/, docs/research/, docs/diagnostics/, docs/notes/ |
frozen dated records (design source, plans, incident diagnoses) | history/rationale only — being outdated is by design |
docs/extensibility/, docs/cli/, docs/migration/ |
distributed-v0.1 design fiction — unimplemented | only when designing that future |
docs/boi-current-state.md, docs/cutover-runbook.md |
bannered historical records | lineage context |
docs/agents/ was rewritten against v2 code 2026-06-10; if a claim there surprises you,
verify against the source (per-claim checks: docs/doc-maintenance.md).