Use at end of a session to update HANDOFF.yaml with completed work, new gaps discovered, and current project state. Also use when asked to create a HANDOFF.yaml for a project that doesn't have one yet.
HANDOFF.yaml is the committed source of truth for task/workflow tracking. It syncs with doob.
Project state (build, tests, branch) lives separately in .ctx/HANDOFF.state.yaml — generated,
never committed. A rendered reference doc is also written to .ctx/HANDOFF.md.
| File | Location | Committed | Purpose |
|---|---|---|---|
HANDOFF.<project>.<base>.yaml | repo root | yes | Tasks, items, log — doob source of truth |
.ctx/HANDOFF.state.yaml | .ctx/ | no | Project snapshot — build/tests/branch/notes |
.ctx/HANDOFF.md | .ctx/ | no |
| Generated reference doc (rendered view of both) |
.ctx/ must be in .gitignore. Never commit anything under it.
Always use handoff-detect to resolve the HANDOFF.yaml path:
handoff-detect # returns path if exists, expected path + exit 2 if not
handoff-detect --name # expected filename only (e.g. HANDOFF.devkit.devkit.yaml)
handoff-detect --root # repo root
handoff-detect --project # project name
File naming convention: HANDOFF.<project>.<cwd-basename>.yaml
project = name from Cargo.toml / go.mod / pyproject.toml, fallback to repo root dir namecwd-basename = basename $(pwd) at time of invocationLegacy fallback (read-only): if handoff-detect exits 2 and a HANDOFF.md exists at repo root,
read it as freeform. Do not convert unless asked.
Task/workflow tracking only. No build state — that goes in .ctx/HANDOFF.state.yaml.