Capability: spec-workflow
The core loop: a work item is specified as a chain of artifacts — optional brainstorm, then a Kiro-style 3-phase spec plus a testing plan — each iterated with the human feedback its approval gate records, locked by that gate, then executed end-to-end with minimal intervention.
What it is
The product-development-lifecycle workflow the-loop runs on every work item, exposed as the /the-loop:work-on superset command and granular per-step commands (brainstorm, new-requirement, create-ticket, create-design, create-tasks-plan, execute-tasks, finish-tasks, work-status).
Current behaviour
- Every work item SHALL have a ticket; nothing is worked without one.
- A work item's spec SHALL live in
docs/specs/<id>/— the loop's fixed convention; the CLI's ownrouting.graph.specDirdefaults to it, and an operator whose instance drives repositories laid out differently sets that key or passes--spec-dir(issue-352) — as the artifact chainbrainstorm.md (optional) → requirements.md|bugfix.md → design.md → testing-plan.md → tasks.md, plusevidence/— the record each gate leaves, and the committed proof once verification has run. - Every tree of checked-in knowledge the loop maintains SHALL sit at its conventional place, not a configured one: specs at
docs/specs/<id>/, capability docs atdocs/capabilities/and learnings atdocs/learnings/(the indexlearnings.md, onelearning-<nnn>.mdeach,topics/), all repo-relative (issue-224, decision-082 placed the learnings inside the documentation tree; issue-352 removed theworkflowkeys that had let a project move the three). The learnings deliberately sit inside the documentation tree, so a repository that publishesdocs/publishes its learnings with it; the git-ignored write-gate queue (.the-loop/learnings-pending/) is harness state and stays out of it. requirements.mdandbugfix.mdSHALL be two accepted names for the same phase-1 artifact, not two artifacts. Either clears therequirements-definitiongate, held to the identical standard; both present blocks, because two phase-1 artifacts in one folder have no defined source of truth (decision-045). Both bundled templates carry the## Requirementsand## Security considerationssections the gate requires, so the choice is about which shape fits the work — reproduction and root cause, or user stories — and never about which one will pass.- An artifact with an approval gate SHALL be iterated with the feedback that gate records and SHALL be locked by the gate itself (issue-281): on an authorized approval,
lock-artifactswritesstatus: approvedand the approver into the front matter. The session SHALL NOT setstatus: approvedand SHALL NOT request an approval of its own — one gate, one human reply (the review per phase is always on and delivered by the gates; theworkflow.requireHumanReviewPerPhaseswitch was removed in issue-352). An artifact with no gate (brainstorm.md,tasks.md) advances on shape alone. No downstream artifact is written against an upstream one whose gate has not yet approved it. - The spec chain SHALL live in the origin repository — the one the ticket was created in — however many repositories the work item touches, and each contributing repository SHALL get one pull request walking its own inner loop (issue-183, decision-069). A work item MAY declare those repositories with
the-loop graph repos <id> --repository <owner>/<repo> …once the design and the task DAG say what the change spans, which records them inwork-item-state.jsonand turns them into a gate atimplementationrather than a note. - Where each artifact is iterated with humans SHALL be a durable, reviewable surface — never a terminal. For the outer loop the work item declares which, at
phase-selection: the work item itself (the default — comments on the ticket, so an item whose code lands in other repositories opens no discussion-only PR) or a pull request in the origin repository (theouter-loop-on-pull-requestbox). Either way the artifact SHALL be a committed file linked from the ticket — the choice is the review surface, not whether the chain is checked in. A pull request's own loop SHALL always be iterated on that pull request, and a contribution SHALL NOT be asked the question at all (issue-199): it joins a work item somebody else is running, so its one artifact is iterated on that thread and its record carries no surface. - WHEN a work item starts as a fuzzy idea THEN the loop SHALL begin with a
brainstorm.mdroot artifact (optional Phase 0) and convert it to requirements once its author says it has converged — the brainstorm has no approval gate and is neverstatus: approved(issue-281). - The work item's phase SHALL be tracked on the ticket via labels (
loop:<phase>, a fixed vocabulary since issue-352) through the state machinenot-started → brainstorming (optional) → requirements-definition → design → test-planning → tasks-breakdown → implementation → verification → needs-review → complete, with the fine detail (current node, attempts, declared skips) inwork-item-state.json. tasks.mdSHALL be a DAG of small verifiable tasks referencing requirements, each task's_Test:_naming a row oftesting-plan.md's matrix; checkmarks are kept current during implementation.- How the work item will be proved SHALL be planned, then executed as its own phase (testing-and-contracts, issue-163):
test-planningauthorstesting-plan.mdbefore the task DAG — and sits beforedesign-approval, so one human gate approves and locks the design and the plan derived from it — andverificationexecutes it after implementation and before the review chain, with results and committed evidence recorded in the same artifact. An activity that could not run is never ticked. - Security SHALL be a gated concern of each phase (a fixed rule, not a setting): requirements/bugfix carry a Security considerations threat-model-lite (untrusted actors, trust boundaries, abuse cases, fail-closed — "no new attack surface" is written and justified, never implied); design carries a Security design section enforcing every boundary; security-relevant tasks name the negative test proving the boundary holds.
- Completion SHALL be gated by the ready-to-ship gate (green checks, threads resolved, evidence — summarised from the verification results, a passed security review — the built-in security-review skill when available, else the-loop's checklist — PR briefing, capability docs folded in) and the fixed risk tiers: tier 1–2 autonomous-complete, 3–4 human-approves-pr, 5 human-approves-spec-and-pr, inferred from the change (default 3) and raised by a fixed set of sensitive paths (schemas,
.the-loop/**,.github/workflows/**, auth/secret/credential paths). An effective risk tier ≥ 4 SHALL wait for a named human security sign-off, and an unresolved security finding SHALL block completion at any tier. Tests are written alongside the implementation, always (a bug fix reproduces red first); there is no TDD mode to choose. - The loop SHALL read and honor the operator's custom instruction docs (
config.customInstructions): every registered doc is read, in order, immediately after loading the config when work on an item starts (and re-read after a context clear). The structured config wins where both speak; no instruction doc can weaken the loop's gates (security, paper trail, reviews, autonomy) — such instructions are ignored and the conflict logged, fail-closed. A missing doc is handled percustomInstructions.onMissing(defaultwarn). - A registration SHALL be verifiable, not only honoured. WHEN the agent (or an operator) runs
the-loop instructions --doc <entry>… --on-missing <policy>with the entries read fromcustomInstructions(the CLI reads no harness config, issue-352) THEN the loop SHALL report every doc given, in the order given, with its resolved path and one ofpresent/missing/unreadable/invalid; everything that is notpresentSHALL count as unresolved (invalidincluded), and--on-missingSHALL decide the exit code —error→ 1,warn→ 0 with a warning naming each one,ignore→ 0. IF no doc is given THEN the report SHALL be empty and the exit code 0, because registering nothing is not an error. The report SHALL carry facts about each doc and never its contents (cli, issue-132). - The loop SHALL manage its context window by checkpoint-then-reset (a fixed rule since issue-352,
config.contextManagementbefore it): a reset (clear or compact) is always preceded by a checkpoint —tasks.mdcheckmarks current, WIP committed, the phase label in sync. No prose checkpoint is written: the next step is the first unticked task and the pointer iswork-item-state.json's (issue-365). - WHEN the phase advances across a locked artifact (most importantly tasks-breakdown → implementation) THEN the loop SHALL clear and derive the next phase's work from the checked-in artifacts, not the conversation.
- WHEN a task in the DAG completes THEN the loop SHALL checkpoint and compact; mid-task only compaction is permitted, never clearing. Headless sessions reset by ending at the boundary and resuming fresh from the state file and the checkmarks.
- The phase state machine SHALL be executable, not only described. Each phase above is a node in the shipped process graph, with entry/exit hook chains that decide when it is complete and declared edges that route on those decisions (process-graph, issue-109). The prose in
reference/workflow.mdand the graph incli/the_loop/graph/pdlc.yamldescribe the same loop; the graph is the one that runs.the-loop check <id>reports where a work item actually stands against its checked-in artifacts, and--recomputederives that verdict from the artifacts alone rather than trusting stored state. - A work item may be delivered by several PRs. WHEN more than one PR delivers a work item (a spec PR then an implementation PR, a stacked series, a follow-up after review, one PR per repository) THEN the loop SHALL label each of them for routing and list all of them in
evidence/pull-requests.md, andfinish-tasksSHALL require every listed PR to be merged or closed before the work item is marked complete — one PR merging is not the work item ending (issue-101).
Design
reference/workflow.md · reference/context.md · reference/instructions.md · reference/security.md · SKILL.md · architecture § the loop
History
| Work item | What changed | Links |
|---|---|---|
| issue-368 | The work item's spec directory carries its pull requests (2026-09-15): work-item-state.json gained pullRequests[] — ref, repository, number, URL, inner-loop directory, upstream state and who recorded it — so a reviewer reads which pull requests deliver the item from the branch, and a second machine does not re-derive them from gh. It lost the session block in the same change: a harness conversation id is a handle to one machine and never belonged in a repository | spec, decision-128, process-graph, issue |
| issue-365 (review) | The multi-repo declaration moved off artifacts (2026-09-14) and onto a verb the agent calls, the-loop graph repos, writing work-item-state.json. It cannot be a phase-selection question: that gate runs before requirements, design and tasks exist, and which repositories a change spans is not knowable until they do — so it is declared at tasks-breakdown, bounded by shape and by the instance's own repositories, with the flags as the full set so a declaration can be corrected. The state file was renamed in the same round | spec, decision-127, process-graph, issue |
| issue-365 | The execution log was retired (2026-09-14): no template, no scaffolding, no log-entry hook at 47 node boundaries, no phase mirror and no prose checkpoint before a context reset — every fact in it was already in work-item-state.json, the loop:<phase> label, the commits and the harness's own transcript. What the log gated stayed: each review-chain node now reads one record of its own under evidence/, and the multi-repo repos declaration moved to work-item-state.json, declared by the agent once the task DAG exists. Existing logs are left where they are — history, read by nothing | spec, decision-126, process-graph, issue |
| issue-352 | The harness config became the agent's alone (2026-09-12): ticketing, workflow.phases, workflow.phaseLabelPrefix, workflow.specApproach, workflow.requireHumanReviewPerPhase, localOrchestration, notifications, reviews.critics and graph left it (version 0.3.0); labels are loop:<phase>; the-loop instructions and the-loop scenarios take the registered docs and globs as flags the agent passes; the skill's Configuration section tells the harness what the file is for and what to hand the CLI. Nine more blocks left because they configured what is now the-loop's fixed rule: autonomy (tiers 1–2 autonomous-complete, 3–4 human-approves-pr, 5 human-approves-spec-and-pr, inferred from the change, fixed sensitive paths), security (considerations in every requirements, design enforces the boundaries, a security review at the ready-to-ship gate, tier 4+ human sign-off), tdd (standard, always), minimalism, tokenEconomy, selfImprovement (learnings always on, index under 200 lines, written at the third occurrence), contextManagement (clear at a phase boundary, compact after each task, never mid-task), userInteraction and externalTools. A fourth pass removed workflow (specDir, capabilitiesDir, learningsDir): docs/specs/<id>/, docs/capabilities/ and docs/learnings/ are the loop's convention, and an instance laid out differently sets the CLI's routing.graph.specDir | spec, decision-123, issue |
| issue-281 | Approvals became gate-owned (2026-08-25): every artifact phase had been costing the human two approvals — one out-of-band to let the session set status: approved (demanded by locked: true on the producing node's exit), one at the graph's approval node, which discards pre-gate feedback — and tasks-breakdown demanded one with no gate at all. Producing nodes now gate shape only; a new lock-artifacts hook on requirements-approval, design-approval and the contribution loop's plan-approval writes status: approved plus the approvers as part of classifying the human's one reply; gate-less artifacts (brainstorm.md, tasks.md) advance with no human stop; and the skills/commands stopped re-implementing approvals in prose | spec, process-graph, issue |
| issue-224 | The learnings tree moved under the documentation tree: docs/learnings instead of a hardcoded top-level learnings/, with the-loop's own tree moved there and the upgrade command presenting (never taking) the relocation (the workflow.learningsDir key this introduced left the harness config in issue-352; the location is now the convention) | spec, decision-082, issue |
| issue-183 | The chain got a place: it lives in the repository the ticket was created in, one PR per contributing repository delivers it, and each work item declares at phase-selection whether the outer loop's artifacts are iterated on that repository's PR or on the work item itself (the default) — the inner loop deliberately not configurable. execution-log.md gained an optional repos: declaration that await-inner-loops gates on | spec, decision-069, process-graph, issue |
| issue-163 | The chain gained testing-plan.md between design and tasks, and the state machine gained the test-planning and verification phases — how a work item is proved is now planned, gated and evidenced rather than assumed | spec, decision-060, testing-and-contracts, issue |
| issue-124 | A bug's bugfix.md clears the phase-1 gate it always should have: the two documented names became alternatives for one artifact, both present blocks, and the bundled bugfix template gained the ## Requirements heading the gate asks for | spec, decision-045, process-graph, issue |
| issue-109 | The phase state machine became executable: every phase is a node in the shipped process graph, with hook chains deciding completion and declared edges routing on the outcome | spec, process-graph, decision-041, issue |
| issue-101 | The execution log tracks a list of the PRs delivering a work item; each is labelled for routing and all must be merged/closed before finish-tasks completes the item | spec, decision-039, issue |
| issue-132 | Custom instruction docs became verifiable: the-loop instructions reports which registered docs resolve and turns onMissing into an exit code, so a mistyped path is a signal rather than silence | spec, decision-049, cli, issue |
| issue-59 | Added per-installation custom instruction docs the loop reads and honors (customInstructions config, onboarding group, precedence rules) | spec, decision-029 |
| issue-48 | Added checkpoint-then-reset context-window management (clear at phase boundaries, compact at task boundaries, contextManagement config) | spec, decision-027 |
| issue-47 | Security became a gated concern of every phase: threat-model-lite in requirements, Security design section, security-review gate item, risk-tiered human sign-off (config.security) | spec, decision-026 |
| issue-25 | Added the capability-docs fold-in as a ready-to-ship gate item | spec, decision-020 |
| issue-18 | Design phase gained first-class UI/UX design artifacts | spec, decision-018 |
| issue-17 | Added the optional brainstorming phase and the iterate-until-locked rule as a first-class principle | spec, decision-017 |
| issue-1 | Established the 3-phase Kiro-style spec workflow, phase labels, granular commands and templates (v0) | spec, decision-004, decision-011 |