| name | bd-close-rationale |
| description | Close a bd issue with structured rationale, evidence-path verification, worktree-owner lifecycle enforcement, and post-close verification. Idempotent. |
bd close with rationale
When to invoke
At every bd issue closure that warrants substantive rationale (most non-trivial closures). The primitive's idempotency makes it safe to use as the default closure mechanism — re-running on an already-closed issue is a no-op rather than an error.
What it does
Invokes tools/bd-close-rationale.sh with an issue id, a rationale markdown file, and optional comma-separated evidence paths. The primitive wraps bd close --reason-file with six value-adds: (1) idempotency (early-return when status is already closed); (2) evidence-path verification (halts on first missing path); (3) worktree-owner lifecycle enforcement (halts if the closing issue still owns non-evidence worktrees); (4) HEAD + ISO 8601 UTC timestamp prefix prepended to the rationale body; (5) post-close round-trip via bd show confirming status=closed; (6) workspace-db pin (amnesia-tvpb / Standing #16 R16): every bd read/write is pinned with bd --db <git-root>/.beads/beads.db. A bd note is also written so the rationale is queryable independent of bd show --reason; its failures are surfaced (non-fatal) rather than silently swallowed.
Database-targeting guarantee (amnesia-tvpb)
The primitive derives the target database from the git common dir (git rev-parse --git-common-dir → main worktree root) and pins it on every bd close/bd note/bd show. Using the common dir (not --show-toplevel) makes it worktree-safe: a closure run from a linked git worktree (.claude/worktrees/agent-*, whose root has no .beads) correctly targets the shared main-repo .beads. It does not rely on bd's cwd auto-discovery, which (when invoked outside a git repo) walks the filesystem up and can silently resolve an ancestor/home .beads — closing the wrong database. (PYTHONPATH for the adapter still uses the invocation worktree's tools/ so a worktree runs its own adapter code.) The wrapper hard-aborts (exit 1, no silent fallback) when:
- it is run outside a git workspace (
git rev-parse --git-common-dir fails), or
- the resolved workspace
.beads directory is absent.
Run it from the main repo or any linked worktree (any depth is fine).
Contract with primitive
- Primitive:
tools/bd-close-rationale.sh
- Flags / inputs:
--id <bd-id> (required)
--rationale <file> (required)
--evidence-paths <comma-list> (optional; each path is verified via the P1 file-path resolver)
- Output:
- On success:
closed: <id> (HEAD=<sha>) on stdout.
- On idempotent no-op:
already closed: <id> on stderr; exit 0.
- On failure: error message on stderr; exit 1.
- Exit semantics: 0 on success or idempotent no-op; 1 on missing inputs, missing evidence, target-owned non-evidence worktrees, or close failure.
Example invocation
tools/bd-close-rationale.sh \
--id amnesia-o4fp.6 \
--rationale apps/amnesia/docs/perf-evidence/2026-05-11/o4fp.6/rationale.md \
--evidence-paths apps/amnesia/docs/perf-evidence/2026-05-11/o4fp.6/manifest.json,apps/amnesia/docs/perf-evidence/2026-05-11/o4fp.6/summary.md
Halt conditions
- Not inside a git workspace (
git rev-parse --git-common-dir fails) — halt + surface "not inside a git workspace — refusing to run" (amnesia-tvpb db-targeting guard).
- Resolved workspace
.beads absent — halt + surface "workspace bd database not found at /.beads" (amnesia-tvpb db-targeting guard).
- An evidence path passed via
--evidence-paths does not exist on disk — halt + surface "evidence missing: ".
- The target issue still owns a non-evidence worktree — halt + surface the owner id, worktree path, and "remove or hand off" remediation. Delete the worktree or update
.amnesia/worktree-owner.json to another open owner before retrying closure.
bd close itself fails — halt + surface bd's stderr.
- Post-close
bd show reports a status other than closed — halt + surface "close failed".
Note
Idempotent. Running on an already-closed issue prints already closed: <id> to stderr and exits 0; no rationale is rewritten and no duplicate bd note is added. Use this primitive freely in retry loops.
Related
- Sibling skill:
closure-attest produces a JSON closureAttestation document that is a natural fit for the rationale body (write closure-attest output to a file, pass that file as --rationale).
- ADR-016 §6 Evidence Bundle Schema: when used together, the rationale references evidence paths whose hashes are recorded in the attestation.