Build a project from scope xBRIEFs following Deft Directive framework standards. Use after deft-directive-setup has generated the project definition, or when the user has story xBRIEFs in xbrief/active/ ready to implement. Handles scaffolding, implementation, testing, and quality checks phase by phase.
Install
npx skillscat add deftai/directive/deft-directive-build Install via the SkillsCat registry.
Deft Directive Build
Implements a project from its scope xBRIEFs following Deft Directive standards.
Legend (from RFC2119): !=MUST, ~=SHOULD, ≉=SHOULD NOT, ⊗=MUST NOT, ?=MAY.
When to Use
- After
deft-directive-setupcompletes and generatesPROJECT-DEFINITION.xbrief.json - User says "build this", "implement the spec", or "start building"
- Resuming a partially-built project that has story xBRIEFs in
xbrief/active/
Ordered-plan / cohort exhaustion (#2402)
Multi-scope turn/cache budget (epic #3009)
Multi-scope greenfield (app-bank pins, N story scopes) multiplies agent turns when ceremony, promote, check, and render are re-run per scope. Apply the following after offline seed.
Offline seed vs implement phase (#3010)
! Distinguish offline seed (operator or harness already ran directive init / deposit, pin-copied scopes into xbrief/proposed/, and recorded session ritual) from the agent implement phase.
! When seed + session ritual are already complete for the engagement:
- ⊗ Run
directive initagain - ⊗ Run full cold
session:startunless hooks deny writes and recovery is required - ⊗ Run
directive migrateor re-copy scopes already present - ! Prefer recovery via
session:ready(or re-arm) when PreToolUse denies — not full re-init - ! Documented consumer/harness contract: seed is done once; implement agents only activate+implement
Batch promote; one active implement (#3011)
! For a multi-scope pin, batch-stage scopes with task scope:promote -- --batch (all proposed/) or task scope:promote -- --batch <path>….
! Implement path remains one scope:activate + implement at a time — no multi-active write fence.
! When pin order is known, do not re-list the entire lifecycle tree every scope; walk the known ordered list.
⊗ Activate all scopes at once or drop the one-active-scope / story-ready stack.
Quality check once at end of multi-scope batch (#3012)
! On an approved multi-scope batch (operator-approved multi-story branch, swarm cohort, or pin walk): run full task check (merge chokepoint) once at the end of the batch (or after the last scope), not after every scope.
! Exception: if the last full check failed, fix loops MAY re-run check until green.
! Pre-PR / merge-ready gates remain end-of-unit — this does not weaken them.
! Iteration lane (affected tests / verify:forward-coverage / coverage:hotspots) still applies per scope during implementation (#1704).
⊗ Spam full directive check / task check after every scope when the batch is still mid-flight and the last merge-chokepoint check was green.
One-shot project:render (#3013)
! Greenfield init seeds a minimal render-ready PROJECT-DEFINITION. Treat task project:render as a refresh of items from lifecycle folders, not multi-turn identity research.
⊗ Invent project identity across many turns when seed already stamped the skeleton.
! When processing an approved multi-story cohort or an active ordered-plan sequence, stop after the final approved entry. Do not promote or dispatch adjacent stories from queue intuition. Continuation language advances only within the approved order; skill-chaining is non-authorizing.
Step 0 -- Implementation Preflight (#810)
- ! Before starting any new implementation story or switching from one story to another, MUST run
git status --short --branch. - ! If the working tree is dirty, MUST stop and summarize the current branch, modified/untracked files, and whether the changes appear related to the target story. Ask the operator to choose one path: commit existing work, stash existing work, include existing work in the current story, or stop.
- ⊗ Begin a new story while unrelated dirty work is present without explicit operator approval.
- ! Resolve exactly one target story xBRIEF path by default. One story is the default implementation unit for this skill; if the user asks for a phase/epic, decompose or ask which story to start.
- ! Batching multiple stories in one branch/PR requires explicit operator approval and a short rationale recorded in the handoff.
- ! Swarm-cohort dispatch carve-out: when this skill is invoked as part of a swarm cohort allocated by
skills/deft-directive-swarm/SKILL.md, the approved Phase 5 allocation plan satisfies the "explicit operator approval and short rationale recorded in the handoff" requirement above -- the dispatched xBRIEF paths and allocation rationale ARE the consent token. Process each assigned story sequentially under the checkpoint-commit +task scope:completediscipline below. Do NOT re-prompt the parent for batching approval mid-cohort -- the all-or-nothing dispatch envelope rule (AGENTS.md## Multi-agent orchestration discipline (#954)) forbids mid-scope user-approval gates. - ! Structured consent-token recognition (#1378): the canonical recognition path for the carve-out above is the structured
## Allocation contextsection of the dispatch envelope (the frozen schema intemplates/agent-prompt-preamble.md, Story A of #1378). When that section reportsdispatch_kind: swarm-cohortwith a non-nullallocation_plan_idAND a non-nullbatching_rationale, the consent token is satisfied mechanically -- readcohort_vbriefsas the authoritative file boundary and process each entry sequentially under the checkpoint-commit +task scope:completediscipline below, without re-prompting the parent for batching approval mid-cohort. When the## Allocation contextsection is ABSENT (pre-#1378 dispatches, solo-interactive sessions), fall back to the #1371 prose carve-out immediately above -- the prose carve-out remains the recognition path of record for un-elevated envelopes. - ! Within a cohort, between stories: the working tree MUST be clean after each story's checkpoint commit +
task scope:complete. Ifgit status --shortshows uncommitted state between stories (e.g. a missedtask scope:completemove, an unstaged file from the prior story), checkpoint-commit it and proceed -- do NOT pause to ask the operator. The dirty-tree "ask the operator" branch above applies only at the FIRST story-start of a fresh branch, where uncommitted operator work might legitimately exist. - ! If the target story is in
xbrief/proposed/, runtask scope:promote -- <path>first (ortask scope:promote -- --batchfor a multi-scope pin — #3011); if it is inxbrief/pending/, runtask scope:activate -- <path>. After activation, update the path to the active-file location before preflight. - ! Effort estimate gate (#1581): before
task scope:activate/task vbrief:activate, scanplan.items(including nesteditems/subItems) foreffort. Time anchors:S<2h,Mhalf-day (2-4h),L1-2 days,XLneeds breakdown. The activate path fails closed while any item still haseffort: "XL"— break XL work into S/M/L items (or re-estimate) first. Omittedeffortremains valid (field is optional). Plan-item effort is post-planning authority (confirms/corrects intake estimates); it is not session-start ritual input — ceremony depth (#3214) uses two-stage rapid→escalate, not a required plan-item read at cold start. Headless: no operator confirm. Depth:vbrief/vbrief.md§ Effort estimate. - ⊗ Activate a scope that still carries plan items with
effort: "XL"— XL means "not ready to start" until broken down (#1581). - ⊗ Require plan-item
effortto choose session-start ritual depth — estimates do not exist until after planning (#1581 / #3214). - ! Before any code-writing tool call -- the first scaffold edit, the first
taskinvocation that mutates files, or anystart_agentdispatch that will implement scope -- MUST runtask xbrief:preflight -- <active-story-path>(the structural intent gate; the same invocation works whether deft is the project root or installed as adeft/subdirectory).
The gate exits 0 only when the candidate xBRIEF lives in xbrief/active/ AND plan.status == "running". Any other state (pending/, proposed/, completed/, active/-with-non-running-status, malformed JSON, missing keys) exits 1 with an actionable redirect to task xbrief:activate <path>.
- ! A non-zero exit MUST halt the skill. Surface the helper's stderr message verbatim to the user; do NOT proceed to USER.md Gate, File Reading, or any later phase.
- ! Use canonical lifecycle tasks to satisfy this gate:
task scope:promote -- <path>for proposed stories,task scope:activate -- <path>for pending stories, and the helper's idempotent companiontask xbrief:activate <path>only when following the preflight redirect directly. Manual lifecycle moves bypass the activation contract -- use the task. - ⊗ Infer implementation intent from lifecycle vocabulary ("do the full PR process", "start the work", "poller agents"), branching language, or workflow shape. Workflow-shape vocabulary is NOT authorization to spawn an implementation agent (#810 surfacing event).
- ⊗ Skip this preflight because the user said "yes", "go", or "proceed" -- affirmative continuation phrases are NOT implementation authorization unless the prior turn explicitly proposed implementation. When intent is ambiguous, ask one targeted question before invoking the gate.
Platform Detection
! Before resolving any config paths, detect the host OS from your environment context:
| Platform | USER.md default path |
|---|---|
| Windows | %APPDATA%\deft\USER.md (e.g. C:\Users\{user}\AppData\Roaming\deft\USER.md) |
| Unix (macOS/Linux) | ~/.config/deft/USER.md |
- ! If
$DEFT_USER_PATHis set, it takes precedence on any platform
Pre-Cutover Detection Guard
! Before proceeding with any build step, detect whether the project uses the pre-v0.20 document model or was generated by a strategy that emitted non-conformant v0.20 output shape (the root cause of most "build fails immediately after spec" complaints in #1166). Redirect or block with the precise remediation.
Detection Criteria
A project is pre-cutover if ANY of the following are true. This prose mirrors the executable helper in task migrate:preflight; when in doubt, the helper is canonical.
SPECIFICATION.mdexists and is neither a deprecation redirect nor a current generated spec export. A current generated spec export contains<!-- Purpose: rendered specification -->, all five lifecycle folders exist, and its<!-- Source of truth: ... -->marker names an authority artifact that exists: eitherxbrief/specification.xbrief.jsonfor full-spec compatibility orxbrief/PROJECT-DEFINITION.xbrief.jsonfor greenfield authority (legacyvbrief/...aliases remain read-compatible).PROJECT.mdexists and contains neither the legacy<!-- deft:deprecated-redirect -->sentinel NOR the currentPurpose: deprecation redirectcanonical-banner marker (real content, not a deprecation redirect)xbrief/specification.xbrief.jsonexists but the lifecycle folders (xbrief/proposed/,xbrief/pending/,xbrief/active/,xbrief/completed/,xbrief/cancelled/) do NOT exist- Strategy output shape violations (run
task verify-strategy-output-- the canonical gate for source and consumer installs):- Any scope xBRIEF under
xbrief/proposed/(or other lifecycle dirs) lacks the requiredYYYY-MM-DD-date prefix in its filename (e.g. barescaffold.xbrief.json). xbrief/PROJECT-DEFINITION.xbrief.jsonis missing.xbrief/specification.xbrief.jsonexists as a legacy dual-write in a user-generated project. This is tolerated only for the framework source tree or a complete post-cutover full-spec consumer where all lifecycle folders exist andSPECIFICATION.mdis rendered fromxbrief/specification.xbrief.json.
- Any scope xBRIEF under
Action on Detection
! If pre-cutover or strategy-nonconformant state is detected, stop immediately and display an actionable message that cites the exact validator:
"This project was generated with pre-v0.20 or non-conformant strategy output. Run the deterministic validator and follow its remediation:
task verify-strategy-output(works in source and afterdeftpackage install). For document-model migration, follow UPGRADING.md § Frozen pre-v0.20 document-model migration (#2068): pin v0.59.0, then runtask migrate:vbrieffrom that payload. Otherwisetask project:render/ strategy re-run as indicated."
! Include specific details about what was detected (the validator output is authoritative):
- Legacy specification.xbrief.json or missing lifecycle folders: "Follow the frozen v0.59.0 migrator path (#2068) or run
task migrate:preflightfor current-release guidance" - Non-date-prefixed xBRIEFs: "Re-run the emitting strategy after the v0.20 migrations (#1166 s1+s2+...) or manually rename files to
YYYY-MM-DD-<slug>.xbrief.jsonandtask scope:promote" - Missing
PROJECT-DEFINITION.xbrief.json: "Runtask project:renderto generate the project definition" SPECIFICATION.md/PROJECT.mdwithout sentinel: the classic pre-cutover messages- Scope xBRIEF in wrong folder: "Status is '{status}' but file is in {folder}/ -- run
task scope:activate <file>to fix"
! After the validator reports clean, re-run this guard before continuing.
⊗ Proceed with build when pre-cutover or strategy-nonconformant artifacts are detected -- always redirect to the frozen migration path first (or run the validator) and surface the exact remediation.
⊗ Silently ignore these artifacts or guess at fixes -- the validator (wired into task check and this guard) is the deterministic gate.
USER.md Gate
! Before proceeding, verify USER.md exists at the platform-appropriate path
(resolved via Platform Detection above, or $DEFT_USER_PATH if set).
- ! If USER.md is not found: inform the user and redirect to
deft-directive-setup
Phase 1 before continuing -- do not proceed without user preferences - ! Once USER.md exists, continue with the Cost Phase Gate below
Forge-outage drop-back (#3422)
! On attributed platform outage or repeated REST 429/502/503 during YOLO / through-merge implement: drop GitHub I/O, report once to the human in chat, and re-probe on plan.policy.forgeOutageRetryMinutes (default 30; USER.md Personal wins; min 5; task policy:show --field=forgeOutageRetryMinutes). Local edit/test/commit MAY continue. Depth: `scm/github.md` § #3180 / #3422. Complements #3167 / #3180.
⊗ Tight retry, empty-commit thrash, or sending the human to github.com as the only remediation.
Cost Phase Gate (#739)
! Before proceeding to File Reading, verify the project has gone through the
pre-build cost & budget transparency phase from skills/deft-directive-cost/SKILL.md.
This closes the adoption-blocker surfaced by issue #739 (refs #151 umbrella) where
users finished the spec flow and stopped at build because deft offered no cost
signal.
Detection
- ! Check for
COST-ESTIMATE.mdin the project root. - ! Check that the file contains a recorded decision (the Decision recorded
block populated with one of:build,rescope,no-build,skip). - ! For
skip,rescope, orno-builddecisions: the Reason field MUST be
populated (one or two sentences in plain language). A skip with no reason
recorded is treated the same as no decision.
Action
! If
COST-ESTIMATE.mdis missing OR the Decision recorded block is
unpopulated OR askip/rescope/no-builddecision has no reason recorded:
stop immediately and redirect the user:"This project has not gone through the pre-build cost & budget transparency
phase. Runskills/deft-directive-cost/SKILL.mdto produce a plain-EnglishCOST-ESTIMATE.md, then re-run the build skill once the user has chosen
build / rescope / no-build / skip(+reason)."! On a
buildorskipdecision: continue with File Reading below.! On a
rescopedecision: stop and redirect the user back to spec edits
(chain toskills/deft-directive-refinement/SKILL.mdto pull spec scope
back, or the interview), then re-runskills/deft-directive-cost/SKILL.md
before re-attempting build.! On a
no-builddecision: stop and exit; do NOT proceed to File Reading.
The user has explicitly stopped the project at the cost phase.⊗ Proceed to File Reading or any subsequent phase when
COST-ESTIMATE.mdis
missing, when the decision is unpopulated, or when a skip / rescope / no-build
decision has no reason recorded.⊗ Treat a
rescopeorno-builddecision as if it were abuild-- the
build skill MUST honor the recorded decision.
File Reading
- ! Read in order, lazy load:
./xbrief/active/-- scope xBRIEFs for work items to build (required)./xbrief/PROJECT-DEFINITION.xbrief.json-- project identity, tech stack, architecture./.planning/codebase/MAP.md-- generated codebase orientation projection, if present (advisory)- USER.md at the platform-appropriate path (see Platform Detection) -- Personal section is highest precedence; Defaults are fallback
deft/main.md-- framework guidelinesdeft/coding/coding.md-- coding standardsdeft/coding/testing.md-- testing requirementsdeft/coding/toolchain.md-- toolchain validation rulesdeft/languages/{language}.md-- only for languages this project uses
- ~ If the MAP is absent or may be stale and the current scope needs broad codebase orientation, run
task codebase:mapandtask verify:codebase-map-freshwhen those commands resolve. Treat absence/staleness as advisory unless the task editsplan.architecture.codeStructure, a configured provider artifact, or the generated MAP itself. - ! Treat
plan.architecture.codeStructureand selected provider artifacts as authoritative. The MAP is a generated projection. - ⊗ Read all language/interface/tool files upfront
- ⊗ Hand-edit
.planning/codebase/MAP.mdor block unrelated implementation solely because the MAP is stale or absent
Rule Precedence
USER.md Personal <- HIGHEST (name, custom rules -- always wins)
PROJECT-DEFINITION.xbrief.json <- Project-specific (tech stack, architecture, config)
USER.md Defaults <- Fallback defaults (used when PROJECT-DEFINITION doesn't specify)
{language}.md <- Language standards
coding.md <- General coding
main.md <- Framework defaults
Scope xBRIEFs <- LOWEST- ! USER.md Personal section always wins over any other file
- ! For project-scoped settings, PROJECT-DEFINITION.xbrief.json overrides USER.md Defaults
Change Lifecycle Gate
! Before any implementation that touches 3+ files, verify that a /deft:change <name> proposal exists and has been confirmed by the user:
- ! Check
history/changes/for an activeproposal.xbrief.jsonmatching this work - ! If no proposal exists: propose
/deft:change <name>and present the change name for explicit confirmation (e.g. "Confirm? yes/no") - ! The user must reply with an affirmative (
yes,confirmed,approve) — a general 'proceed', 'do it', or 'go ahead' does NOT satisfy this gate - ? For solo projects: this gate is RECOMMENDED but not mandatory for changes fully covered by
task check; it remains mandatory for cross-cutting, architectural, or high-risk changes - ⊗ Skip this gate because the user has already said "proceed" or "go ahead"
Build Process
All xBRIEFs (including those read from xbrief/active/ and any new xBRIEFs this skill emits) MUST use "xBRIEFInfo": { "version": "0.8" }. Legacy 0.6 is read-accepted until deft migrate:xbrief. The validator accepts both; new writes are 0.8 only (see `../../conventions/references.md`).
Step 1: Understand the Scope
- ! Read story xBRIEFs from
xbrief/active/andPROJECT-DEFINITION.xbrief.json - ! Identify phases, dependencies, starting point from scope xBRIEF acceptance criteria
- ~ Use
.planning/codebase/MAP.md, when present, to orient broad codebase scanning. If the MAP conflicts with current code or canonical metadata, surface the drift and trustplan.architecture.codeStructure/ provider artifacts plus the working tree over generated prose. - ! When scanning the existing codebase during scope understanding, MUST surface any contradicting patterns (two error-handling shapes, two state-management approaches, two naming conventions, etc.) before implementation begins -- apply
coding/hygiene.md## Surface Conflicts: Pick One, Explain, Flag the Other (#1005)and choose ONE pattern (more recent OR more tested), explain the choice in the scope summary, and flag the other for cleanup - ⊗ Begin implementation against an averaged blend of two contradicting patterns -- "average code that satisfies both rules is the worst code" (#1005)
- ! Present brief summary to user:
"Here's what I see: {N} story xBRIEFs in active/. I'll start with {name}. Ready?"
Step 2: Verify Toolchain
- ! Before any implementation, verify all tools required by this project are installed and functional — see
deft/coding/toolchain.mdfor full rules - ! At minimum: confirm task runner (
task --version), language compiler/runtime, and platform SDK (if applicable) are available - ! If any required tool is missing, stop and report — do not proceed to Step 3
- ⊗ Assume tools are available because the spec references them
Gate throughput — iteration fast lane vs merge chokepoint (#1704)
Invariant: every change MUST pass the full gate at least once before merge. Iteration MAY use a cheaper proxy; the merge chokepoint MUST NOT be skipped.
- ! Iteration lane (agents + humans): during implementation commits, use affected/static gates — targeted tests on changed paths (
vitest run --coverage <paths>or project equivalent), staticverify:*gates relevant to touched files, andtask coverage:hotspots/task verify:forward-coverage— NOT fulltask checkon every commit. - ! Merge chokepoint: run full
task check(ortask check:mergein the framework source repo) once before push/PR and again when CI merge gate runs. Pre-PR skill exit and review-cycle fix batches still require a green full gate. - ! Escape-rate safety (#1703 Tier-1): before tightening fast-lane defaults fleet-wide, consult
#1703measurement —task eval:health(Tier 0) and Tier-1 session telemetry (helped/crud-metrics.jsonlvia instrumented CRUD / workflow metrics). Do NOT invent a separate fast-lane escape-rate surface (#1704 LockedDecisions). - ~ In-engine incrementality (#1713): content-hash task cache and runner-delegated affected selection are sibling work — not required for this policy face.
- ⊗ Run full
task checkon every iteration commit when a cheaper proxy suffices — reserve the full gate for PR/merge (#1704). - ⊗ Skip the merge chokepoint because the iteration lane passed — the fast lane is convenience only.
Cost model (swarm-heavy path): moves from roughly O(commits × full-gate) toward O(merges × full-gate) + O(iterations × cheap-proxy) when workers iterate with affected/static gates and run full task check only at PR/merge.
Dual stop — multi-iteration implement and pre-PR loops (#2442)
Multi-iteration implement-fix and pre-PR polish loops MUST carry both a success stop and a failure/budget stop (main.md ## Dual Stop Rule (#2442)). Single-turn edits and one-shot probes are exempt.
Defaults for this skill (override only with an explicit operator envelope or xBRIEF field):
| Loop class | Success stop | Default failure stop |
|---|---|---|
| Implement / quality fix (tests, lint, typecheck, coverage, AC) | Affected/static gates green for the change; AC met | max 5 fix iterations or 3 consecutive identical outcomes (same failing command + same primary error class) with no material code/config change |
Pre-PR polish (deft-directive-pre-pr Read-Write-Lint-Diff) |
Full pass with zero further edits | max 3 polish passes or 2 consecutive no-diff / same-diff outcomes |
Full task check re-run after a red merge chokepoint |
task check green |
Counts toward the implement/quality fix envelope above (do not open a separate unbounded check-retry loop) |
On failure stop:
- ! Halt the loop. Surface an operator-visible halt report with: (1) iterations attempted and which stop fired (max-iter / no-progress / budget), (2) commands and primary failure fingerprints tried, (3) what is still red or missing, (4) the human decision needed (unblock dependency, rescope AC, waive with audit, abandon).
- ! Prefer a structured
BLOCKED:terminal (preamble §11 / #2843) when exiting a drive-to:merge-ready or parent-dispatched unit early because the envelope is exhausted. - ⊗ Continue "one more fix" after the envelope is exhausted.
- ⊗ Reset the counter by opening a new commit, rewording the same change, or swapping workers while the same failure class remains.
Budget-aware effort - bank the pass before deepening (#3266)
When a hard turn or cost budget is detectable (session:start effort_budget / env DEFT_MAX_TURNS / DEFT_MAX_BUDGET / host descriptor #1461), size effort to the stated acceptance bar first. This is the success-side analog of dual-stop (#2442): dual-stop stops thrash on failure; bank-the-pass stops budget exhaustion on over-deepening.
- ! At implement start, read the session effort-budget signal (
task session:startlines or JSONeffort_budget, or env). Whenposture=hard-capped, treat the run as budget-constrained. - ! Bank the pass first: satisfy stated acceptance criteria (xBRIEF items / issue AC / official checker) and produce the passing artifact before any self-imposed deeper verification suite that exceeds the stated bar.
- ! Only with remaining budget after the stated pass, extend verification depth. Never deepen past the point where a found defect could not also be fixed within budget (default reserve: enough turns/cost for one fix batch).
- ! Self-verification scope scales with remaining budget - prefer the official/stated checks under a tight cap.
- ! When deepening is skipped for budget, MUST say so in the run summary / handoff (
deepening_skipped=true+ reason) - fail-loud (#1006). UseformatDeepeningSkippedNotesemantics frompackages/core/src/session/effort-budget.ts. - ~ When no hard budget is detected (
posture=unbounded), normal dual-stop defaults still apply; bank-the-pass is optional discipline, not a license to skip stated AC. - ⊗ Exhaust the turn/cost budget on self-imposed gold-plating after the stated bar is already within reach (#3266).
- ⊗ Silently skip deepening without naming it, or silently gold-plate under a hard cap (#1006 / #3266).
- ⊗ Treat bank-the-pass as permission to ship without meeting stated AC - stated AC remains the success stop.
Core helper: packages/core/src/session/effort-budget.ts (detectHardEffortBudget, recommendVerificationDepth). Composes #2442, #1581, #3214, #1006.
Enforcement note: skill defaults are behavioral. Durable delivery/acceptance circuit-breaker: #3143 packages/core/src/delivery-attempt/ (evaluatePreDispatch, .deft/delivery-attempts/). Docs: docs/delivery-attempt.md. Route delivery/acceptance automatic retries through that gate; do not invent a parallel ledger in this skill.
AC-pass banking checkpoint - finalize on green (#3285)
Sharpens #3266: the first moment stated/official acceptance criteria pass is a banking checkpoint, not a license to keep spending the turn budget on self-imposed depth.
- ! When stated acceptance criteria first pass (
task verify:ac/ product-first done-gate #3284 / official checker), the next action is FINALIZE: checkpoint-commit the green state and record the bank (durable under.deft/cache/ac-pass-banks/; optional run-summary line whenDEFT_RUN_SUMMARY_PATHis set). - ! Deepening after the bank requires surplus budget. Self-imposed extra verification, refactors, or polish are permitted only when remaining budget meets
plan.policy.acPassBanking.surplusThreshold(default 0.2 = 20% of max turns/cost still remaining) and the absolute reserve from #3266. Env override:DEFT_AC_PASS_SURPLUS_THRESHOLD. - ! Deepening, when allowed, happens on top of the committed checkpoint so a failed experiment can revert to banked green.
- ! Post-bank discoveries are reported, not chased when surplus is insufficient: file a note/issue in the deliverable for out-of-scope defects unless they regress stated AC (then fix-regression). Finding beyond the bar is a win; thrashing a dying budget into a zero is the failure mode this rule closes.
- ! When surplus is insufficient, ship the banked state and fail-loud (
deepening_skipped=true+ surplus reason) viaevaluateAcPassBanking/formatDeepeningSkippedNotesemantics. - ~ When no hard budget is detected, dual-stop still applies; bank-on-first-AC-pass remains good discipline but is not a hard surplus gate.
- ⊗ Convert a banked official pass into a scored failure by chasing post-bank polish until the turn budget dies (#3285).
- ⊗ Start post-bank deepening without a finalize checkpoint when a hard budget is active (#3285).
- ⊗ Chase out-of-scope post-bank findings when surplus is below threshold (#3285).
Core helpers: packages/core/src/session/ac-pass-banking.ts (evaluateAcPassBanking, bankAcPass, decidePostBankFinding, simulateSurplusInsufficientRun); policy: packages/core/src/policy/ac-pass-banking.ts (plan.policy.acPassBanking). Composes #3266, #3284, #3282 (optional bank-event JSONL), #1006.
Step 3: Build Phase by Phase
For each phase:
- ! Scaffold — file structure, dependencies, config
- ! Test first — write tests before implementation (TDD)
- ! Implement — make tests pass, following deft coding standards
- ! Verify (iteration lane) — run affected/static gates per
#1704fast lane above; fix failures before checkpoint commits - ! Origin sync — when this phase materially changed an origin-linked scope xBRIEF (
plan.referencesincludesx-xbrief/github-issue), runtask issue:sync-from-xbrief -- <path>(or--dry-runto preview) so the linked GitHub issue receives a sync comment; if skipped, document why in the PR or session notes (#2540) - ! Checkpoint — tell user what's done, what's next
- ⊗ Move to next phase until current phase passes all checks
Step 4: Quality Gates
After EVERY phase (iteration lane — #1704):
vitest run --coverage <changed-paths> # or project test runner on touched modules
task coverage:hotspots # branch headroom before merge
task verify:forward-coverage # new-source coverage (#1310)Before PR / phase handoff (merge chokepoint):
task check # Full gate — format, lint, typecheck, tests, coverage, verify:*
task test:coverage # >=85% or PROJECT-DEFINITION.xbrief.json override- ! Phase checkpoint commits MAY use the iteration lane; phase is NOT done for PR handoff until full
task checkpasses at the merge chokepoint - ⊗ Skip quality gates or claim they passed without running
- ⊗ Treat iteration-lane green as merge-ready without full
task check - ! Multi-scope batch (#3012): when implementing an approved multi-scope pin/cohort, reserve full
task checkfor end-of-batch (or after last scope) unless the last full check failed — then re-run on the fix loop. Do not run full check after every intermediate scope. - ⊗ Re-run full install/session ceremony after offline seed when ritual is already complete (#3010) — use
session:readyfor recovery only.
Product-first done-gate (#3284) / literal AC (#3267)
At intake, capture the task statement's exact acceptance commands as executable AC (plan.acceptance.commands + #3267 literal_acceptance_commands). Empty is allowed only with none_stated: true (ladder: stated → derived → project_floor). Before declaring done, run them verbatim — same paths, same flags, same working directory. Self-chosen verification is supplementary, never a substitute. Extends #973. task check runs verify:ac first (fail-fast); hygiene is second and may become advisory under pressure. Rapid ceremony = AC-only.
- ! When reading the active scope xBRIEF / issue body at story start, capture stated shell acceptance commands into
plan.acceptance.commands(issue:ingest stamps this + the #3267 ledger automatically). Do not paraphrase. - ! Before claiming phase or story done (and before merge-chokepoint PR handoff), run:
task verify:ac -- <active-story-path> Exit 0 = pass or none stated with valid marker; exit 1 = a stated command failed; exit 2 = config. (verify:literal-ac is the #3267 mechanism alias.)
- ! Quote the literal invocations and their outputs in the completion note when commands were stated.
- ⊗ Substitute a self-chosen approximation (
pnpm testwhen the statement saidpnpm exec vitest run packages/core/src) for the stated command. - ⊗ Skip this gate because ceremony dial is rapid/minimal — rapid's positive content is exactly this check (#3284).
- ⊗ Leave
plan.acceptance.commandsempty withoutnone_stated: true— absence must be an explicit decision.
Product-oracle gate integrity (#3322 / #3156)
A red product verification may be resolved only by a product change or an independently re-derived oracle (both sides rebuilt from scratch, different method). In-place repair of the failing comparison then pass is not a pass — it is an unresolved discrepancy.
- ! When a product oracle is red, resolve it by changing the product or by independently re-deriving the oracle, and record
independent_rederivationon the run-summaryverificationevent. - ! Emit a run-summary verification event
{check_id, method_fingerprint, outcome}for each product-oracle attempt whenDEFT_RUN_SUMMARY_PATHis set.failthen a differentmethod_fingerprintthenpasson one check id is machine-flagged. - !
task verify:actreats comparison-method mutation as unresolved (exit non-zero) unless independent re-derivation is recorded. Lead the done report with any unresolved discrepancy (#1006). - ⊗ Self-adjudicate a red product oracle by editing the comparison (reference file, diff invocation, one-sided regenerate) and shipping the new pass as success.
Operator-log hygiene (lazy-load, #1940)
When the story touches operator-facing services (dashboards, multi-process
workers, WARN/ERROR operators triage):
- ~ SHOULD load
patterns/operator-log-hygiene.mdand apply the copy-paste
checklist indocs/operator-log-hygiene-checklist.mdto story AC or probe
locked decisions before claiming logging done - ⊗ MUST NOT treat this as Product Insights (#2603) or LLM-call telemetry
(#481) — those are different lanes - ⊗ MUST NOT assume core
deft checkenforces a log schema by default —
consumer-owned shape; optional pack stub underdocs/operator-log-hygiene-consumer-pack-stub.md
Discovery keywords: operator log, operator-facing logs, observability checklist
— also indexed in REFERENCES.md.
Goal-gate determinism (lazy-load, #852)
When authoring or tightening story acceptance criteria, quality gates, or skill
steps during build:
- ~ SHOULD load
patterns/goal-gate-determinism.md— goals, AC, gates, exit,
scope, stop, and preserve are rigid; pure execution path is flexible guidance - ⊗ MUST NOT treat "all process steps done" as verification — outcomes and
gates own "done" (see alsoverification/verification.mdand Fail Loud #1006)
Discovery keywords: goal-gate-determinism, rigid goals flexible path — also
indexed in REFERENCES.md.
Coding Standards (Summary)
Read full files when you need detail:
- ! TDD: write tests first — implementation incomplete without passing tests
- ! Coverage: ≥85% lines, functions, branches, statements
- ~ Files: stay small; line counts live in the file-size-thresholds policy module (review trigger, not a hard cap; #1488 / #3424)
- ~ Naming: hyphens for filenames unless language idiom dictates otherwise
- ! Contracts first: define interfaces/types before implementation
- ! Secrets: in
secrets/dir with.exampletemplates; ⊗ secrets in code - ! Commits: Conventional Commits format; ! use iteration fast lane before checkpoint commits; ! run full
task checkat PR/merge chokepoint only (#1704)
See deft/coding/coding.md and deft/coding/testing.md for full rules.
Pre-Commit File Review
! Before every commit, re-read ALL modified files and explicitly check for:
- ! Encoding errors -- em-dashes corrupted to replacement characters, BOM artifacts, mojibake from round-trip read/write
- ! Unintended duplication -- accidental double entries in CHANGELOG.md, scope xBRIEF files, or structured data files
- ! Structural issues -- malformed CHANGELOG entries, broken table rows, mismatched index entries, invalid JSON/YAML
- ! Semantic accuracy -- verify that counts, claims, and summaries in CHANGELOG entries and ROADMAP changelog lines match the actual data in the commit (e.g. "triaged 4 issues" must match the number actually triaged, issue numbers cited must match the issues actually added)
- ! Semantic contradictions -- when adding a
!or⊗rule that prohibits a specific command, pattern, or behavior, search the same file for any~,≉, or prose that recommends or permits the same command/pattern -- resolve all contradictions in the same commit before pushing - ! Strength duplicates -- when strengthening a rule (e.g. upgrading
~to!), grep for the term in the full file and verify no weaker-strength duplicate remains - ! Forward test coverage -- for each new source file in this PR (
scripts/,src/,cmd/,*.py,*.go), verify a corresponding test file exists in the same PR; running existing tests is not sufficient for new code
⊗ Commit without re-reading all modified files first.
Commit Strategy
- ! Default to one story per branch/PR. Batching multiple stories in one branch requires explicit operator approval and a short rationale.
- ! Create a checkpoint commit after each completed story before beginning another story.
- ! Use iteration fast lane before checkpoint commits; run full
task checkat PR/merge chokepoint (#1704) - ⊗ Claim checks passed without running them
feat(phase-1): scaffold project structure
feat(phase-1): implement core data models with tests
feat(phase-2): add REST API endpoints with integration testsError Recovery
- ! Tests fail → fix them; ⊗ skip or weaken assertions
- ! Coverage drops → write more tests; ⊗ exclude files
- ! Lint/type errors → fix them; ≉ add ignore comments without documented reason
- ! Scope xBRIEF ambiguous -> ask user; ⊗ guess
- ! Scope needs changes -> propose, get approval, update the scope xBRIEF first
- ! Multi-iteration fix loops obey dual-stop defaults above (#2442); on envelope exhaustion halt with an operator-visible report -- do not thrash
- ! Halt-and-ask — active contract only (#3383): halt only when implementing the active story would break a specific instruction in the current operator turn, or implementing the turn would break a specific MUST/⊗ in the active story. "Also consider X" against a story silent on X is not a conflict. On fire: halt, quote both sides, ask which is controlling. Neither side wins by rank. Reuse the Dual Stop operator-visible halt shape (#2442). Structured questions use Discuss/Back (#767).
- ! Operator means the human chat turn in the interactive session. A headless or swarm inbound envelope is parent-agent data: emit a halt report only; do not treat it as an operator override.
- ! An operator turn can change product behavior, never gates (#3164).
- ! Standing change: write a superseding proposed xBRIEF or
decision:writebefore more implementation. Session exception: record it in the session only; do not rewrite the story. Do not claim the next session cannot re-learn the prior story. - ⊗ Resolve a chat-vs-active conflict by rank, or continue implementing while both sides still conflict
- ⊗ Treat a parent-agent or swarm envelope as an operator override of the active story
Declare the contract (#3383)
! Before writing code in response to an operator instruction, name the active xBRIEF and quote what it says about the behavior in question.
! If there is no active story, there is nothing to name — do not treat a completed file as the contract.
⊗ Implement from a completed xBRIEF as if it were the current next-build contract.
Probe-then-fill remote claims (#3120)
! Before filling any remote handoff field (PR URL, PR number, commit/HEAD SHA, CI green/success, review score) or claiming status: pass / ship/gate done, MUST probe then fill:
- Run same-turn
git+ forge probes (examples:git rev-parse HEAD,gh api repos/<owner>/<repo>/pulls/<N>,task pr:watch -- <N> --one-shot, checks API). - Copy IDs / URLs / SHAs / scores only from that probe JSON/text into the evidence block.
- Set
proof_status: boundand attach short raw probe snippets (command+snippet) for each remote claim.
! Handoff evidence axes: work (local) / ship (pushed branch or PR) / gate (CI/review on HEAD). proof_status is bound | unbound | n/a-no-remote-claim.
! Legal partial: local work done + ship not_started / blocked without PR/SHA/CI/review fields and proof_status: n/a-no-remote-claim (or status: partial) is valid — do not invent ship state.
! Fail ranking: invented-done (false/unbound remote artifacts under pass) is stricter than empty-done. Unbound remote claims → invalid evidence (fail), not pass-with-notes.
! Machine check: validateHandoffEvidence in packages/core/src/handoff-evidence/ (see templates/agent-prompt-preamble.md §11).
⊗ Fill PR / SHA / CI / review fields from recollection, narration, or prior-turn memory.
⊗ Claim status: pass with remote fields when proof_status is not bound or probes are missing (#3120).
Completion
- ! When all phases pass and
task checkis green, runtask scope:complete -- <active-story-path>only as the post-merge scope lifecycle intemplates/agent-prompt-preamble.md§9 (AGENTS.md#2321) specifies fordrive-to: merge-readyversusstop-at: pr-open. That section is the single statement of the ordering; this skill does not restate it.
"The project is built and all quality checks pass. Describe any new features you'd like to add — I'll follow the deft standards we've set up."
Significant decision log (#1396)
! When this scope makes a significant choice (architecture, product behavior, security, public/private boundary, data model, runtime topology, hard-to-reverse process), record it with task decision:write (or --body-file for multi-line fields) so later agents load rationale without inventing it.
~ Prefer attaching with --scope <active-xbrief> when the decision is bound to this story; use standalone xbrief/decisions/ for cross-cutting / multi-scope process choices.
~ Before claiming a process/architecture path was 'already decided', run task decision:list -- --query <topic> (or --issue N).
⊗ Require a decision record for every trivial scope or routine fix.
⊗ Merge lessons (#1513) into decision records, or replace ADRs under docs/decisions/ADR-*.md.
Docs: docs/decision-log.md · xbrief/decisions/README.md.
Anti-Patterns
⊗ Skip tests or write them after implementation
⊗ Ignore
task checkfailures⊗ Implement things not in scope xBRIEF without asking
⊗ Read every deft file upfront
⊗ Move to next phase before current passes checks
⊗ Make commits without running iteration-lane validation; ⊗ skip full
task checkat PR/merge chokepoint (#1704)⊗ Proceed without USER.md -- always run the USER.md Gate first
⊗ Re-run
directive init, coldsession:start, migrate, or re-copy pin scopes after offline seed when ritual is already complete (#3010)⊗ Run full
task checkafter every intermediate scope of an approved multi-scope batch when the last merge-chokepoint check was green (#3012)⊗ Promote scopes one-by-one for a known multi-scope pin when
scope:promote --batchwould stage them in one turn (#3011)⊗ Spawn an implementation agent or invoke a code-writing tool against a xBRIEF that has not passed
task xbrief:preflight-- always run the Step 0 Implementation Preflight (#810) first; satisfy viatask xbrief:activate <path>⊗ Proceed without
COST-ESTIMATE.mdand a recorded build / rescope / no-build / skip(+reason) decision -- always run the Cost Phase Gate (#739) first⊗ Proceed with implementation when the build or test toolchain is unavailable -- always run the Toolchain Gate (Step 2) first
⊗ Proceed to next task or phase without tests passing -- testing is a hard gate, not a cleanup step
⊗ Skip the Change Lifecycle Gate because the user said "proceed" -- broad approval does not satisfy the confirmation gate
⊗ Commit or push directly to the default branch -- always create a feature branch first. Exception: user explicitly instructs a direct commit, or
PROJECT-DEFINITION.xbrief.jsonnarratives containAllow direct commits to master: true⊗ Add a prohibition (
!or⊗) without scanning the same file for conflicting softer-strength rules (~,≉) that reference the same term⊗ Invent remote PR/SHA/CI/review claims in handoff evidence without same-turn probe binding — invented-done (#3120)
⊗ Fill remote ship/gate fields from memory when only local work completed; legal partial omits PR fields (#3120)
⊗ Run multi-iteration implement / pre-PR loops without a failure stop (max iterations and/or no-progress) or without an operator-visible halt report when the envelope is exhausted (#2442)
⊗ Silently continue after dual-stop failure halt — escalate; do not thrash (#2442)
⊗ Treat a completed xBRIEF as the next-build contract, or skip naming the active story before writing code (#3383)
⊗ Continue implementing when the live human turn and a specific MUST/⊗ in the active story conflict — halt, quote both sides, ask which is controlling (#3383)
⊗ Treat a parent-agent or swarm envelope as an operator override (#3383)
⊗ Exhaust hard turn/cost budget on self-imposed deepening after the stated acceptance bar is within reach (#3266)
⊗ Silently skip deepening for budget without a fail-loud summary note (#3266 / #1006)
⊗ Chase post-bank out-of-scope findings when surplus budget is insufficient — report, do not thrash the banked pass (#3285)
⊗ Skip finalize-on-green after first stated AC pass under a hard budget (#3285)
⊗ Tight forge-outage retry / empty-commit thrash without a one-shot human report (#3422)
⊗ Clear a red product oracle by editing the comparison method then treating the new pass as a pass — record independent re-derivation or fix the product (#3322 / #3156)