@deftai/directive-content 0.61.2 → 0.62.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -22,7 +22,7 @@
22
22
  ],
23
23
  "path": "skills/deft-directive-build/SKILL.md",
24
24
  "version": "0.1",
25
- "body": "# Deft Directive Build\n\nImplements a project from its scope vBRIEFs following Deft Directive standards.\n\nLegend (from RFC2119): !=MUST, ~=SHOULD, ≉=SHOULD NOT, ⊗=MUST NOT, ?=MAY.\n\n## When to Use\n\n- After `deft-directive-setup` completes and generates `PROJECT-DEFINITION.vbrief.json`\n- User says \"build this\", \"implement the spec\", or \"start building\"\n- Resuming a partially-built project that has story vBRIEFs in `vbrief/active/`\n\n## Step 0 -- Implementation Preflight (#810)\n\n- ! Before starting any new implementation story or switching from one story to another, MUST run `git status --short --branch`.\n- ! 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.\n- ⊗ Begin a new story while unrelated dirty work is present without explicit operator approval.\n- ! Resolve exactly one target story vBRIEF 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.\n- ! Batching multiple stories in one branch/PR requires explicit operator approval and a short rationale recorded in the handoff.\n- ! **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 vBRIEF paths and allocation rationale ARE the consent token. Process each assigned story sequentially under the checkpoint-commit + `task scope:complete` discipline 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.\n- ! **Structured consent-token recognition (#1378)**: the canonical recognition path for the carve-out above is the structured `## Allocation context` section of the dispatch envelope (the frozen schema in `templates/agent-prompt-preamble.md`, Story A of #1378). When that section reports `dispatch_kind: swarm-cohort` with a non-null `allocation_plan_id` AND a non-null `batching_rationale`, the consent token is satisfied mechanically -- read `cohort_vbriefs` as the authoritative file boundary and process each entry sequentially under the checkpoint-commit + `task scope:complete` discipline below, without re-prompting the parent for batching approval mid-cohort. When the `## Allocation context` section 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.\n- ! **Within a cohort, between stories**: the working tree MUST be clean after each story's checkpoint commit + `task scope:complete`. If `git status --short` shows uncommitted state between stories (e.g. a missed `task scope:complete` move, 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.\n- ! If the target story is in `vbrief/proposed/`, run `task scope:promote -- <path>` first; if it is in `vbrief/pending/`, run `task scope:activate -- <path>`. After activation, update the path to the active-file location before preflight.\n- ! Before any code-writing tool call -- the first scaffold edit, the first `task` invocation that mutates files, or any `start_agent` dispatch that will implement scope -- MUST run `task vbrief:preflight -- <active-story-path>` (the structural intent gate; wraps `scripts/preflight_implementation.py` so the same invocation works whether deft is the project root or installed as a `deft/` subdirectory).\n\nThe gate exits 0 only when the candidate vBRIEF lives in `vbrief/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 vbrief:activate <path>`.\n\n- ! 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.\n- ! 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 companion `task vbrief:activate <path>` only when following the preflight redirect directly. Manual lifecycle moves bypass the activation contract -- use the task.\n- ⊗ 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).\n- ⊗ 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.\n\n## Platform Detection\n\n! Before resolving any config paths, detect the host OS from your environment context:\n\n| Platform | USER.md default path |\n|--------------------|-------------------------------------------------------------------|\n| Windows | `%APPDATA%\\deft\\USER.md` (e.g. `C:\\Users\\{user}\\AppData\\Roaming\\deft\\USER.md`) |\n| Unix (macOS/Linux) | `~/.config/deft/USER.md` |\n\n- ! If `$DEFT_USER_PATH` is set, it takes precedence on any platform\n\n## Pre-Cutover Detection Guard\n\n! 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.\n\n### Detection Criteria\n\nA project is **pre-cutover** if ANY of the following are true. This prose mirrors the executable helper in `scripts/_precutover.py`; when in doubt, the helper is canonical.\n\n1. `SPECIFICATION.md` exists and is neither a deprecation redirect nor a current generated spec export. A current generated spec export contains `<!-- Purpose: rendered specification -->` and `<!-- Source of truth: vbrief/specification.vbrief.json -->`, and `vbrief/specification.vbrief.json` plus all five lifecycle folders exist.\n2. `PROJECT.md` exists and contains neither the legacy `<!-- deft:deprecated-redirect -->` sentinel NOR the current `Purpose: deprecation redirect` canonical-banner marker (real content, not a deprecation redirect)\n3. `vbrief/specification.vbrief.json` exists but the lifecycle folders (`vbrief/proposed/`, `vbrief/pending/`, `vbrief/active/`, `vbrief/completed/`, `vbrief/cancelled/`) do NOT exist\n4. Strategy output shape violations (run `task verify-strategy-output` -- the canonical gate -- or the direct form `python .deft/core/scripts/validate_strategy_output.py --project-root <path>` after `deft` install):\n - Any scope vBRIEF under `vbrief/proposed/` (or other lifecycle dirs) lacks the required `YYYY-MM-DD-` date prefix in its filename (e.g. bare `scaffold.vbrief.json`).\n - `vbrief/PROJECT-DEFINITION.vbrief.json` is missing.\n - `vbrief/specification.vbrief.json` exists 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 and `SPECIFICATION.md` is rendered from `vbrief/specification.vbrief.json`.\n\n### Action on Detection\n\n! If pre-cutover or strategy-nonconformant state is detected, **stop immediately** and display an actionable message that cites the exact validator:\n\n> \"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 after `deft` package install) or `python .deft/core/scripts/validate_strategy_output.py --project-root .` . Then `task migrate:vbrief` / `task project:render` / strategy re-run as indicated.\"\n\n! Include specific details about what was detected (the validator output is authoritative):\n\n- Legacy specification.vbrief.json or missing lifecycle folders: \"Run `task migrate:vbrief` to create the lifecycle folder structure and remove legacy dual-writes\"\n- Non-date-prefixed vBRIEFs: \"Re-run the emitting strategy after the v0.20 migrations (#1166 s1+s2+...) or manually rename files to `YYYY-MM-DD-<slug>.vbrief.json` and `task scope:promote`\"\n- Missing `PROJECT-DEFINITION.vbrief.json`: \"Run `task project:render` to generate the project definition\"\n- `SPECIFICATION.md` / `PROJECT.md` without sentinel: the classic pre-cutover messages\n- Scope vBRIEF in wrong folder: \"Status is '{status}' but file is in {folder}/ -- run `task scope:activate <file>` to fix\"\n\n! After the validator reports clean, re-run this guard before continuing.\n\n⊗ Proceed with build when pre-cutover or strategy-nonconformant artifacts are detected -- always redirect to migration first (or run the validator) and surface the exact remediation.\n⊗ Silently ignore these artifacts or guess at fixes -- the validator (wired into `task check` and this guard) is the deterministic gate.\n\n## USER.md Gate\n\n! Before proceeding, verify USER.md exists at the platform-appropriate path\n(resolved via Platform Detection above, or `$DEFT_USER_PATH` if set).\n\n- ! If USER.md is not found: inform the user and redirect to `deft-directive-setup`\n Phase 1 before continuing -- do not proceed without user preferences\n- ! Once USER.md exists, continue with the Cost Phase Gate below\n\n## Cost Phase Gate (#739)\n\n! Before proceeding to File Reading, verify the project has gone through the\npre-build cost & budget transparency phase from `skills/deft-directive-cost/SKILL.md`.\nThis closes the adoption-blocker surfaced by issue #739 (refs #151 umbrella) where\nusers finished the spec flow and stopped at build because deft offered no cost\nsignal.\n\n### Detection\n\n- ! Check for `COST-ESTIMATE.md` in the project root.\n- ! Check that the file contains a recorded decision (the **Decision recorded**\n block populated with one of: `build`, `rescope`, `no-build`, `skip`).\n- ! For `skip`, `rescope`, or `no-build` decisions: the **Reason** field MUST be\n populated (one or two sentences in plain language). A skip with no reason\n recorded is treated the same as no decision.\n\n### Action\n\n- ! If `COST-ESTIMATE.md` is missing OR the **Decision recorded** block is\n unpopulated OR a `skip`/`rescope`/`no-build` decision has no reason recorded:\n stop immediately and redirect the user:\n\n > \"This project has not gone through the pre-build cost & budget transparency\n > phase. Run `skills/deft-directive-cost/SKILL.md` to produce a plain-English\n > `COST-ESTIMATE.md`, then re-run the build skill once the user has chosen\n > build / rescope / no-build / skip(+reason).\"\n\n- ! On a `build` or `skip` decision: continue with File Reading below.\n- ! On a `rescope` decision: stop and redirect the user back to spec edits\n (chain to `skills/deft-directive-refinement/SKILL.md` to pull spec scope\n back, or the interview), then re-run `skills/deft-directive-cost/SKILL.md`\n before re-attempting build.\n- ! On a `no-build` decision: stop and exit; do NOT proceed to File Reading.\n The user has explicitly stopped the project at the cost phase.\n- ⊗ Proceed to File Reading or any subsequent phase when `COST-ESTIMATE.md` is\n missing, when the decision is unpopulated, or when a skip / rescope / no-build\n decision has no reason recorded.\n- ⊗ Treat a `rescope` or `no-build` decision as if it were a `build` -- the\n build skill MUST honor the recorded decision.\n\n## File Reading\n\n- ! Read in order, lazy load:\n 1. `./vbrief/active/` -- scope vBRIEFs for work items to build (required)\n 2. `./vbrief/PROJECT-DEFINITION.vbrief.json` -- project identity, tech stack, architecture\n 3. `./.planning/codebase/MAP.md` -- generated codebase orientation projection, if present (advisory)\n 4. USER.md at the platform-appropriate path (see Platform Detection) -- Personal section is highest precedence; Defaults are fallback\n 5. `deft/main.md` -- framework guidelines\n 6. `deft/coding/coding.md` -- coding standards\n 7. `deft/coding/testing.md` -- testing requirements\n 8. `deft/coding/toolchain.md` -- toolchain validation rules\n 9. `deft/languages/{language}.md` -- only for languages this project uses\n- ~ If the MAP is absent or may be stale and the current scope needs broad codebase orientation, run `task codebase:map` and `task verify:codebase-map-fresh` when those commands resolve. Treat absence/staleness as advisory unless the task edits `plan.architecture.codeStructure`, a configured provider artifact, or the generated MAP itself.\n- ! Treat `plan.architecture.codeStructure` and selected provider artifacts as authoritative. The MAP is a generated projection.\n- ⊗ Read all language/interface/tool files upfront\n- ⊗ Hand-edit `.planning/codebase/MAP.md` or block unrelated implementation solely because the MAP is stale or absent\n\n## Rule Precedence\n\n```\nUSER.md Personal <- HIGHEST (name, custom rules -- always wins)\nPROJECT-DEFINITION.vbrief.json <- Project-specific (tech stack, architecture, config)\nUSER.md Defaults <- Fallback defaults (used when PROJECT-DEFINITION doesn't specify)\n{language}.md <- Language standards\ncoding.md <- General coding\nmain.md <- Framework defaults\nScope vBRIEFs <- LOWEST\n```\n\n- ! USER.md Personal section always wins over any other file\n- ! For project-scoped settings, PROJECT-DEFINITION.vbrief.json overrides USER.md Defaults\n\n## Change Lifecycle Gate\n\n! Before any implementation that touches 3+ files, verify that a `/deft:change <name>` proposal exists and has been confirmed by the user:\n\n- ! Check `history/changes/` for an active `proposal.vbrief.json` matching this work\n- ! If no proposal exists: propose `/deft:change <name>` and present the change name for explicit confirmation (e.g. \"Confirm? yes/no\")\n- ! The user must reply with an affirmative (`yes`, `confirmed`, `approve`) — a general 'proceed', 'do it', or 'go ahead' does NOT satisfy this gate\n- ? 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\n- ⊗ Skip this gate because the user has already said \"proceed\" or \"go ahead\"\n\n## Build Process\n\nAll vBRIEFs (including those read from `vbrief/active/` and any new vBRIEFs this skill emits) MUST use `\"vBRIEFInfo\": { \"version\": \"0.6\" }`. The validator rejects any other version (see [`../../conventions/references.md`](../../conventions/references.md)).\n\n### Step 1: Understand the Scope\n\n- ! Read story vBRIEFs from `vbrief/active/` and `PROJECT-DEFINITION.vbrief.json`\n- ! Identify phases, dependencies, starting point from scope vBRIEF acceptance criteria\n- ~ 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 trust `plan.architecture.codeStructure` / provider artifacts plus the working tree over generated prose.\n- ! 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\n- ⊗ Begin implementation against an averaged blend of two contradicting patterns -- \"average code that satisfies both rules is the worst code\" (#1005)\n- ! Present brief summary to user:\n\n> \"Here's what I see: {N} story vBRIEFs in active/. I'll start with {name}. Ready?\"\n\n### Step 2: Verify Toolchain\n\n- ! Before any implementation, verify all tools required by this project are installed and functional — see `deft/coding/toolchain.md` for full rules\n- ! At minimum: confirm task runner (`task --version`), language compiler/runtime, and platform SDK (if applicable) are available\n- ! If any required tool is missing, stop and report — do not proceed to Step 3\n- ⊗ Assume tools are available because the spec references them\n\n### Step 3: Build Phase by Phase\n\nFor each phase:\n\n1. ! **Scaffold** — file structure, dependencies, config\n2. ! **Test first** — write tests before implementation (TDD)\n3. ! **Implement** — make tests pass, following deft coding standards\n4. ! **Verify** — run `task check`, fix any issues\n5. ! **Checkpoint** — tell user what's done, what's next\n\n- ⊗ Move to next phase until current phase passes all checks\n\n### Step 4: Quality Gates\n\nAfter EVERY phase:\n\n```bash\ntask check # Format, lint, type check, test, coverage\ntask test:coverage # >=85% or PROJECT-DEFINITION.vbrief.json override\n```\n\n- ! Phase is NOT done until `task check` passes\n- ⊗ Skip quality gates or claim they passed without running\n\n## Coding Standards (Summary)\n\nRead full files when you need detail:\n\n- ! TDD: write tests first — implementation incomplete without passing tests\n- ! Coverage: ≥85% lines, functions, branches, statements\n- ~ Files: <300 lines ideal, <500 recommended, ! <1000 max\n- ~ Naming: hyphens for filenames unless language idiom dictates otherwise\n- ! Contracts first: define interfaces/types before implementation\n- ! Secrets: in `secrets/` dir with `.example` templates; ⊗ secrets in code\n- ! Commits: Conventional Commits format; ! run `task check` before every commit\n\nSee `deft/coding/coding.md` and `deft/coding/testing.md` for full rules.\n\n## Pre-Commit File Review\n\n! Before every commit, re-read ALL modified files and explicitly check for:\n\n1. ! **Encoding errors** -- em-dashes corrupted to replacement characters, BOM artifacts, mojibake from round-trip read/write\n2. ! **Unintended duplication** -- accidental double entries in CHANGELOG.md, scope vBRIEF files, or structured data files\n3. ! **Structural issues** -- malformed CHANGELOG entries, broken table rows, mismatched index entries, invalid JSON/YAML\n4. ! **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)\n5. ! **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\n6. ! **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\n7. ! **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\n\n⊗ Commit without re-reading all modified files first.\n\n## Commit Strategy\n\n- ! Default to one story per branch/PR. Batching multiple stories in one branch requires explicit operator approval and a short rationale.\n- ! Create a checkpoint commit after each completed story before beginning another story.\n- ! Run `task check` before committing\n- ⊗ Claim checks passed without running them\n\n```\nfeat(phase-1): scaffold project structure\nfeat(phase-1): implement core data models with tests\nfeat(phase-2): add REST API endpoints with integration tests\n```\n\n## Error Recovery\n\n- ! Tests fail → fix them; ⊗ skip or weaken assertions\n- ! Coverage drops → write more tests; ⊗ exclude files\n- ! Lint/type errors → fix them; ≉ add ignore comments without documented reason\n- ! Scope vBRIEF ambiguous -> ask user; ⊗ guess\n- ! Scope needs changes -> propose, get approval, update the scope vBRIEF first\n\n## Completion\n\n- ! When all phases pass and `task check` is green, complete each implemented story via `task scope:complete -- <active-story-path>` before final PR handoff.\n\n> \"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.\"\n\n## Anti-Patterns\n\n- ⊗ Skip tests or write them after implementation\n- ⊗ Ignore `task check` failures\n- ⊗ Implement things not in scope vBRIEF without asking\n- ⊗ Read every deft file upfront\n- ⊗ Move to next phase before current passes checks\n- ⊗ Make commits without running `task check`\n- ⊗ Proceed without USER.md -- always run the USER.md Gate first\n- ⊗ Spawn an implementation agent or invoke a code-writing tool against a vBRIEF that has not passed `task vbrief:preflight` (which wraps `scripts/preflight_implementation.py`) -- always run the Step 0 Implementation Preflight (#810) first; satisfy via `task vbrief:activate <path>`\n- ⊗ Proceed without `COST-ESTIMATE.md` and a recorded build / rescope / no-build / skip(+reason) decision -- always run the Cost Phase Gate (#739) first\n- ⊗ Proceed with implementation when the build or test toolchain is unavailable -- always run the Toolchain Gate (Step 2) first\n- ⊗ Proceed to next task or phase without tests passing -- testing is a hard gate, not a cleanup step\n- ⊗ Skip the Change Lifecycle Gate because the user said \"proceed\" -- broad approval does not satisfy the confirmation gate\n- ⊗ Commit or push directly to the default branch -- always create a feature branch first. Exception: user explicitly instructs a direct commit, or `PROJECT-DEFINITION.vbrief.json` narratives contain `Allow direct commits to master: true`\n- ⊗ Add a prohibition (`!` or `⊗`) without scanning the same file for conflicting softer-strength rules (`~`, `≉`) that reference the same term\n",
25
+ "body": "# Deft Directive Build\n\nImplements a project from its scope vBRIEFs following Deft Directive standards.\n\nLegend (from RFC2119): !=MUST, ~=SHOULD, ≉=SHOULD NOT, ⊗=MUST NOT, ?=MAY.\n\n## When to Use\n\n- After `deft-directive-setup` completes and generates `PROJECT-DEFINITION.vbrief.json`\n- User says \"build this\", \"implement the spec\", or \"start building\"\n- Resuming a partially-built project that has story vBRIEFs in `vbrief/active/`\n\n## Step 0 -- Implementation Preflight (#810)\n\n- ! Before starting any new implementation story or switching from one story to another, MUST run `git status --short --branch`.\n- ! 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.\n- ⊗ Begin a new story while unrelated dirty work is present without explicit operator approval.\n- ! Resolve exactly one target story vBRIEF 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.\n- ! Batching multiple stories in one branch/PR requires explicit operator approval and a short rationale recorded in the handoff.\n- ! **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 vBRIEF paths and allocation rationale ARE the consent token. Process each assigned story sequentially under the checkpoint-commit + `task scope:complete` discipline 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.\n- ! **Structured consent-token recognition (#1378)**: the canonical recognition path for the carve-out above is the structured `## Allocation context` section of the dispatch envelope (the frozen schema in `templates/agent-prompt-preamble.md`, Story A of #1378). When that section reports `dispatch_kind: swarm-cohort` with a non-null `allocation_plan_id` AND a non-null `batching_rationale`, the consent token is satisfied mechanically -- read `cohort_vbriefs` as the authoritative file boundary and process each entry sequentially under the checkpoint-commit + `task scope:complete` discipline below, without re-prompting the parent for batching approval mid-cohort. When the `## Allocation context` section 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.\n- ! **Within a cohort, between stories**: the working tree MUST be clean after each story's checkpoint commit + `task scope:complete`. If `git status --short` shows uncommitted state between stories (e.g. a missed `task scope:complete` move, 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.\n- ! If the target story is in `vbrief/proposed/`, run `task scope:promote -- <path>` first; if it is in `vbrief/pending/`, run `task scope:activate -- <path>`. After activation, update the path to the active-file location before preflight.\n- ! Before any code-writing tool call -- the first scaffold edit, the first `task` invocation that mutates files, or any `start_agent` dispatch that will implement scope -- MUST run `task vbrief:preflight -- <active-story-path>` (the structural intent gate; wraps `scripts/preflight_implementation.py` so the same invocation works whether deft is the project root or installed as a `deft/` subdirectory).\n\nThe gate exits 0 only when the candidate vBRIEF lives in `vbrief/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 vbrief:activate <path>`.\n\n- ! 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.\n- ! 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 companion `task vbrief:activate <path>` only when following the preflight redirect directly. Manual lifecycle moves bypass the activation contract -- use the task.\n- ⊗ 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).\n- ⊗ 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.\n\n## Platform Detection\n\n! Before resolving any config paths, detect the host OS from your environment context:\n\n| Platform | USER.md default path |\n|--------------------|-------------------------------------------------------------------|\n| Windows | `%APPDATA%\\deft\\USER.md` (e.g. `C:\\Users\\{user}\\AppData\\Roaming\\deft\\USER.md`) |\n| Unix (macOS/Linux) | `~/.config/deft/USER.md` |\n\n- ! If `$DEFT_USER_PATH` is set, it takes precedence on any platform\n\n## Pre-Cutover Detection Guard\n\n! 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.\n\n### Detection Criteria\n\nA project is **pre-cutover** if ANY of the following are true. This prose mirrors the executable helper in `scripts/_precutover.py`; when in doubt, the helper is canonical.\n\n1. `SPECIFICATION.md` exists and is neither a deprecation redirect nor a current generated spec export. A current generated spec export contains `<!-- Purpose: rendered specification -->` and `<!-- Source of truth: vbrief/specification.vbrief.json -->`, and `vbrief/specification.vbrief.json` plus all five lifecycle folders exist.\n2. `PROJECT.md` exists and contains neither the legacy `<!-- deft:deprecated-redirect -->` sentinel NOR the current `Purpose: deprecation redirect` canonical-banner marker (real content, not a deprecation redirect)\n3. `vbrief/specification.vbrief.json` exists but the lifecycle folders (`vbrief/proposed/`, `vbrief/pending/`, `vbrief/active/`, `vbrief/completed/`, `vbrief/cancelled/`) do NOT exist\n4. Strategy output shape violations (run `task verify-strategy-output` -- the canonical gate -- or the direct form `python .deft/core/scripts/validate_strategy_output.py --project-root <path>` after `deft` install):\n - Any scope vBRIEF under `vbrief/proposed/` (or other lifecycle dirs) lacks the required `YYYY-MM-DD-` date prefix in its filename (e.g. bare `scaffold.vbrief.json`).\n - `vbrief/PROJECT-DEFINITION.vbrief.json` is missing.\n - `vbrief/specification.vbrief.json` exists 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 and `SPECIFICATION.md` is rendered from `vbrief/specification.vbrief.json`.\n\n### Action on Detection\n\n! If pre-cutover or strategy-nonconformant state is detected, **stop immediately** and display an actionable message that cites the exact validator:\n\n> \"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 after `deft` package install) or `python .deft/core/scripts/validate_strategy_output.py --project-root .`. For document-model migration, follow UPGRADING.md § Frozen pre-v0.20 document-model migration (#2068): pin v0.59.0, then run `task migrate:vbrief` from that payload. Otherwise `task project:render` / strategy re-run as indicated.\"\n\n! Include specific details about what was detected (the validator output is authoritative):\n\n- Legacy specification.vbrief.json or missing lifecycle folders: \"Follow the frozen v0.59.0 migrator path (#2068) or run `task migrate:preflight` for current-release guidance\"\n- Non-date-prefixed vBRIEFs: \"Re-run the emitting strategy after the v0.20 migrations (#1166 s1+s2+...) or manually rename files to `YYYY-MM-DD-<slug>.vbrief.json` and `task scope:promote`\"\n- Missing `PROJECT-DEFINITION.vbrief.json`: \"Run `task project:render` to generate the project definition\"\n- `SPECIFICATION.md` / `PROJECT.md` without sentinel: the classic pre-cutover messages\n- Scope vBRIEF in wrong folder: \"Status is '{status}' but file is in {folder}/ -- run `task scope:activate <file>` to fix\"\n\n! After the validator reports clean, re-run this guard before continuing.\n\n⊗ 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.\n⊗ Silently ignore these artifacts or guess at fixes -- the validator (wired into `task check` and this guard) is the deterministic gate.\n\n## USER.md Gate\n\n! Before proceeding, verify USER.md exists at the platform-appropriate path\n(resolved via Platform Detection above, or `$DEFT_USER_PATH` if set).\n\n- ! If USER.md is not found: inform the user and redirect to `deft-directive-setup`\n Phase 1 before continuing -- do not proceed without user preferences\n- ! Once USER.md exists, continue with the Cost Phase Gate below\n\n## Cost Phase Gate (#739)\n\n! Before proceeding to File Reading, verify the project has gone through the\npre-build cost & budget transparency phase from `skills/deft-directive-cost/SKILL.md`.\nThis closes the adoption-blocker surfaced by issue #739 (refs #151 umbrella) where\nusers finished the spec flow and stopped at build because deft offered no cost\nsignal.\n\n### Detection\n\n- ! Check for `COST-ESTIMATE.md` in the project root.\n- ! Check that the file contains a recorded decision (the **Decision recorded**\n block populated with one of: `build`, `rescope`, `no-build`, `skip`).\n- ! For `skip`, `rescope`, or `no-build` decisions: the **Reason** field MUST be\n populated (one or two sentences in plain language). A skip with no reason\n recorded is treated the same as no decision.\n\n### Action\n\n- ! If `COST-ESTIMATE.md` is missing OR the **Decision recorded** block is\n unpopulated OR a `skip`/`rescope`/`no-build` decision has no reason recorded:\n stop immediately and redirect the user:\n\n > \"This project has not gone through the pre-build cost & budget transparency\n > phase. Run `skills/deft-directive-cost/SKILL.md` to produce a plain-English\n > `COST-ESTIMATE.md`, then re-run the build skill once the user has chosen\n > build / rescope / no-build / skip(+reason).\"\n\n- ! On a `build` or `skip` decision: continue with File Reading below.\n- ! On a `rescope` decision: stop and redirect the user back to spec edits\n (chain to `skills/deft-directive-refinement/SKILL.md` to pull spec scope\n back, or the interview), then re-run `skills/deft-directive-cost/SKILL.md`\n before re-attempting build.\n- ! On a `no-build` decision: stop and exit; do NOT proceed to File Reading.\n The user has explicitly stopped the project at the cost phase.\n- ⊗ Proceed to File Reading or any subsequent phase when `COST-ESTIMATE.md` is\n missing, when the decision is unpopulated, or when a skip / rescope / no-build\n decision has no reason recorded.\n- ⊗ Treat a `rescope` or `no-build` decision as if it were a `build` -- the\n build skill MUST honor the recorded decision.\n\n## File Reading\n\n- ! Read in order, lazy load:\n 1. `./vbrief/active/` -- scope vBRIEFs for work items to build (required)\n 2. `./vbrief/PROJECT-DEFINITION.vbrief.json` -- project identity, tech stack, architecture\n 3. `./.planning/codebase/MAP.md` -- generated codebase orientation projection, if present (advisory)\n 4. USER.md at the platform-appropriate path (see Platform Detection) -- Personal section is highest precedence; Defaults are fallback\n 5. `deft/main.md` -- framework guidelines\n 6. `deft/coding/coding.md` -- coding standards\n 7. `deft/coding/testing.md` -- testing requirements\n 8. `deft/coding/toolchain.md` -- toolchain validation rules\n 9. `deft/languages/{language}.md` -- only for languages this project uses\n- ~ If the MAP is absent or may be stale and the current scope needs broad codebase orientation, run `task codebase:map` and `task verify:codebase-map-fresh` when those commands resolve. Treat absence/staleness as advisory unless the task edits `plan.architecture.codeStructure`, a configured provider artifact, or the generated MAP itself.\n- ! Treat `plan.architecture.codeStructure` and selected provider artifacts as authoritative. The MAP is a generated projection.\n- ⊗ Read all language/interface/tool files upfront\n- ⊗ Hand-edit `.planning/codebase/MAP.md` or block unrelated implementation solely because the MAP is stale or absent\n\n## Rule Precedence\n\n```\nUSER.md Personal <- HIGHEST (name, custom rules -- always wins)\nPROJECT-DEFINITION.vbrief.json <- Project-specific (tech stack, architecture, config)\nUSER.md Defaults <- Fallback defaults (used when PROJECT-DEFINITION doesn't specify)\n{language}.md <- Language standards\ncoding.md <- General coding\nmain.md <- Framework defaults\nScope vBRIEFs <- LOWEST\n```\n\n- ! USER.md Personal section always wins over any other file\n- ! For project-scoped settings, PROJECT-DEFINITION.vbrief.json overrides USER.md Defaults\n\n## Change Lifecycle Gate\n\n! Before any implementation that touches 3+ files, verify that a `/deft:change <name>` proposal exists and has been confirmed by the user:\n\n- ! Check `history/changes/` for an active `proposal.vbrief.json` matching this work\n- ! If no proposal exists: propose `/deft:change <name>` and present the change name for explicit confirmation (e.g. \"Confirm? yes/no\")\n- ! The user must reply with an affirmative (`yes`, `confirmed`, `approve`) — a general 'proceed', 'do it', or 'go ahead' does NOT satisfy this gate\n- ? 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\n- ⊗ Skip this gate because the user has already said \"proceed\" or \"go ahead\"\n\n## Build Process\n\nAll vBRIEFs (including those read from `vbrief/active/` and any new vBRIEFs this skill emits) MUST use `\"vBRIEFInfo\": { \"version\": \"0.6\" }`. The validator rejects any other version (see [`../../conventions/references.md`](../../conventions/references.md)).\n\n### Step 1: Understand the Scope\n\n- ! Read story vBRIEFs from `vbrief/active/` and `PROJECT-DEFINITION.vbrief.json`\n- ! Identify phases, dependencies, starting point from scope vBRIEF acceptance criteria\n- ~ 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 trust `plan.architecture.codeStructure` / provider artifacts plus the working tree over generated prose.\n- ! 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\n- ⊗ Begin implementation against an averaged blend of two contradicting patterns -- \"average code that satisfies both rules is the worst code\" (#1005)\n- ! Present brief summary to user:\n\n> \"Here's what I see: {N} story vBRIEFs in active/. I'll start with {name}. Ready?\"\n\n### Step 2: Verify Toolchain\n\n- ! Before any implementation, verify all tools required by this project are installed and functional — see `deft/coding/toolchain.md` for full rules\n- ! At minimum: confirm task runner (`task --version`), language compiler/runtime, and platform SDK (if applicable) are available\n- ! If any required tool is missing, stop and report — do not proceed to Step 3\n- ⊗ Assume tools are available because the spec references them\n\n### Step 3: Build Phase by Phase\n\nFor each phase:\n\n1. ! **Scaffold** — file structure, dependencies, config\n2. ! **Test first** — write tests before implementation (TDD)\n3. ! **Implement** — make tests pass, following deft coding standards\n4. ! **Verify** — run `task check`, fix any issues\n5. ! **Checkpoint** — tell user what's done, what's next\n\n- ⊗ Move to next phase until current phase passes all checks\n\n### Step 4: Quality Gates\n\nAfter EVERY phase:\n\n```bash\ntask check # Format, lint, type check, test, coverage\ntask test:coverage # >=85% or PROJECT-DEFINITION.vbrief.json override\n```\n\n- ! Phase is NOT done until `task check` passes\n- ⊗ Skip quality gates or claim they passed without running\n\n## Coding Standards (Summary)\n\nRead full files when you need detail:\n\n- ! TDD: write tests first — implementation incomplete without passing tests\n- ! Coverage: ≥85% lines, functions, branches, statements\n- ~ Files: <300 lines ideal, <500 recommended, ! <1000 max\n- ~ Naming: hyphens for filenames unless language idiom dictates otherwise\n- ! Contracts first: define interfaces/types before implementation\n- ! Secrets: in `secrets/` dir with `.example` templates; ⊗ secrets in code\n- ! Commits: Conventional Commits format; ! run `task check` before every commit\n\nSee `deft/coding/coding.md` and `deft/coding/testing.md` for full rules.\n\n## Pre-Commit File Review\n\n! Before every commit, re-read ALL modified files and explicitly check for:\n\n1. ! **Encoding errors** -- em-dashes corrupted to replacement characters, BOM artifacts, mojibake from round-trip read/write\n2. ! **Unintended duplication** -- accidental double entries in CHANGELOG.md, scope vBRIEF files, or structured data files\n3. ! **Structural issues** -- malformed CHANGELOG entries, broken table rows, mismatched index entries, invalid JSON/YAML\n4. ! **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)\n5. ! **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\n6. ! **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\n7. ! **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\n\n⊗ Commit without re-reading all modified files first.\n\n## Commit Strategy\n\n- ! Default to one story per branch/PR. Batching multiple stories in one branch requires explicit operator approval and a short rationale.\n- ! Create a checkpoint commit after each completed story before beginning another story.\n- ! Run `task check` before committing\n- ⊗ Claim checks passed without running them\n\n```\nfeat(phase-1): scaffold project structure\nfeat(phase-1): implement core data models with tests\nfeat(phase-2): add REST API endpoints with integration tests\n```\n\n## Error Recovery\n\n- ! Tests fail → fix them; ⊗ skip or weaken assertions\n- ! Coverage drops → write more tests; ⊗ exclude files\n- ! Lint/type errors → fix them; ≉ add ignore comments without documented reason\n- ! Scope vBRIEF ambiguous -> ask user; ⊗ guess\n- ! Scope needs changes -> propose, get approval, update the scope vBRIEF first\n\n## Completion\n\n- ! When all phases pass and `task check` is green, complete each implemented story via `task scope:complete -- <active-story-path>` before final PR handoff.\n\n> \"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.\"\n\n## Anti-Patterns\n\n- ⊗ Skip tests or write them after implementation\n- ⊗ Ignore `task check` failures\n- ⊗ Implement things not in scope vBRIEF without asking\n- ⊗ Read every deft file upfront\n- ⊗ Move to next phase before current passes checks\n- ⊗ Make commits without running `task check`\n- ⊗ Proceed without USER.md -- always run the USER.md Gate first\n- ⊗ Spawn an implementation agent or invoke a code-writing tool against a vBRIEF that has not passed `task vbrief:preflight` (which wraps `scripts/preflight_implementation.py`) -- always run the Step 0 Implementation Preflight (#810) first; satisfy via `task vbrief:activate <path>`\n- ⊗ Proceed without `COST-ESTIMATE.md` and a recorded build / rescope / no-build / skip(+reason) decision -- always run the Cost Phase Gate (#739) first\n- ⊗ Proceed with implementation when the build or test toolchain is unavailable -- always run the Toolchain Gate (Step 2) first\n- ⊗ Proceed to next task or phase without tests passing -- testing is a hard gate, not a cleanup step\n- ⊗ Skip the Change Lifecycle Gate because the user said \"proceed\" -- broad approval does not satisfy the confirmation gate\n- ⊗ Commit or push directly to the default branch -- always create a feature branch first. Exception: user explicitly instructs a direct commit, or `PROJECT-DEFINITION.vbrief.json` narratives contain `Allow direct commits to master: true`\n- ⊗ Add a prohibition (`!` or `⊗`) without scanning the same file for conflicting softer-strength rules (`~`, `≉`) that reference the same term\n",
26
26
  "frontmatter_extra": null
27
27
  },
28
28
  {
@@ -163,7 +163,7 @@
163
163
  ],
164
164
  "path": "skills/deft-directive-refinement/SKILL.md",
165
165
  "version": "0.1",
166
- "body": "# Deft Directive Refinement\n\nConversational refinement session -- ingest, evaluate, reconcile, and prioritize scope vBRIEFs with the user.\n\nLegend (from RFC2119): !=MUST, ~=SHOULD, ≉=SHOULD NOT, ⊗=MUST NOT, ?=MAY.\n\n**Upstream pass**: refinement begins with a triage pass -- see [`../deft-directive-triage/SKILL.md`](../deft-directive-triage/SKILL.md) (D6 / #1130) for the canonical cache-hygiene + \"what's next?\" queue playbook before continuing into the refinement flow below.\n\n**See also**: [`../../contracts/deterministic-questions.md`](../../contracts/deterministic-questions.md) (canonical numbered-menu rule used by every Phase 0 / Phase 2-5 gate below) | `task cache:fetch-all` / `task cache:get` (Tier 1 unified content cache, #883 Story 2) | `task triage:bootstrap` / `task triage:accept` / `task triage:reject` / `task triage:defer` / `task triage:needs-ac` / `task triage:mark-duplicate` / `task triage:bulk-*` / `task triage:refresh-active` (Phase 0 action surface, #845 + #883 Story 3 rebind).\n\n## Platform Requirements\n\n! This skill requires **GitHub** as the SCM platform and the **GitHub CLI (`gh`)** to be installed and authenticated. Issue ingestion, origin freshness checks, and completion lifecycle all depend on `gh`.\n\n## Deterministic Questions Contract\n\n! Every numbered-menu prompt rendered in this skill (Phase 0 Triage action menu, Phase 2 Evaluate per-item accept/reject, Phase 3 Reconcile flagged-item walk, Phase 4 Promote/Demote lifecycle gates, Phase 5 Prioritize reorder gates) MUST follow [`../../contracts/deterministic-questions.md`](../../contracts/deterministic-questions.md): render the canonical numbered menu in chat unless the host UI visibly preserves numeric option labels and returns numeric selections or exact displayed option text. The final two numbered options MUST be `Discuss` and `Back`, in that order. The Discuss-pause semantic is documented verbatim there -- on `Discuss` selection the agent MUST halt the in-progress sequence immediately, prompt `What would you like to discuss?`, and resume only on an explicit user signal. Implicit resumption is forbidden, and fallback chat replies MUST map only to the displayed number or exact displayed option text.\n\n## When to Use\n\n- User says \"refinement\", \"reprioritize\", \"refine\", \"roadmap refresh\", or \"refresh roadmap\" (legacy v0.19 terms -- deft-directive-refinement is the current skill name)\n- User says \"triage\", \"action menu\", \"work the cache\", or \"pre-ingest\" -- first-class Phase 0 direct triggers introduced under #845; they route to Phase 0 (Triage), not the general refinement entry\n- New issues have accumulated since the last refinement session\n- Periodic maintenance pass (e.g. weekly or after a batch of user feedback)\n- User wants to review and organize the backlog\n\n! **Entry point (#1141, supersedes #845 / #883 action-menu).** Phase 0 -- Triage-first consultation is the canonical entry point for any refinement session. Phase 0 consults `task triage:summary` (D2 / #1122) and `task triage:queue --state=accept` (D11 / #1128) and pulls the `[RESUME]`-tagged slice (D3 / #1123) FIRST. Refinement does NOT itself triage cached candidates -- that work belongs to [`../deft-directive-triage/SKILL.md`](../deft-directive-triage/SKILL.md) (D6 / #1130). Phase 0 ! MUST chain into Phase 1 -- Ingest on completion (or surface the empty-cache fallback prompt when the cache has not yet been bootstrapped -- see Phase 0a below). Phase 1+ semantics are unchanged.\n\n## Prerequisites\n\n- ! `vbrief/` directory exists with lifecycle folders (`proposed/`, `pending/`, `active/`, `completed/`, `cancelled/`)\n- ! GitHub CLI (`gh`) is authenticated and can access the repo\n- ~ `PROJECT-DEFINITION.vbrief.json` exists (run `task project:render` if missing)\n\n## Session Model\n\nRefinement is a **conversational loop**, not a batch job. The user directs the flow:\n\n- \"Triage\" / \"action menu\" / \"work the cache\" / \"pre-ingest\" -> Phase 0 (Triage-first consultation, #1141) -- refinement consults the cache; the canonical decision-making playbook is `../deft-directive-triage/SKILL.md` (D6 / #1130)\n- \"Pull in issues\" / \"ingest\" -> Phase 0 ALWAYS runs first to consult `task triage:summary` + `task triage:queue --state=accept`; Phase 1 follows on the cohort Phase 0b produces (#1141)\n- \"Show proposed\" / \"evaluate\" -> Phase 2 (Evaluate)\n- \"Check origins\" / \"reconcile\" -> Phase 3 (Reconcile)\n- \"Accept these\" / \"reject that\" / \"promote\" / \"demote\" -> Phase 4 (Promote/Demote)\n- \"Reprioritize\" / \"reorder pending\" -> Phase 5 (Prioritize)\n- \"Close out\" / \"scope is done\" / \"completion\" -> Phase 6 (Completion Lifecycle)\n- \"Done\" / \"exit\" -> Exit\n\nThe agent may suggest the next phase, but the user decides. Phases can be entered in any order and repeated.\n\n## Branch Setup (Preflight)\n\n! Before making any changes, ensure you are working on a feature branch. This preflight runs before Phase 0 and again before Phase 1 if Phase 0 is auto-skipped.\n\n1. ! Check if the working tree has uncommitted changes that would conflict -- stop and ask the user to resolve them first\n2. ! Create or switch to a refinement branch (e.g. `refinement/YYYY-MM-DD`) if not already on one\n3. ! Confirm the branch and working directory to the user before proceeding\n\n## Phase 0 -- Triage-first consultation (cache-first, #1141)\n\n! Phase 0 is a thin consumer of the canonical triage cache: refinement consults `task triage:summary` (D2 / #1122) and `task triage:queue` (D11 / #1128) BEFORE walking any `vbrief/` lifecycle folder. The dedicated triage playbook lives at [`../deft-directive-triage/SKILL.md`](../deft-directive-triage/SKILL.md) (D6 / #1130) -- refinement does NOT itself triage cached candidates; it consumes the queue's `accept` and `[RESUME]` slices and turns them into scope vBRIEFs.\n\n! Phase 0 runs three sub-phases in canonical order: **Phase 0a -- Triage gate** -> **Phase 0b -- Cache-first ingestion** -> **Phase 0c -- Resume conditions**. Each sub-phase MUST run before the next, and Phase 0 MUST chain into Phase 1 -- Ingest on completion. Numbered prompts in Phase 0 ! MUST follow [`../../contracts/deterministic-questions.md`](../../contracts/deterministic-questions.md) (`Discuss` / `Back` as the final two numbered options; Discuss-pause semantic applies verbatim).\n\n**See also (#883 Story 2):** the unified cache (`task cache:fetch-all --source=github-issue --repo OWNER/NAME`) is the sole content-mirroring surface in v0.26.0+. Tier 1 reads MUST go through `task cache:get -- github-issue OWNER/NAME/<N>`. The legacy \"Three-Tier Inventory Model\" + action-menu walk that lived here pre-#1141 has moved out of refinement and into `../deft-directive-triage/SKILL.md` (D6 / #1130); refinement now consumes the post-decision queue rather than producing decisions.\n\n### Phase 0a -- Triage gate (`task triage:summary`)\n\n1. ! Invoke `task triage:summary` (D2 / #1122) and capture the one-liner.\n2. ! **Empty-cache backward-compat fallback.** If the one-liner is the documented empty-cache prompt (`[triage] cache empty -- run task triage:bootstrap`), the agent ! MUST emit the verbatim recovery message to stderr BEFORE any folder scan:\n\n ```\n triage cache empty -- run `task triage:welcome` (N3 / #1143) to onboard, or `task triage:bootstrap` to seed the cache directly; refinement Phase 0 cannot consult the queue against an empty cache. Falling back to a legacy `vbrief/proposed/` folder scan only if you opt in.\n ```\n\n Then prompt the user `Fall back to legacy folder-scan against vbrief/proposed/ for this session? [y/N]` (default `N`). On `N`, exit refinement with the canonical `deft-directive-refinement complete -- exiting skill.` confirmation and the chaining instruction `Run task triage:welcome (N3 / #1143) to onboard, then re-enter refinement.`. On `y`, chain into Phase 1 against `vbrief/proposed/` as the legacy fallback. ! MUST NOT silently proceed without surfacing the breadcrumb to `task triage:welcome` -- a fresh post-upgrade install needs that pointer to find the canonical onboarding ritual.\n\n3. ! **Outstanding-work gate.** If the cache is populated AND any of `untriaged`, `stale-defer (resume condition met)`, or `in-flight` is non-zero, surface the one-liner verbatim to the user with the canonical recommendation:\n\n ```\n triage cache has outstanding work -- recommend running `skills/deft-directive-triage/SKILL.md` (D6 / #1130) first. Proceed to refinement anyway? [y/N]\n ```\n\n ~ Default is `N`: deferring to the triage skill is the documented happy path because refinement consumes `accept`-decisioned candidates and an untriaged backlog means there are fewer `accept` rows than there could be. On `N`, exit with the canonical confirmation phrasing and the chaining instruction `Run skills/deft-directive-triage/SKILL.md to clear the backlog, then re-enter refinement.`. On `y`, proceed to Phase 0b.\n\n4. ? When all counts are zero (cache populated, no outstanding work), proceed to Phase 0b without prompting.\n\n⊗ Skip Phase 0a -- refinement on top of an untriaged cache wastes the operator's time on items the triage skill would have rejected, deferred, or marked needs-AC.\n⊗ Bypass the empty-cache fallback prompt -- a silent proceed against an empty cache surfaces a misleading \"no candidates\" state and hides the upgrade-onboarding path from the operator.\n\n### Phase 0b -- Cache-first ingestion (`task triage:queue --state=accept`)\n\n1. ! Pull the ingestion candidate list via `task triage:queue --state=accept` (D11 / #1128). Each row is a cached issue whose latest audit-log decision is `accept` -- the canonical \"ready to become a scope vBRIEF\" cohort. ! MUST NOT enumerate `vbrief/proposed/` independently of the queue; the folder participates only via the join described in step 2.\n2. ! Join the queue against `vbrief/proposed/` (and the rest of the lifecycle folders) by `references[].uri`: queue rows whose issue is already represented by an existing vBRIEF surface as \"already tracked\"; queue rows with no matching vBRIEF are \"new accept candidates\". Items already in `vbrief/proposed/` continue to participate -- they are joined against the cache rather than enumerated separately.\n3. ~ When the join surfaces zero new candidates (every `accept` row already has a vBRIEF), Phase 0b is a clean no-op; chain straight into Phase 0c.\n4. ! For each new candidate, fall through to Phase 1 -- Ingest, which delegates the actual scope-vBRIEF write to `task issue:ingest`. The intended single-verb form is `task scope:promote --from-issue=<N>` (#1136 / D18); until D18 lands, refinement chains the existing `task issue:ingest` + `task scope:promote` pair.\n\n <!-- TODO(#1136 / D18): when `task scope:promote --from-issue=<N>` ships, refinement Phase 0b consumes it directly instead of chaining `task issue:ingest` + `task scope:promote`. -->\n\n⊗ Walk `vbrief/proposed/` directly as the primary ingestion surface -- the cache is the authoritative \"what is ready to refine?\" surface; the folder is the destination, not the source of truth.\n⊗ Drop items that exist in `vbrief/proposed/` but lack a matching cache row -- those are reconciled later (Phase 3 / origin reconciliation), not silently discarded.\n\n### Phase 0c -- Resume conditions (`[RESUME]`-tagged items first)\n\n1. ! Before walking new untriaged candidates from Phase 0b, process every `[RESUME]`-tagged row in the queue. `[RESUME]` rows surface from D3 (#1123) when a prior `defer` audit entry's `resume-on` condition fires (atomics: `ref:closed:#N`, `ref:merged:#N`, `date:>=YYYY-MM-DD`, `pending-count:>=N|<=N`, composed by a single top-level `AND` or `OR`).\n2. ! Stale-defer (resume-eligible) items take priority over fresh untriaged when both are present in the same Phase 0 pass -- the operator made a forward-dated decision on the deferred item and the framework is honouring it. Treat the `[RESUME]` slice as the FIRST class of candidates surfaced to the user.\n3. ~ The exact precedence in `task triage:queue` is `[ORPHAN]` -> `[RESUME]` -> `[URGENT]` -> untriaged -> other (per D11 + D13 / #1132 grouping). Refinement consumes this order verbatim and surfaces `[RESUME]` candidates first; `[ORPHAN]` rows are out-of-scope for refinement (they are handled by the triage skill's audit phase).\n\n⊗ Treat `[RESUME]` rows as \"leftover\" -- they are the highest-priority class refinement is meant to process, because the operator already decided to revisit them when the condition fired.\n\n### Pre-Phase-1 handoff\n\n1. ! Surface a one-line session summary: `{resume_eligible} resume-eligible, {new_accept} new accept candidate(s), {already_tracked} already tracked in vbrief/`.\n2. ! Chain into Phase 1 -- Ingest, which now operates on the cohort produced by Phase 0b's join (`[RESUME]` rows first, then new accept candidates).\n3. ? If the user opts out of Phase 1 (e.g. \"that's it for today\"), exit via the Phase 0 mid-session exit surface below -- ! MUST NOT route to the `### EXIT` block under `## PR & Review Cycle` because that block is the post-PR-creation exit path and references a `PR #{N}` that does not yet exist at this point in the flow.\n\n#### Phase 0 mid-session exit surface\n\n! When the user opts out of Phase 1 after completing (or partially completing) Phase 0, perform exactly these steps -- ! MUST NOT mention any PR number, since none has been created yet:\n\n1. ! Surface the outstanding-work tally: `{resume_eligible} resume-eligible candidate(s) still pending, {new_accept} accept candidate(s) not yet ingested -- these will resurface on the next Phase 0 entry.`\n2. ! Note the audit-log location verbatim using double-backtick fencing so the inner path renders correctly: ``Audit log preserved at `vbrief/.eval/candidates.jsonl`; queue state is reproducible via `task triage:queue --state=accept`.``\n3. ! Confirm skill exit with the canonical phrasing: `deft-directive-refinement complete -- exiting skill.`\n4. ! Provide the Phase-0-appropriate chaining instruction: ``Resume with `task triage:queue --state=accept` to inspect the queue, or re-enter the refinement skill when ready to continue.`` Do NOT reference a PR, a review cycle, or a monitor agent.\n\n⊗ Skip Phase 1 silently after Phase 0 -- always render the chaining decision so the user knows the entry point shifted.\n⊗ Mutate `vbrief/proposed/` directly during Phase 0 -- only `task issue:ingest` (called from Phase 1) is allowed to write there; Phase 0 is read-only against the cache.\n⊗ Route Phase 0 mid-session opt-out to the post-PR `### EXIT` block under `## PR & Review Cycle` -- that block surfaces a non-existent `PR #{N}` and confuses the user.\n\n## Phase 1 -- Ingest\n\n! Scan external sources for new work items and create proposed scope vBRIEFs.\n\n### Step 1: Gather Sources\n\n1. ? Scan non-GitHub sources (Jira, direct user requests, etc.) manually if applicable — those ingest paths are not yet task-wrapped\n2. ! GitHub issues are ingested via the task wrapper documented in Step 3 — the task fetches open issues itself, so no separate `gh issue list` call is needed\n\n### Step 2: Deduplicate via References (Dry-Run Preview)\n\n1. ? Run `task issue:ingest -- --all --dry-run` to preview which issues the ingest task would create scope vBRIEFs for. The task deduplicates candidates against `references` entries in existing vBRIEFs (across all lifecycle folders) so already-tracked issues are skipped automatically.\n2. ! Present the user with the list of new-vs-already-tracked items the dry-run reports: \"{N} new items found, {M} already tracked\"\n3. ! Wait for user approval before proceeding to ingest\n\n### Step 3: Ingest Approved Items\n\n! Delegate ingest to `task issue:ingest` — the task is the canonical implementation of scope-vBRIEF creation. Skills MUST NOT reinvent the slug rules, reference shape, or deduplication logic inline (see #537 for background).\n\n- **Single issue**: `task issue:ingest -- <N>` — creates `vbrief/proposed/YYYY-MM-DD-<slug>.vbrief.json` with origin `references`, canonical slug from `scripts/slug_normalize.py` (see [`../../conventions/vbrief-filenames.md`](../../conventions/vbrief-filenames.md)), and schema-conformant shape.\n- **Batch**: `task issue:ingest -- --all [--label <L>] [--status <S>]` — ingests every open issue matching the filters, skipping duplicates by `references.uri` match.\n- **Preview**: add `--dry-run` to either form to preview without writing files.\n\nThe task emits vBRIEFs conforming to the canonical v0.6 schema (`vbrief/schemas/vbrief-core.schema.json`) with origin references in the form documented in [`../../conventions/references.md`](../../conventions/references.md):\n\n```json\n\"references\": [\n {\n \"uri\": \"https://github.com/{owner}/{repo}/issues/{N}\",\n \"type\": \"x-vbrief/github-issue\",\n \"title\": \"Issue #{N}: {issue title}\"\n }\n]\n```\n\n- ! New scope vBRIEFs MUST target `\"vBRIEFInfo\": { \"version\": \"0.6\" }` (the task handles this automatically)\n- ! `plan.status` starts at `\"proposed\"`; the task sets this\n- ! Conform to `vbrief/schemas/vbrief-core.schema.json` (v0.6) -- the task validates before writing\n- ~ After ingest, review the generated vBRIEFs with the user before promoting any of them to `pending/`\n\n⊗ Hand-author scope vBRIEFs inside the skill when the ingest task exists — duplicating the narrative logic is how #534 (non-conformant references) and #537 (drift between skill and task) arise\n⊗ Write references with `url`/`id`/bare `github-issue` types — use the schema-conformant `{uri, type, title}` shape above\n⊗ Ingest an item that already has a matching vBRIEF reference -- `task issue:ingest` handles deduplication; skills MUST NOT duplicate that logic inline\n\n## Phase 2 -- Evaluate\n\n! List proposed items for interactive user review.\n\n### Step 1: List Proposed Items\n\n1. ! Read all vBRIEFs in `vbrief/proposed/`\n2. ! Present each item with:\n - Title and filename\n - Origin link(s) from `references`\n - Summary from `narratives` (if populated)\n - Labels/category (if available from origin)\n3. ! Sort by creation date (oldest first) or as user prefers\n\n### Step 2: Interactive Review\n\n! For each proposed item (or batch, as user directs):\n\n- ! Present the item and wait for user decision\n- ~ The user may: accept (promote to pending), reject (cancel), defer (keep in proposed), or request more detail\n- ! Do not proceed to the next item until the user responds\n- ? The user may batch-accept or batch-reject multiple items at once\n\n⊗ Auto-accept or auto-reject proposed items without user review\n\n## Phase 3 -- Reconcile (RFC D12)\n\n! Check if linked origins have changed since the vBRIEF was last touched. Delegate the scan to `task reconcile:issues` and walk the user through flagged items for approval (see #537 for why the skill is a thin wrapper over the task).\n\n### Step 1: Run the Reconciler\n\n```\ntask reconcile:issues\n```\n\nThe task scans every vBRIEF with a GitHub-backed reference (whether the reference uses the legacy `github-issue` bare type or the canonical `x-vbrief/github-issue` shape), fetches each linked issue, compares timestamps and state, and reports items in four buckets:\n\n- **Linked & current** — origin has not changed since the vBRIEF was last updated (no action)\n- **Stale** — origin `updatedAt` is newer than the vBRIEF (propose an update)\n- **Externally closed** — origin issue is `CLOSED` (propose cancellation or reconcile if intentional divergence)\n- **Unlinked** — vBRIEF has no GitHub reference (flag for review)\n\n### Step 2: Walk Flagged Items with the User\n\n1. ! For each **stale** item the task surfaces, show the user the diff between the current vBRIEF and the refreshed origin. Propose edits; ! wait for explicit user approval before writing anything.\n2. ! For each **externally closed** item, ask the user whether to `task scope:cancel <file>` it or preserve intentional divergence.\n3. ! For each **unlinked** item, ask whether to attach an origin reference or leave the vBRIEF as-is.\n\n### Step 3: Apply User-Approved Updates\n\n- ! Agent proposes edits; ! user approves each change\n- ! Never auto-update vBRIEFs — intentional divergence (vBRIEF refined beyond original issue scope) must be preserved\n- ! For approved updates, update the vBRIEF content and `vBRIEFInfo.updated` timestamp; prefer the task commands (`task scope:cancel`, `task scope:block`, etc.) over hand-editing where they apply\n\n⊗ Replace the task invocation with a hand-written `gh issue view` loop — the task is the canonical implementation; skills MUST NOT duplicate it (#537)\n⊗ Auto-update vBRIEFs based on origin changes without user approval\n⊗ Overwrite intentional divergence -- if a vBRIEF has been refined beyond the original issue, preserve the refinement\n\n## Phase 4 -- Promote/Demote\n\n! Move vBRIEFs between lifecycle folders using deterministic task commands. The status values below align with the canonical v0.6 Status enum (`draft | proposed | approved | pending | running | completed | blocked | failed | cancelled`) — note that `failed` is also a valid terminal transition for active work that could not complete.\n\n### Available Commands\n\n- `task scope:promote <file>` -- proposed/ -> pending/ (status: pending)\n- `task scope:activate <file>` -- pending/ -> active/ (status: running)\n- `task scope:complete <file>` -- active/ -> completed/ (status: completed)\n- `task scope:cancel <file>` -- any -> cancelled/ (status: cancelled)\n- `task scope:restore <file>` -- cancelled/ -> proposed/ (status: proposed)\n- `task scope:block <file>` -- stays in active/ (status: blocked)\n- `task scope:unblock <file>` -- stays in active/ (status: running)\n- `task scope:fail <file>` (v0.6+) -- active/ -> completed/ (status: failed) — record a failure terminal state when a scope cannot complete but should not be cancelled\n- `task scope:undo <decision_id>` (D15 / #1134) -- reverse a single scope-lifecycle audit entry (`demote` -> re-promote, `cancel` -> restore-from-cancelled-to-prior-folder, `restore` -> re-cancel); terminal actions (`complete` / `fail`) are REFUSED -- use `git revert` or hand-edit\n- `task scope:undo --batch-id=<uuid>` (D15 / #1134) -- reverse every audit entry tagged with the batch_id (e.g. the cohort produced by `task scope:demote --batch`); idempotent on already-undone entries; the undo cohort is itself reversible via the `undo_batch_id` minted on the new entries. Optional `--dry-run` previews without writing.\n- `task scope:undo --latest` (D15 / #1134) -- reverse the most-recent reversible audit entry (`demote` / `cancel` / `restore` / `undo`) not already undone; convenience form used by the N6 / #1146 smoketest contract.\n\n### Workflow\n\n1. ! Execute transitions using the task commands above -- they handle `plan.status` updates, `plan.updated` timestamps, and file moves atomically\n2. ! Derived-artifact renders (`task roadmap:render`, `task project:render`) happen after a **batch** of promotions/demotions, not after each individual item. During high-volume triage (e.g. dozens of accept/reject decisions in one session), defer both renders until the end of the batch -- the source of truth is the lifecycle folder contents under `vbrief/`, so ROADMAP.md and PROJECT-DEFINITION.vbrief.json can be refreshed once per batch without losing correctness.\n3. ! `task roadmap:render` regenerates ROADMAP.md from the updated lifecycle folder contents. Call it once per batch (typically at the end of Phase 4, before handing back to the user or transitioning to Phase 5), not after every single promote/demote.\n4. ! `task project:render` refreshes the PROJECT-DEFINITION items registry. Call it **once per refinement pass** -- usually at the end of the session alongside the final roadmap render -- unless the user explicitly needs an intermediate registry refresh. It is not a per-edit tax.\n5. ! Before the user is shown the final backlog state (end of Phase 4, end of Phase 5, or session exit), both `task roadmap:render` AND `task project:render` MUST have been run at least once so ROADMAP.md and PROJECT-DEFINITION.vbrief.json reflect the current lifecycle folder truth. This preserves correctness while allowing N promotions/demotions to share one render checkpoint.\n6. ! Mark rejected items as `cancelled` via `task scope:cancel` (never delete vBRIEFs)\n\n~ Operationally: a large refinement session can ingest/evaluate/promote multiple issues and close out with **one** final render checkpoint, rather than N repetitive renders after every individual item.\n\n⊗ Rerender derived artifacts (`task roadmap:render`, `task project:render`) after every single accept/reject/promote/demote during high-volume triage -- batch the lifecycle edits and render once at the end of the batch\n⊗ Move vBRIEFs between folders manually (cp/mv) -- always use `task scope:*` commands\n⊗ Delete vBRIEFs -- use `task scope:cancel` to preserve history\n\n## Phase 5 -- Prioritize\n\n! Reorder and organize the pending backlog.\n\n1. ! List all vBRIEFs in `vbrief/pending/` with titles, origins, and any phase/dependency metadata\n2. ~ Help the user set phases and dependencies:\n - Group related items into phases (via vBRIEF `items` hierarchy or `tags`)\n - Identify dependencies between items (via `edges` in vBRIEF schema)\n3. ! `task roadmap:render` is the **checkpoint** before showing the reordered backlog to the user -- not a per-edit tax. Run it ONCE at the end of the reorder pass to regenerate ROADMAP.md from the updated pending/ contents. Do not invoke it after each individual reorder action.\n4. ~ Present the regenerated roadmap summary to the user for confirmation\n\n## Phase 6 -- Completion Lifecycle\n\n! On scope completion, update origins to close the loop.\n\n### When a Scope Completes\n\n1. ! Read the completed vBRIEF's `references` array\n2. ! For each GitHub-issue reference (either the legacy bare `github-issue` type or the canonical `x-vbrief/github-issue` shape):\n - Close the issue with a comment linking to the implementing PR:\n ```\n gh issue close {N} --comment \"Completed via PR #{PR} -- scope vBRIEF: {filename}\"\n ```\n - The issue number is extracted from the reference `uri` (e.g. `https://github.com/o/r/issues/{N}`)\n3. ? For other reference types (`x-vbrief/jira-ticket`, `x-vbrief/user-request`, `x-vbrief/github-pr`, etc.), follow the appropriate update mechanism\n4. ! Update PROJECT-DEFINITION via `task project:render`\n\n⊗ Complete a scope without updating its origins\n~ Completion lifecycle can be triggered during refinement or as a standalone action after a PR merge\n\n! When the refinement session files a new umbrella issue (or surfaces one whose current-shape comment is missing), file the umbrella then file its `## Current shape (as of pass-N)` comment per `## Umbrella current-shape convention` in `AGENTS.md` (#1152) -- the edit-in-place comment is the canonical surface every subsequent design pass updates.\n\n~ Issue-label hygiene for any umbrella or child issue this skill files: before creating issues, inspect the target repo's existing labels with `gh label list` or the labels API; choose one or more suitable existing labels when practical, or explicitly note that no label was applied. This is a recommendation, not a gate -- do not block issue creation solely because no label fits, and do not invent ad hoc labels outside the repo's existing label set.\n\n! When a refinement pass produces a slicing event (rare but possible -- e.g. a design pass on an existing umbrella files N additional Wave-N child issues), record the cohort in `vbrief/.eval/slices.jsonl` via `scripts/slice_record.py::write_slice(...)` with `actor=\"skill:refinement\"` immediately after the children are filed (#1132 / D13). Same call shape as `skills/deft-directive-gh-slice/SKILL.md` Step 6. The cohort record is what makes `task triage:audit --orphans` able to detect Wave-2+ children whose umbrella closes prematurely; without it the production-side drift this surface guards against re-fires. Skip when the pass produced no new child cohort (e.g. a pure re-prioritization).\n\n\n! When the umbrella + children were filed by hand (legacy `gh issue create` / `issue_write` MCP / prior pass-N runs that pre-date this skill's slicing phase), use the canonical retro verb `task slice:record-existing` (#1147 / N7) -- it wraps the same `slice_record.write_slice` helper with `actor=\"manual:operator\"`, takes `--umbrella=N --children=A,B,C [--wave-N=...]` flags, validates each issue via the N5 / #1145 `scm.call` shim, and is idempotent on a matching umbrella + child set (re-run is a no-op; `--force` writes a second record for legitimate multi-session slicing). Companion `task slice:list` enumerates persisted slices for verification. The backfill verb is the canonical retro path for cohorts D13's writer never saw.\n\n## CHANGELOG Convention\n\n- ! Write ONE batch `CHANGELOG.md` entry at the END of the full refinement session -- not one entry per vBRIEF created or promoted. The batch entry summarizes all changes made during the session.\n- ⊗ Add a CHANGELOG entry after each individual action during refinement -- wait until the full session is complete and write a single summary entry.\n\n## PR & Review Cycle\n\nAfter all refinement work is complete:\n\n1. ! Ask the user: \"Ready to commit and create a PR?\"\n2. ! Wait for explicit user confirmation before proceeding.\n\n### Pre-Flight (before pushing)\n\n! Run all pre-flight checks BEFORE committing and pushing:\n\n1. ! Verify `CHANGELOG.md` has an `[Unreleased]` entry covering the refinement changes\n2. ! Run `task check` -- all checks must pass\n3. ! Verify `.github/PULL_REQUEST_TEMPLATE.md` checklist is satisfiable for this PR. If the file is **missing**, do NOT block — copy the canonical template from `templates/PULL_REQUEST_TEMPLATE.md` (ship-with-deft) to `.github/PULL_REQUEST_TEMPLATE.md` in the consumer project, then proceed with pre-flight (#531). If the file exists but contains unsatisfiable checklist items for this PR, call them out to the user before pushing.\n4. ! **Mandatory file review**: Re-read ALL modified files before committing. Explicitly check for:\n - Encoding errors (em-dashes corrupted to replacement characters, BOM artifacts)\n - Unintended duplication (accidental double vBRIEFs or duplicate entries)\n - Structural issues (malformed vBRIEF JSON, broken references)\n - Semantic accuracy (verify that counts and claims in CHANGELOG entries match the actual data)\n\n### Commit, Push, and Create PR\n\n1. ! Commit with a descriptive message: `docs(vbrief): refinement session -- {summary}`\n2. ! Push the branch to origin\n3. ! Create a PR targeting the appropriate base branch\n\n### Review Cycle Handoff\n\n! After the PR is created, automatically sequence into `skills/deft-directive-review-cycle/SKILL.md`.\n\n- ! Inform the user: \"PR #{N} created -- starting review cycle.\"\n- ! Follow the full review cycle skill from Phase 1 (Deft Process Audit) onward.\n\n### EXIT\n\n! When the review cycle completes (exit condition met) or the PR is ready for human review:\n\n1. ! Explicitly confirm skill exit: \"deft-directive-refinement complete -- exiting skill.\"\n2. ! Provide chaining instructions to the user/agent:\n - If review cycle is complete and PR is approved: \"PR #{N} is ready for human merge review.\"\n - If review cycle is still in progress: \"Review cycle handed off to deft-review-cycle. Monitor PR #{N} for Greptile findings.\"\n - If returning to a monitor agent: \"Returning control to monitor agent -- refinement PR #{N} created and review cycle initiated.\"\n3. ! Do NOT continue into adjacent work after this point -- the skill boundary is an exit condition.\n\n## Anti-Patterns\n\n- ⊗ Bypass Phase 0 by walking `vbrief/proposed/` or `gh issue list` directly -- `task triage:queue --state=accept` (D11 / #1128) is the canonical ingestion-candidate surface (#1141)\n- ⊗ Skip Phase 0a's `task triage:summary` invocation -- the triage-gate decision (run the triage skill first vs proceed) depends on its output (#1141 / D2 / #1122)\n- ⊗ Silently proceed against an empty cache -- emit the canonical `task triage:welcome` (N3 / #1143) breadcrumb to stderr first (#1141)\n- ⊗ Treat `[RESUME]`-tagged items as leftover -- they are the highest-priority class refinement processes (#1141 / D3 / #1123)\n- ⊗ Skip Phase 1 silently after Phase 0 -- always render the chaining decision so the user knows the entry point shifted (#1141, supersedes #845)\n- ⊗ Auto-accept or auto-reject proposed items without user review\n- ⊗ Create vBRIEFs without origin provenance (`references` linking to the source)\n- ⊗ Ingest items without deduplicating against existing vBRIEF references first\n- ⊗ Auto-update vBRIEFs based on origin changes -- user approves all updates\n- ⊗ Overwrite intentional divergence when reconciling stale origins\n- ⊗ Move vBRIEFs between folders manually -- always use `task scope:*` commands\n- ⊗ Delete vBRIEFs -- use `task scope:cancel` to preserve history\n- ⊗ Complete a scope without updating its origins (closing issues, posting comments)\n- ⊗ Skip deduplication during ingest -- always diff against existing references\n- ⊗ Add a CHANGELOG entry per individual action during refinement -- write one batch entry at the end of the full session\n- ⊗ Proceed to the next proposed item without waiting for user decision during evaluate\n- ⊗ Auto-push without explicit user instruction\n- ⊗ Rerender ROADMAP.md or PROJECT-DEFINITION.vbrief.json after every single accept/reject/promote/demote during high-volume triage -- `task roadmap:render` and `task project:render` are batch checkpoints, not per-edit taxes, and calling them N times for N lifecycle edits turns O(1) render work into O(N) without changing correctness (see #638)\n- ⊗ Return a final backlog view to the user without having run `task roadmap:render` and `task project:render` at least once since the last lifecycle edit -- batch the renders, but do not skip them\n\n## See also\n\n- Upstream skill: [`../deft-directive-triage/SKILL.md`](../deft-directive-triage/SKILL.md) (D6 / #1130) -- the canonical triage hygiene + queue selection playbook. Refinement Phase 0a consults `task triage:summary` (D2 / #1122) and Phase 0b consumes `task triage:queue --state=accept` (D11 / #1128), both of which are produced by the triage skill's decision flow. `[RESUME]`-tagged items (Phase 0c) originate from D3 (#1123) `--resume-on` conditions documented in the triage skill's Phase 3.\n- Reversibility verb in Phase 4: `task scope:undo <file>` (D15 / #1134).\n- Onboarding (empty-cache fallback target): `task triage:welcome` (N3 / #1143) -- the single chained command a fresh post-upgrade install runs before re-entering refinement.\n- Refs: #1141 (this rewrite), #1119 (umbrella), #1122 (D2), #1128 (D11), #1123 (D3), #1130 (D6), #1134 (D15), #1143 (N3), #1149 (N9 routing).\n",
166
+ "body": "# Deft Directive Refinement\n\nConversational refinement session -- ingest, evaluate, reconcile, and prioritize scope vBRIEFs with the user.\n\nLegend (from RFC2119): !=MUST, ~=SHOULD, ≉=SHOULD NOT, ⊗=MUST NOT, ?=MAY.\n\n**Upstream pass**: refinement begins with a triage pass -- see [`../deft-directive-triage/SKILL.md`](../deft-directive-triage/SKILL.md) (D6 / #1130) for the canonical cache-hygiene + \"what's next?\" queue playbook before continuing into the refinement flow below.\n\n**See also**: [`../../contracts/deterministic-questions.md`](../../contracts/deterministic-questions.md) (canonical numbered-menu rule used by every Phase 0 / Phase 2-5 gate below) | `task cache:fetch-all` / `task cache:get` (Tier 1 unified content cache, #883 Story 2) | `task triage:bootstrap` / `task triage:accept` / `task triage:reject` / `task triage:defer` / `task triage:needs-ac` / `task triage:mark-duplicate` / `task triage:bulk-*` / `task triage:refresh-active` (Phase 0 action surface, #845 + #883 Story 3 rebind).\n\n## Platform Requirements\n\n! This skill requires **GitHub** as the SCM platform and the **GitHub CLI (`gh`)** to be installed and authenticated. Issue ingestion, origin freshness checks, and completion lifecycle all depend on `gh`.\n\n## Deterministic Questions Contract\n\n! Every numbered-menu prompt rendered in this skill (Phase 0 Triage action menu, Phase 2 Evaluate per-item accept/reject, Phase 3 Reconcile flagged-item walk, Phase 4 Promote/Demote lifecycle gates, Phase 5 Prioritize reorder gates) MUST follow [`../../contracts/deterministic-questions.md`](../../contracts/deterministic-questions.md): render the canonical numbered menu in chat unless the host UI visibly preserves numeric option labels and returns numeric selections or exact displayed option text. The final two numbered options MUST be `Discuss` and `Back`, in that order. The Discuss-pause semantic is documented verbatim there -- on `Discuss` selection the agent MUST halt the in-progress sequence immediately, prompt `What would you like to discuss?`, and resume only on an explicit user signal. Implicit resumption is forbidden, and fallback chat replies MUST map only to the displayed number or exact displayed option text.\n\n## When to Use\n\n- User says \"refinement\", \"reprioritize\", \"refine\", \"roadmap refresh\", or \"refresh roadmap\" (legacy v0.19 terms -- deft-directive-refinement is the current skill name)\n- User says \"triage\", \"action menu\", \"work the cache\", or \"pre-ingest\" -- first-class Phase 0 direct triggers introduced under #845; they route to Phase 0 (Triage), not the general refinement entry\n- New issues have accumulated since the last refinement session\n- Periodic maintenance pass (e.g. weekly or after a batch of user feedback)\n- User wants to review and organize the backlog\n\n! **Entry point (#1141, supersedes #845 / #883 action-menu).** Phase 0 -- Triage-first consultation is the canonical entry point for any refinement session. Phase 0 consults `task triage:summary` (D2 / #1122) and `task triage:queue --state=accept` (D11 / #1128) and pulls the `[RESUME]`-tagged slice (D3 / #1123) FIRST. Refinement does NOT itself triage cached candidates -- that work belongs to [`../deft-directive-triage/SKILL.md`](../deft-directive-triage/SKILL.md) (D6 / #1130). Phase 0 ! MUST chain into Phase 1 -- Ingest on completion (or surface the empty-cache fallback prompt when the cache has not yet been bootstrapped -- see Phase 0a below). Phase 1+ semantics are unchanged.\n\n## Prerequisites\n\n- ! `vbrief/` directory exists with lifecycle folders (`proposed/`, `pending/`, `active/`, `completed/`, `cancelled/`)\n- ! GitHub CLI (`gh`) is authenticated and can access the repo\n- ~ `PROJECT-DEFINITION.vbrief.json` exists (run `task project:render` if missing)\n\n## Session Model\n\nRefinement is a **conversational loop**, not a batch job. The user directs the flow:\n\n- \"Triage\" / \"action menu\" / \"work the cache\" / \"pre-ingest\" -> Phase 0 (Triage-first consultation, #1141) -- refinement consults the cache; the canonical decision-making playbook is `../deft-directive-triage/SKILL.md` (D6 / #1130)\n- \"Pull in issues\" / \"ingest\" -> Phase 0 ALWAYS runs first to consult `task triage:summary` + `task triage:queue --state=accept`; Phase 1 follows on the cohort Phase 0b produces (#1141)\n- \"Show proposed\" / \"evaluate\" -> Phase 2 (Evaluate)\n- \"Check origins\" / \"reconcile\" -> Phase 3 (Reconcile)\n- \"Accept these\" / \"reject that\" / \"promote\" / \"demote\" -> Phase 4 (Promote/Demote)\n- \"Reprioritize\" / \"reorder pending\" -> Phase 5 (Prioritize)\n- \"Close out\" / \"scope is done\" / \"completion\" -> Phase 6 (Completion Lifecycle)\n- \"Done\" / \"exit\" -> Exit\n\nThe agent may suggest the next phase, but the user decides. Phases can be entered in any order and repeated.\n\n## Branch Setup (Preflight)\n\n! Before making any changes, ensure you are working on a feature branch. This preflight runs before Phase 0 and again before Phase 1 if Phase 0 is auto-skipped.\n\n1. ! Check if the working tree has uncommitted changes that would conflict -- stop and ask the user to resolve them first\n2. ! Create or switch to a refinement branch (e.g. `refinement/YYYY-MM-DD`) if not already on one\n3. ! Confirm the branch and working directory to the user before proceeding\n\n## Phase 0 -- Triage-first consultation (cache-first, #1141)\n\n! Phase 0 is a thin consumer of the canonical triage cache: refinement consults `task triage:summary` (D2 / #1122) and `task triage:queue` (D11 / #1128) BEFORE walking any `vbrief/` lifecycle folder. The dedicated triage playbook lives at [`../deft-directive-triage/SKILL.md`](../deft-directive-triage/SKILL.md) (D6 / #1130) -- refinement does NOT itself triage cached candidates; it consumes the queue's `accept` and `[RESUME]` slices and turns them into scope vBRIEFs.\n\n! Phase 0 runs three sub-phases in canonical order: **Phase 0a -- Triage gate** -> **Phase 0b -- Cache-first ingestion** -> **Phase 0c -- Resume conditions**. Each sub-phase MUST run before the next, and Phase 0 MUST chain into Phase 1 -- Ingest on completion. Numbered prompts in Phase 0 ! MUST follow [`../../contracts/deterministic-questions.md`](../../contracts/deterministic-questions.md) (`Discuss` / `Back` as the final two numbered options; Discuss-pause semantic applies verbatim).\n\n**See also (#883 Story 2):** the unified cache (`task cache:fetch-all --source=github-issue --repo OWNER/NAME`) is the sole content-mirroring surface in v0.26.0+. Tier 1 reads MUST go through `task cache:get -- github-issue OWNER/NAME/<N>`. The legacy \"Three-Tier Inventory Model\" + action-menu walk that lived here pre-#1141 has moved out of refinement and into `../deft-directive-triage/SKILL.md` (D6 / #1130); refinement now consumes the post-decision queue rather than producing decisions.\n\n### Phase 0a -- Triage gate (`task triage:summary`)\n\n1. ! Invoke `task triage:summary` (D2 / #1122) and capture the one-liner.\n2. ! **Empty-cache backward-compat fallback.** If the one-liner is the documented empty-cache prompt (`[triage] cache empty -- run task triage:bootstrap`), the agent ! MUST emit the verbatim recovery message to stderr BEFORE any folder scan:\n\n ```\n triage cache empty -- run `task triage:welcome` (N3 / #1143) to onboard, or `task triage:bootstrap` to seed the cache directly; refinement Phase 0 cannot consult the queue against an empty cache. Falling back to a legacy `vbrief/proposed/` folder scan only if you opt in.\n ```\n\n Then prompt the user `Fall back to legacy folder-scan against vbrief/proposed/ for this session? [y/N]` (default `N`). On `N`, exit refinement with the canonical `deft-directive-refinement complete -- exiting skill.` confirmation and the chaining instruction `Run task triage:welcome (N3 / #1143) to onboard, then re-enter refinement.`. On `y`, chain into Phase 1 against `vbrief/proposed/` as the legacy fallback. ! MUST NOT silently proceed without surfacing the breadcrumb to `task triage:welcome` -- a fresh post-upgrade install needs that pointer to find the canonical onboarding ritual.\n\n3. ! **Outstanding-work gate.** If the cache is populated AND any of `untriaged`, `stale-defer (resume condition met)`, or `in-flight` is non-zero, surface the one-liner verbatim to the user with the canonical recommendation:\n\n ```\n triage cache has outstanding work -- recommend running `skills/deft-directive-triage/SKILL.md` (D6 / #1130) first. Proceed to refinement anyway? [y/N]\n ```\n\n ~ Default is `N`: deferring to the triage skill is the documented happy path because refinement consumes `accept`-decisioned candidates and an untriaged backlog means there are fewer `accept` rows than there could be. On `N`, exit with the canonical confirmation phrasing and the chaining instruction `Run skills/deft-directive-triage/SKILL.md to clear the backlog, then re-enter refinement.`. On `y`, proceed to Phase 0b.\n\n4. ? When all counts are zero (cache populated, no outstanding work), proceed to Phase 0b without prompting.\n\n⊗ Skip Phase 0a -- refinement on top of an untriaged cache wastes the operator's time on items the triage skill would have rejected, deferred, or marked needs-AC.\n⊗ Bypass the empty-cache fallback prompt -- a silent proceed against an empty cache surfaces a misleading \"no candidates\" state and hides the upgrade-onboarding path from the operator.\n\n### Phase 0b -- Cache-first ingestion (`task triage:queue --state=accept`)\n\n1. ! Pull the ingestion candidate list via `task triage:queue --state=accept` (D11 / #1128). Each row is a cached issue whose latest audit-log decision is `accept` -- the canonical \"ready to become a scope vBRIEF\" cohort. ! MUST NOT enumerate `vbrief/proposed/` independently of the queue; the folder participates only via the join described in step 2.\n2. ! Join the queue against `vbrief/proposed/` (and the rest of the lifecycle folders) by `references[].uri`: queue rows whose issue is already represented by an existing vBRIEF surface as \"already tracked\"; queue rows with no matching vBRIEF are \"new accept candidates\". Items already in `vbrief/proposed/` continue to participate -- they are joined against the cache rather than enumerated separately.\n3. ~ When the join surfaces zero new candidates (every `accept` row already has a vBRIEF), Phase 0b is a clean no-op; chain straight into Phase 0c.\n4. ! For each new candidate, fall through to Phase 1 -- Ingest, which delegates the actual scope-vBRIEF write to `task issue:ingest`. The intended single-verb form is `task scope:promote --from-issue=<N>` (#1136 / D18); until D18 lands, refinement chains the existing `task issue:ingest` + `task scope:promote` pair.\n\n <!-- TODO(#1136 / D18): when `task scope:promote --from-issue=<N>` ships, refinement Phase 0b consumes it directly instead of chaining `task issue:ingest` + `task scope:promote`. -->\n\n⊗ Walk `vbrief/proposed/` directly as the primary ingestion surface -- the cache is the authoritative \"what is ready to refine?\" surface; the folder is the destination, not the source of truth.\n⊗ Drop items that exist in `vbrief/proposed/` but lack a matching cache row -- those are reconciled later (Phase 3 / origin reconciliation), not silently discarded.\n\n### Phase 0c -- Resume conditions (`[RESUME]`-tagged items first)\n\n1. ! Before walking new untriaged candidates from Phase 0b, process every `[RESUME]`-tagged row in the queue. `[RESUME]` rows surface from D3 (#1123) when a prior `defer` audit entry's `resume-on` condition fires (atomics: `ref:closed:#N`, `ref:merged:#N`, `date:>=YYYY-MM-DD`, `pending-count:>=N|<=N`, composed by a single top-level `AND` or `OR`).\n2. ! Stale-defer (resume-eligible) items take priority over fresh untriaged when both are present in the same Phase 0 pass -- the operator made a forward-dated decision on the deferred item and the framework is honouring it. Treat the `[RESUME]` slice as the FIRST class of candidates surfaced to the user.\n3. ~ The exact precedence in `task triage:queue` is `[ORPHAN]` -> `[RESUME]` -> `[URGENT]` -> untriaged -> other (per D11 + D13 / #1132 grouping). Refinement consumes this order verbatim and surfaces `[RESUME]` candidates first; `[ORPHAN]` rows are out-of-scope for refinement (they are handled by the triage skill's audit phase).\n\n⊗ Treat `[RESUME]` rows as \"leftover\" -- they are the highest-priority class refinement is meant to process, because the operator already decided to revisit them when the condition fired.\n\n### Pre-Phase-1 handoff\n\n1. ! Surface a one-line session summary: `{resume_eligible} resume-eligible, {new_accept} new accept candidate(s), {already_tracked} already tracked in vbrief/`.\n2. ! Chain into Phase 1 -- Ingest, which now operates on the cohort produced by Phase 0b's join (`[RESUME]` rows first, then new accept candidates).\n3. ? If the user opts out of Phase 1 (e.g. \"that's it for today\"), exit via the Phase 0 mid-session exit surface below -- ! MUST NOT route to the `### EXIT` block under `## PR & Review Cycle` because that block is the post-PR-creation exit path and references a `PR #{N}` that does not yet exist at this point in the flow.\n\n#### Phase 0 mid-session exit surface\n\n! When the user opts out of Phase 1 after completing (or partially completing) Phase 0, perform exactly these steps -- ! MUST NOT mention any PR number, since none has been created yet:\n\n1. ! Surface the outstanding-work tally: `{resume_eligible} resume-eligible candidate(s) still pending, {new_accept} accept candidate(s) not yet ingested -- these will resurface on the next Phase 0 entry.`\n2. ! Note the audit-log location verbatim using double-backtick fencing so the inner path renders correctly: ``Audit log preserved at `vbrief/.eval/candidates.jsonl`; queue state is reproducible via `task triage:queue --state=accept`.``\n3. ! Confirm skill exit with the canonical phrasing: `deft-directive-refinement complete -- exiting skill.`\n4. ! Provide the Phase-0-appropriate chaining instruction: ``Resume with `task triage:queue --state=accept` to inspect the queue, or re-enter the refinement skill when ready to continue.`` Do NOT reference a PR, a review cycle, or a monitor agent.\n\n⊗ Skip Phase 1 silently after Phase 0 -- always render the chaining decision so the user knows the entry point shifted.\n⊗ Mutate `vbrief/proposed/` directly during Phase 0 -- only `task issue:ingest` (called from Phase 1) is allowed to write there; Phase 0 is read-only against the cache.\n⊗ Route Phase 0 mid-session opt-out to the post-PR `### EXIT` block under `## PR & Review Cycle` -- that block surfaces a non-existent `PR #{N}` and confuses the user.\n\n## Phase 1 -- Ingest\n\n! Scan external sources for new work items and create proposed scope vBRIEFs.\n\n### Step 1: Gather Sources\n\n1. ? Scan non-GitHub sources (Jira, direct user requests, etc.) manually if applicable — those ingest paths are not yet task-wrapped\n2. ! GitHub issues are ingested via the task wrapper documented in Step 3 — the task fetches open issues itself, so no separate `gh issue list` call is needed\n\n### Step 2: Deduplicate via References (Dry-Run Preview)\n\n1. ? Run `task issue:ingest -- --all --dry-run` to preview which issues the ingest task would create scope vBRIEFs for. The task deduplicates candidates against `references` entries in existing vBRIEFs (across all lifecycle folders) so already-tracked issues are skipped automatically.\n2. ! Present the user with the list of new-vs-already-tracked items the dry-run reports: \"{N} new items found, {M} already tracked\"\n3. ! Wait for user approval before proceeding to ingest\n\n### Step 3: Ingest Approved Items\n\n! Delegate ingest to `task issue:ingest` — the task is the canonical implementation of scope-vBRIEF creation. Skills MUST NOT reinvent the slug rules, reference shape, or deduplication logic inline (see #537 for background).\n\n- **Single issue**: `task issue:ingest -- <N>` — creates `vbrief/proposed/YYYY-MM-DD-<slug>.vbrief.json` with origin `references`, canonical slug from `scripts/slug_normalize.py` (see [`../../conventions/vbrief-filenames.md`](../../conventions/vbrief-filenames.md)), and schema-conformant shape.\n- **Batch**: `task issue:ingest -- --all [--label <L>] [--status <S>]` — ingests every open issue matching the filters, skipping duplicates by `references.uri` match.\n- **Preview**: add `--dry-run` to either form to preview without writing files.\n\nThe task emits vBRIEFs conforming to the canonical v0.6 schema (`vbrief/schemas/vbrief-core.schema.json`) with origin references in the form documented in [`../../conventions/references.md`](../../conventions/references.md):\n\n```json\n\"references\": [\n {\n \"uri\": \"https://github.com/{owner}/{repo}/issues/{N}\",\n \"type\": \"x-vbrief/github-issue\",\n \"title\": \"Issue #{N}: {issue title}\"\n }\n]\n```\n\n- ! New scope vBRIEFs MUST target `\"vBRIEFInfo\": { \"version\": \"0.6\" }` (the task handles this automatically)\n- ! `plan.status` starts at `\"proposed\"`; the task sets this\n- ! Conform to `vbrief/schemas/vbrief-core.schema.json` (v0.6) -- the task validates before writing\n- ~ After ingest, review the generated vBRIEFs with the user before promoting any of them to `pending/`\n\n⊗ Hand-author scope vBRIEFs inside the skill when the ingest task exists — duplicating the narrative logic is how #534 (non-conformant references) and #537 (drift between skill and task) arise\n⊗ Write references with `url`/`id`/bare `github-issue` types — use the schema-conformant `{uri, type, title}` shape above\n⊗ Ingest an item that already has a matching vBRIEF reference -- `task issue:ingest` handles deduplication; skills MUST NOT duplicate that logic inline\n\n## Phase 2 -- Evaluate\n\n! List proposed items for interactive user review.\n\n### Step 1: List Proposed Items\n\n1. ! Read all vBRIEFs in `vbrief/proposed/`\n2. ! Present each item with:\n - Title and filename\n - Origin link(s) from `references`\n - Summary from `narratives` (if populated)\n - Labels/category (if available from origin)\n3. ! Sort by creation date (oldest first) or as user prefers\n\n### Step 2: Interactive Review\n\n! For each proposed item (or batch, as user directs):\n\n- ! Present the item and wait for user decision\n- ~ The user may: accept (promote to pending), reject (cancel), defer (keep in proposed), or request more detail\n- ! Do not proceed to the next item until the user responds\n- ? The user may batch-accept or batch-reject multiple items at once\n\n⊗ Auto-accept or auto-reject proposed items without user review\n\n## Phase 3 -- Reconcile (RFC D12)\n\n! Check if linked origins have changed since the vBRIEF was last touched. Delegate the scan to `task reconcile:issues` and walk the user through flagged items for approval (see #537 for why the skill is a thin wrapper over the task).\n\n### Step 1: Run the Reconciler\n\n```\ntask reconcile:issues\n```\n\nThe task scans every vBRIEF with a GitHub-backed reference (whether the reference uses the legacy `github-issue` bare type or the canonical `x-vbrief/github-issue` shape), fetches each linked issue, compares timestamps and state, and reports items in four buckets:\n\n- **Linked & current** — origin has not changed since the vBRIEF was last updated (no action)\n- **Stale** — origin `updatedAt` is newer than the vBRIEF (propose an update)\n- **Externally closed** — origin issue is `CLOSED` (propose cancellation or reconcile if intentional divergence)\n- **Unlinked** — vBRIEF has no GitHub reference (flag for review)\n\n### Step 2: Walk Flagged Items with the User\n\n1. ! For each **stale** item the task surfaces, show the user the diff between the current vBRIEF and the refreshed origin. Propose edits; ! wait for explicit user approval before writing anything.\n2. ! For each **externally closed** item, ask the user whether to `task scope:cancel <file>` it or preserve intentional divergence.\n3. ! For each **unlinked** item, ask whether to attach an origin reference or leave the vBRIEF as-is.\n\n### Step 3: Apply User-Approved Updates\n\n- ! Agent proposes edits; ! user approves each change\n- ! Never auto-update vBRIEFs — intentional divergence (vBRIEF refined beyond original issue scope) must be preserved\n- ! For approved updates, update the vBRIEF content and `vBRIEFInfo.updated` timestamp; prefer the task commands (`task scope:cancel`, `task scope:block`, etc.) over hand-editing where they apply\n\n⊗ Replace the task invocation with a hand-written `gh issue view` loop — the task is the canonical implementation; skills MUST NOT duplicate it (#537)\n⊗ Auto-update vBRIEFs based on origin changes without user approval\n⊗ Overwrite intentional divergence -- if a vBRIEF has been refined beyond the original issue, preserve the refinement\n\n## Phase 4 -- Promote/Demote\n\n! Move vBRIEFs between lifecycle folders using deterministic task commands. The status values below align with the canonical v0.6 Status enum (`draft | proposed | approved | pending | running | completed | blocked | failed | cancelled`) — note that `failed` is also a valid terminal transition for active work that could not complete.\n\n### Available Commands\n\n- `task scope:promote <file>` -- proposed/ -> pending/ (status: pending)\n- `task scope:activate <file>` -- pending/ -> active/ (status: running)\n- `task scope:complete <file>` -- active/ -> completed/ (status: completed)\n- `task scope:cancel <file>` -- any -> cancelled/ (status: cancelled)\n- `task scope:restore <file>` -- cancelled/ -> proposed/ (status: proposed)\n- `task scope:block <file>` -- stays in active/ (status: blocked)\n- `task scope:unblock <file>` -- stays in active/ (status: running)\n- `task scope:fail <file>` (v0.6+) -- active/ -> completed/ (status: failed) — record a failure terminal state when a scope cannot complete but should not be cancelled\n- `task scope:undo <decision_id>` (D15 / #1134) -- reverse a single scope-lifecycle audit entry (`demote` -> re-promote, `cancel` -> restore-from-cancelled-to-prior-folder, `restore` -> re-cancel); terminal actions (`complete` / `fail`) are REFUSED -- use `git revert` or hand-edit\n- `task scope:undo --batch-id=<uuid>` (D15 / #1134) -- reverse every audit entry tagged with the batch_id (e.g. the cohort produced by `task scope:demote --batch`); idempotent on already-undone entries; the undo cohort is itself reversible via the `undo_batch_id` minted on the new entries. Optional `--dry-run` previews without writing.\n- `task scope:undo --latest` (D15 / #1134) -- reverse the most-recent reversible audit entry (`demote` / `cancel` / `restore` / `undo`) not already undone; convenience form used by the N6 / #1146 smoketest contract.\n\n### Workflow\n\n1. ! Execute transitions using the task commands above -- they handle `plan.status` updates, `plan.updated` timestamps, and file moves atomically\n2. ! Derived-artifact renders (`task roadmap:render`, `task project:render`) happen after a **batch** of promotions/demotions, not after each individual item. During high-volume triage (e.g. dozens of accept/reject decisions in one session), defer both renders until the end of the batch -- the source of truth is the lifecycle folder contents under `vbrief/`, so ROADMAP.md and PROJECT-DEFINITION.vbrief.json can be refreshed once per batch without losing correctness.\n3. ! `task roadmap:render` regenerates ROADMAP.md from the updated lifecycle folder contents. Call it once per batch (typically at the end of Phase 4, before handing back to the user or transitioning to Phase 5), not after every single promote/demote.\n4. ! `task project:render` refreshes the PROJECT-DEFINITION items registry. Call it **once per refinement pass** -- usually at the end of the session alongside the final roadmap render -- unless the user explicitly needs an intermediate registry refresh. It is not a per-edit tax.\n5. ! Before the user is shown the final backlog state (end of Phase 4, end of Phase 5, or session exit), both `task roadmap:render` AND `task project:render` MUST have been run at least once so ROADMAP.md and PROJECT-DEFINITION.vbrief.json reflect the current lifecycle folder truth. This preserves correctness while allowing N promotions/demotions to share one render checkpoint.\n6. ! Mark rejected items as `cancelled` via `task scope:cancel` (never delete vBRIEFs)\n\n~ Operationally: a large refinement session can ingest/evaluate/promote multiple issues and close out with **one** final render checkpoint, rather than N repetitive renders after every individual item.\n\n⊗ Rerender derived artifacts (`task roadmap:render`, `task project:render`) after every single accept/reject/promote/demote during high-volume triage -- batch the lifecycle edits and render once at the end of the batch\n⊗ Move vBRIEFs between folders manually (cp/mv) -- always use `task scope:*` commands\n⊗ Delete vBRIEFs -- use `task scope:cancel` to preserve history\n\n## Phase 5 -- Prioritize\n\n! Reorder and organize the pending backlog.\n\n1. ! List all vBRIEFs in `vbrief/pending/` with titles, origins, and any phase/dependency metadata\n2. ~ Help the user set phases and dependencies:\n - Group related items into phases (via vBRIEF `items` hierarchy or `tags`)\n - Identify dependencies between items (via `edges` in vBRIEF schema)\n3. ! `task roadmap:render` is the **checkpoint** before showing the reordered backlog to the user -- not a per-edit tax. Run it ONCE at the end of the reorder pass to regenerate ROADMAP.md from the updated pending/ contents. Do not invoke it after each individual reorder action.\n4. ~ Present the regenerated roadmap summary to the user for confirmation\n\n## Phase 6 -- Completion Lifecycle\n\n! On scope completion, update origins to close the loop.\n\n### When a Scope Completes\n\n1. ! Read the completed vBRIEF's `references` array\n2. ! For each GitHub-issue reference (either the legacy bare `github-issue` type or the canonical `x-vbrief/github-issue` shape):\n - Close the issue with a comment linking to the implementing PR:\n ```\n gh issue close {N} --comment \"Completed via PR #{PR} -- scope vBRIEF: {filename}\"\n ```\n - The issue number is extracted from the reference `uri` (e.g. `https://github.com/o/r/issues/{N}`)\n3. ? For other reference types (`x-vbrief/jira-ticket`, `x-vbrief/user-request`, `x-vbrief/github-pr`, etc.), follow the appropriate update mechanism\n4. ! Update PROJECT-DEFINITION via `task project:render`\n\n⊗ Complete a scope without updating its origins\n~ Completion lifecycle can be triggered during refinement or as a standalone action after a PR merge\n\n! When the refinement session files a new umbrella issue (or surfaces one whose current-shape comment is missing), file the umbrella then file its `## Current shape (as of pass-N)` comment per `## Umbrella current-shape convention` in `AGENTS.md` (#1152) -- the edit-in-place comment is the canonical surface every subsequent design pass updates.\n\n! Before reporting an umbrella or epic's current status to the operator (what is done, what blocks, wave order), fetch `repos/<owner>/<repo>/issues/<N>/comments` via REST, read the `## Current shape (as of pass-N)` comment and any linked context/`LockedDecisions` vBRIEF — never conclude status from the issue body alone (claim-cites-state-surface, #2066).\n\n~ Issue-label hygiene for any umbrella or child issue this skill files: before creating issues, inspect the target repo's existing labels with `gh label list` or the labels API; choose one or more suitable existing labels when practical, or explicitly note that no label was applied. This is a recommendation, not a gate -- do not block issue creation solely because no label fits, and do not invent ad hoc labels outside the repo's existing label set.\n\n! When a refinement pass produces a slicing event (rare but possible -- e.g. a design pass on an existing umbrella files N additional Wave-N child issues), record the cohort in `vbrief/.eval/slices.jsonl` via `scripts/slice_record.py::write_slice(...)` with `actor=\"skill:refinement\"` immediately after the children are filed (#1132 / D13). Same call shape as `skills/deft-directive-gh-slice/SKILL.md` Step 6. The cohort record is what makes `task triage:audit --orphans` able to detect Wave-2+ children whose umbrella closes prematurely; without it the production-side drift this surface guards against re-fires. Skip when the pass produced no new child cohort (e.g. a pure re-prioritization).\n\n\n! When the umbrella + children were filed by hand (legacy `gh issue create` / `issue_write` MCP / prior pass-N runs that pre-date this skill's slicing phase), use the canonical retro verb `task slice:record-existing` (#1147 / N7) -- it wraps the same `slice_record.write_slice` helper with `actor=\"manual:operator\"`, takes `--umbrella=N --children=A,B,C [--wave-N=...]` flags, validates each issue via the N5 / #1145 `scm.call` shim, and is idempotent on a matching umbrella + child set (re-run is a no-op; `--force` writes a second record for legitimate multi-session slicing). Companion `task slice:list` enumerates persisted slices for verification. The backfill verb is the canonical retro path for cohorts D13's writer never saw.\n\n## CHANGELOG Convention\n\n- ! Write ONE batch `CHANGELOG.md` entry at the END of the full refinement session -- not one entry per vBRIEF created or promoted. The batch entry summarizes all changes made during the session.\n- ⊗ Add a CHANGELOG entry after each individual action during refinement -- wait until the full session is complete and write a single summary entry.\n\n## PR & Review Cycle\n\nAfter all refinement work is complete:\n\n1. ! Ask the user: \"Ready to commit and create a PR?\"\n2. ! Wait for explicit user confirmation before proceeding.\n\n### Pre-Flight (before pushing)\n\n! Run all pre-flight checks BEFORE committing and pushing:\n\n1. ! Verify `CHANGELOG.md` has an `[Unreleased]` entry covering the refinement changes\n2. ! Run `task check` -- all checks must pass\n3. ! Verify `.github/PULL_REQUEST_TEMPLATE.md` checklist is satisfiable for this PR. If the file is **missing**, do NOT block — copy the canonical template from `templates/PULL_REQUEST_TEMPLATE.md` (ship-with-deft) to `.github/PULL_REQUEST_TEMPLATE.md` in the consumer project, then proceed with pre-flight (#531). If the file exists but contains unsatisfiable checklist items for this PR, call them out to the user before pushing.\n4. ! **Mandatory file review**: Re-read ALL modified files before committing. Explicitly check for:\n - Encoding errors (em-dashes corrupted to replacement characters, BOM artifacts)\n - Unintended duplication (accidental double vBRIEFs or duplicate entries)\n - Structural issues (malformed vBRIEF JSON, broken references)\n - Semantic accuracy (verify that counts and claims in CHANGELOG entries match the actual data)\n\n### Commit, Push, and Create PR\n\n1. ! Commit with a descriptive message: `docs(vbrief): refinement session -- {summary}`\n2. ! Push the branch to origin\n3. ! Create a PR targeting the appropriate base branch\n\n### Review Cycle Handoff\n\n! After the PR is created, automatically sequence into `skills/deft-directive-review-cycle/SKILL.md`.\n\n- ! Inform the user: \"PR #{N} created -- starting review cycle.\"\n- ! Follow the full review cycle skill from Phase 1 (Deft Process Audit) onward.\n\n### EXIT\n\n! When the review cycle completes (exit condition met) or the PR is ready for human review:\n\n1. ! Explicitly confirm skill exit: \"deft-directive-refinement complete -- exiting skill.\"\n2. ! Provide chaining instructions to the user/agent:\n - If review cycle is complete and PR is approved: \"PR #{N} is ready for human merge review.\"\n - If review cycle is still in progress: \"Review cycle handed off to deft-review-cycle. Monitor PR #{N} for Greptile findings.\"\n - If returning to a monitor agent: \"Returning control to monitor agent -- refinement PR #{N} created and review cycle initiated.\"\n3. ! Do NOT continue into adjacent work after this point -- the skill boundary is an exit condition.\n\n## Anti-Patterns\n\n- ⊗ Bypass Phase 0 by walking `vbrief/proposed/` or `gh issue list` directly -- `task triage:queue --state=accept` (D11 / #1128) is the canonical ingestion-candidate surface (#1141)\n- ⊗ Skip Phase 0a's `task triage:summary` invocation -- the triage-gate decision (run the triage skill first vs proceed) depends on its output (#1141 / D2 / #1122)\n- ⊗ Silently proceed against an empty cache -- emit the canonical `task triage:welcome` (N3 / #1143) breadcrumb to stderr first (#1141)\n- ⊗ Treat `[RESUME]`-tagged items as leftover -- they are the highest-priority class refinement processes (#1141 / D3 / #1123)\n- ⊗ Skip Phase 1 silently after Phase 0 -- always render the chaining decision so the user knows the entry point shifted (#1141, supersedes #845)\n- ⊗ Auto-accept or auto-reject proposed items without user review\n- ⊗ Create vBRIEFs without origin provenance (`references` linking to the source)\n- ⊗ Ingest items without deduplicating against existing vBRIEF references first\n- ⊗ Auto-update vBRIEFs based on origin changes -- user approves all updates\n- ⊗ Overwrite intentional divergence when reconciling stale origins\n- ⊗ Move vBRIEFs between folders manually -- always use `task scope:*` commands\n- ⊗ Delete vBRIEFs -- use `task scope:cancel` to preserve history\n- ⊗ Complete a scope without updating its origins (closing issues, posting comments)\n- ⊗ Skip deduplication during ingest -- always diff against existing references\n- ⊗ Add a CHANGELOG entry per individual action during refinement -- write one batch entry at the end of the full session\n- ⊗ Proceed to the next proposed item without waiting for user decision during evaluate\n- ⊗ Auto-push without explicit user instruction\n- ⊗ Rerender ROADMAP.md or PROJECT-DEFINITION.vbrief.json after every single accept/reject/promote/demote during high-volume triage -- `task roadmap:render` and `task project:render` are batch checkpoints, not per-edit taxes, and calling them N times for N lifecycle edits turns O(1) render work into O(N) without changing correctness (see #638)\n- ⊗ Return a final backlog view to the user without having run `task roadmap:render` and `task project:render` at least once since the last lifecycle edit -- batch the renders, but do not skip them\n\n## See also\n\n- Upstream skill: [`../deft-directive-triage/SKILL.md`](../deft-directive-triage/SKILL.md) (D6 / #1130) -- the canonical triage hygiene + queue selection playbook. Refinement Phase 0a consults `task triage:summary` (D2 / #1122) and Phase 0b consumes `task triage:queue --state=accept` (D11 / #1128), both of which are produced by the triage skill's decision flow. `[RESUME]`-tagged items (Phase 0c) originate from D3 (#1123) `--resume-on` conditions documented in the triage skill's Phase 3.\n- Reversibility verb in Phase 4: `task scope:undo <file>` (D15 / #1134).\n- Onboarding (empty-cache fallback target): `task triage:welcome` (N3 / #1143) -- the single chained command a fresh post-upgrade install runs before re-entering refinement.\n- Refs: #1141 (this rewrite), #1119 (umbrella), #1122 (D2), #1128 (D11), #1123 (D3), #1130 (D6), #1134 (D15), #1143 (N3), #1149 (N9 routing).\n",
167
167
  "frontmatter_extra": "triggers:\n - refinement\n - reprioritize\n - refine\n - roadmap refresh\n - refresh roadmap\n - triage\n - action menu\n - work the cache\n - pre-ingest"
168
168
  },
169
169
  {
@@ -203,7 +203,7 @@
203
203
  ],
204
204
  "path": "skills/deft-directive-setup/SKILL.md",
205
205
  "version": "0.1",
206
- "body": "<!-- AUTO-GENERATED by task packs:render -- DO NOT EDIT MANUALLY -->\n<!-- Purpose: rendered skill -->\n<!-- Source of truth: packs/skills/skills-pack-0.1.json -->\n<!-- Regenerate with: task packs:render -->\n<!-- Edit the source, not this file. Slice instead of loading every SKILL.md: task packs:slice skills by-trigger --trigger <kw> (or list) -->\n\n# Deft Directive Setup\n\nAgent-driven alternative to `.deft/core/run bootstrap && .deft/core/run project && .deft/core/run spec`.\n\nLegend (from RFC2119): !=MUST, ~=SHOULD, ≉=SHOULD NOT, ⊗=MUST NOT, ?=MAY.\n\n## When to Use\n\n- User says \"set up deft\", \"configure deft\", or \"bootstrap my project\"\n- User asks to create USER.md, PROJECT-DEFINITION.vbrief.json, or a specification\n- User clones a deft-enabled repo for the first time with no config\n\n## Pre-Cutover Detection Guard\n\n! Before proceeding with any setup phase, detect whether the project uses the pre-v0.20 document model and redirect to migration if so.\n\n### Detection Criteria\n\nA project is **pre-cutover** if ANY of the following are true. This prose mirrors the executable helper in `scripts/_precutover.py`; when in doubt, the helper is canonical.\n\n1. `SPECIFICATION.md` exists and is neither a deprecation redirect nor a current generated spec export. A current generated spec export contains `<!-- Purpose: rendered specification -->` and `<!-- Source of truth: vbrief/specification.vbrief.json -->`, and `vbrief/specification.vbrief.json` plus all five lifecycle folders exist.\n2. `PROJECT.md` exists and contains neither the legacy `<!-- deft:deprecated-redirect -->` sentinel NOR the current `Purpose: deprecation redirect` canonical-banner marker (same one-release-cycle grace window).\n3. `vbrief/specification.vbrief.json` exists but the lifecycle folders (`vbrief/proposed/`, `vbrief/pending/`, `vbrief/active/`, `vbrief/completed/`, `vbrief/cancelled/`) do NOT exist\n\n### Action on Detection\n\n! If pre-cutover state is detected, **stop immediately** and display an actionable message:\n\n> \"This project uses the pre-v0.20 document model. Run `task migrate:vbrief` to upgrade to the vBRIEF-centric model.\"\n\n! Include specific details about what was detected:\n\n- Missing lifecycle folders: \"Run `task migrate:vbrief` to create the lifecycle folder structure\"\n- `SPECIFICATION.md` with real content: \"SPECIFICATION.md contains non-redirect content -- this file is deprecated; use scope vBRIEFs in `vbrief/` instead\"\n- `PROJECT.md` with real content: \"PROJECT.md contains non-redirect content -- this file is deprecated; use `PROJECT-DEFINITION.vbrief.json` instead\"\n- Missing `PROJECT-DEFINITION.vbrief.json`: \"Run `task project:render` to generate the project definition\"\n\n### Environment Preflight (before asking to run migration)\n\n! Before asking the user \"Would you like me to run `task migrate:vbrief` now?\", run an environment preflight and report the results to the user. Do NOT ask the yes/no prompt until preflight results have been reported. Each failing check must be surfaced with a specific fix pointer so the user (or agent) can resolve the blocker before approving the run.\n\nRun these four checks, in order:\n\n1. **Document-model confirmation** -- re-apply the Detection Criteria above (the executable source is `scripts/_precutover.py`). If `SPECIFICATION.md` is a current generated spec export from `vbrief/specification.vbrief.json` and all lifecycle folders exist, stop: migration is NOT needed and MUST NOT be run.\n2. **Task resolvability** -- check whether `task migrate:vbrief` is dispatchable from the project root:\n - Run `task --list` (or platform-equivalent) and grep the output for a line containing `migrate:vbrief`.\n - If present: the primary command works from the project root -- canonical invocation is `task migrate:vbrief`.\n - If absent: the consumer `Taskfile.yml` does not include `deft/Taskfile.yml`. Fall back to the explicit-taskfile invocation `task -t ./deft/Taskfile.yml migrate:vbrief` and tell the user: \"`task migrate:vbrief` is not resolvable from the project root. I will use the fallback invocation `task -t ./deft/Taskfile.yml migrate:vbrief`, which reads the task directly from the framework Taskfile. To make the primary command work in future, add an include for `deft/Taskfile.yml` to your project `Taskfile.yml` — see `deft/main.md` § Publishing deft tasks in your project root.\"\n3. **`uv` on PATH** -- the migrator runs `uv run python scripts/migrate_vbrief.py`. Check `uv --version` (or equivalent): if it fails, point the user at the uv install docs (`https://docs.astral.sh/uv/`) and stop; migration cannot run without `uv`.\n4. **Migration script present** -- check `deft/scripts/migrate_vbrief.py` exists on disk. If absent, the `deft/` checkout is incomplete or came from a pre-v0.20 framework version; point the user at `deft/QUICK-START.md` (framework refresh guidance) and stop.\n\n! Report each preflight check's result to the user (e.g. \"✓ task migrate:vbrief resolvable\", \"✗ uv not on PATH — install from https://docs.astral.sh/uv/\") BEFORE prompting for yes/no approval. If any check fails, do NOT offer to run migration until it is resolved.\n\n⊗ Skip preflight and immediately ask \"Would you like me to run `task migrate:vbrief` now?\" -- preflight catches preventable errors (unresolvable task, missing `uv`, missing script) before the user commits to running migration.\n⊗ Propose an install-step mutation that writes `migrate:vbrief` content into the consumer Taskfile. The supported publish mechanism is the `includes: deft: deft/Taskfile.yml` pattern documented in `deft/main.md` § Publishing deft tasks in your project root; inline Taskfile mutation is explicitly out of scope (per #506 D6).\n\n### Prompt and Run\n\n! After preflight results are reported (and all checks pass), ask the user: \"Would you like me to run `task migrate:vbrief` now?\"\n- If yes: run the migration command (use the fallback invocation `task -t ./deft/Taskfile.yml migrate:vbrief` if the preflight resolvability check found the primary task unresolvable). Then re-run the pre-cutover detection guard to verify clean state before proceeding.\n- If no: stop and let the user handle migration manually.\n\n⊗ Proceed with setup phases when pre-cutover artifacts are detected -- always redirect to migration first.\n⊗ Silently ignore pre-cutover artifacts -- the user must be informed with an actionable command to fix the state.\n⊗ Display the migration diagnostic without offering to run it -- always ask the user if they want the agent to handle it (after preflight has passed).\n\n### Greenfield Projects (No Migration Needed)\n\n! For new projects (no existing `SPECIFICATION.md`, `PROJECT.md`, or `vbrief/specification.vbrief.json`), the guard passes silently and setup proceeds normally.\n\n! Greenfield setup creates the full vBRIEF-centric structure from scratch:\n\n1. `./vbrief/` directory with all 5 lifecycle subdirectories: `proposed/`, `pending/`, `active/`, `completed/`, `cancelled/`\n2. `./vbrief/PROJECT-DEFINITION.vbrief.json` generated from Phase 2 interview results\n3. First scope vBRIEF created in `proposed/` or `pending/` depending on Phase 3 interview outcome\n\n~ This is already handled by Phase 2 Output Path (creates `./vbrief/` and lifecycle subfolders) and Phase 3 Output (creates scope vBRIEFs in lifecycle folders). The guard ensures migrating projects are redirected before reaching these phases.\n\n### Migration safety flags\n\n`task migrate:vbrief` is destructive by default (it replaces `SPECIFICATION.md` and `PROJECT.md` with redirect stubs and rewrites `vbrief/`), but it carries four always-on / on-demand safety affordances so operators can preview, recover, and undo (#497, #506 D7). Agents offering to run migration MUST mention these and pick the right one for the operator's situation.\n\n- ! **Automatic `.premigrate.*` backups (always-on, no flag)**: before any destructive write the migrator copies every pre-cutover input to its `.premigrate` sibling -- `SPECIFICATION.md` -> `SPECIFICATION.premigrate.md`, `PROJECT.md` -> `PROJECT.premigrate.md`, `ROADMAP.md` -> `ROADMAP.premigrate.md`, `PRD.md` -> `PRD.premigrate.md` (only if present), and `vbrief/specification.vbrief.json` -> `vbrief/specification.premigrate.vbrief.json`. Each backup emits a `BACKUP <src> -> <dst> (<N> bytes)` line in the migration output. These files are `.gitignore`d by default so they do not leak into commits; operators who want them versioned can remove the patterns.\n- ! **`task migrate:vbrief -- --dry-run` (preview)**: prints the complete migration plan (every proposed backup, lifecycle folder, narrative ingestion, scope vBRIEF, and deprecation-redirect replacement) prefixed `DRYRUN` without writing any file. Exits 0 on success. Use this before running migration for the first time on an unfamiliar project.\n- ! **Dirty-tree guard (always-on)**: if `git status --porcelain` is non-empty the migrator refuses to run and points the operator at `--force`. Keeps migration output separable from in-progress edits. Bypass with `task migrate:vbrief -- --force` only after confirming the operator has accepted the risk.\n- ! **`task migrate:vbrief -- --rollback`**: restores every pre-cutover input from its `.premigrate.*` backup and removes the scope vBRIEFs and migration-report files a prior run created. Reads `vbrief/migration/safety-manifest.json` (written by the migrator). Refuses if any redirect stub has been edited since migration -- re-run with `--force` to overwrite those edits on purpose, or commit them before rolling back. Prompts for a yes/no confirmation unless `--force` is passed.\n\n! When a user declines an in-flight migration or reports an incorrect result, offer `task migrate:vbrief -- --rollback` before asking them to edit files by hand.\n\n⊗ Offer `task migrate:vbrief` without also telling the user about `--dry-run` when they sound hesitant -- previewing is free and catches reconciliation surprises that would otherwise land in a commit.\n⊗ Suggest `git reset --hard` or manual file deletion as a recovery path when `--rollback` would do the right thing more safely.\n\n## Deterministic Questions Contract\n\n! Every numbered-menu prompt rendered in this skill (Phase 1 depth question, Phase 2 project type / deployment / language / strategy / branching gates, Phase 3 onboarding question, end-of-phase transition prompts, post-interview confirmation gate) MUST follow [`../../contracts/deterministic-questions.md`](../../contracts/deterministic-questions.md): render the canonical numbered menu in chat unless the host UI visibly preserves numeric option labels and returns numeric selections or exact displayed option text. The final two numbered options MUST be `Discuss` and `Back`, in that order. The Discuss-pause semantic is documented verbatim there -- on `Discuss` selection the agent MUST halt the in-progress sequence immediately, prompt `What would you like to discuss?`, and resume only on an explicit user signal (re-asks original question, says `resume`/`continue`, or re-issues prior selection). Implicit resumption is forbidden. Fallback chat replies MUST map only to the displayed number or exact displayed option text; do not infer from alphabetic host affordances.\n\n## Platform Detection\n\n! Before resolving any config paths, detect the host OS from your environment context:\n\n| Platform | USER.md default path |\n|--------------------|-------------------------------------------------------------------|\n| Windows | `%APPDATA%\\deft\\USER.md` (e.g. `C:\\Users\\{user}\\AppData\\Roaming\\deft\\USER.md`) |\n| Unix (macOS/Linux) | `~/.config/deft/USER.md` |\n\n- ! If `$DEFT_USER_PATH` is set, it takes precedence on any platform\n- ! Create parent directories as needed when writing USER.md\n- ~ `$DEFT_PROJECT_PATH` overrides the default project config path (`./vbrief/PROJECT-DEFINITION.vbrief.json`) if set\n\n## Agent Behavior\n\n**Flow:**\n- ! Start asking immediately — everything you need is in THIS file\n- ⊗ Explore the codebase, read framework files, or gather context before asking\n- ? Read `deft/main.md` or language files LATER when generating output\n\n**Interaction:**\n- ~ Use structured question tools only when their visible option labels preserve the canonical numbers (for example, `1. Yes`) and their return value is the numeric selection or exact displayed option text.\n- ! Fall back to the numbered chat menu when the host UI may replace numbers with alphabetic affordances, unlabeled buttons, or any other non-canonical choice labels.\n- ⊗ Infer deterministic answers from host-added letters or shortcuts unless those letters were actually displayed in the canonical menu labels.\n\n**Defaults:**\n- ! Communicate that deft ships with best-in-class standards for 20+ languages\n- ! Frame setup as \"tell me your overrides\" — not \"configure everything\"\n- ~ \"Deft has solid opinions on how code should be written and tested — I just need a few things about you and your project.\"\n\n**Adapt to Technical Level:**\n- ! First question gauges whether user is technical or non-technical\n- ! Technical user: ask about languages, strategy, coverage directly — they'll have opinions\n- ! Non-technical user: skip jargon, use sensible defaults, ask about what they're building not how\n- ⊗ Ask non-technical users about coverage thresholds, strategies, or framework choices\n\n## Available Languages\n\nC, C++, C#, Dart, Delphi, Elixir, Go, Java, JavaScript, Julia, Kotlin,\nOffice.js (Excel JavaScript API), Python, R, Rust, SQL, Swift, TypeScript,\nVBA (Excel macros), VHDL, Visual Basic (.NET), Zig, 6502-DASM\n\n- ? Read `deft/languages/{name}.md` when generating output — not before asking\n\n## Available Strategies\n\n~ When presenting strategies to the user, always use this numbered list format (not a plain table).\n~ Always include the chaining note below the list.\n! Always show the FULL strategy list at every chaining gate — never remove a strategy because it was previously run.\n~ If a strategy has been run already, indicate it with a note e.g. `(run 1x)` but keep it selectable.\n\n1. **interview** ★ (recommended) — Structured interview with sizing gate: Light or Full path\n2. **yolo** — Auto-pilot interview — Johnbot picks all recommended options\n3. **map** — Analyze existing codebase conventions before adding features\n4. **discuss** — Front-load decisions and alignment before planning\n5. **probe** — Adversarially stress-test the plan; surface assumptions, edge cases, and risks before spec\n6. **research** — Investigate the domain before planning\n7. **speckit** — Five-phase spec-driven workflow for large/complex projects\n\n> 💡 Strategies can be chained — after one completes, you'll be asked if you want to run another.\n\n---\n\n## Phase 1 — User Preferences (USER.md)\n\n**Goal:** Personal preferences file with two sections:\n- **Personal** — always wins over everything (name, custom rules)\n- **Defaults** — fallback values that PROJECT-DEFINITION.vbrief.json can override (strategy, coverage)\n\n- ~ Skip if USER.md exists at the platform-appropriate path (see Platform Detection) and user doesn't want to overwrite\n- ⊗ Scan filesystem beyond checking that one path\n\n### USER.md Freshness Detection\n\n! When an existing USER.md is found (returning user), check its `deft_version` field before skipping Phase 1:\n\n1. ! If `deft_version` is **missing**: the USER.md predates versioning -- treat as stale\n2. ! If `deft_version` is present but **differs from the current framework version** (0.20.0): check whether any expected fields are missing from the USER.md\n3. ! If fields are missing: query the user for each missing field individually -- do NOT re-run the full Phase 1 interview\n4. ! After completing any field queries (even if none were needed), write the current `deft_version` (0.20.0) to USER.md\n5. ~ If `deft_version` matches the current version and all expected fields are present: no action needed (USER.md is fresh)\n\nExpected USER.md fields: **Name**, **Custom Rules**, **Default Strategy**, and optionally **Coverage** and **Experimental Rules**.\n\n⊗ Re-run the full Phase 1 interview when only individual fields are missing from a stale USER.md -- query missing fields individually instead.\n\n### Interview Rules\n\n! This phase follows the deterministic interview loop defined in `skills/deft-directive-interview/SKILL.md`. The core rules (one question per turn, numbered options with stated default, explicit \"other\" escape, depth gate, default acceptance, confirmation gate, structured handoff) apply here. Key points repeated for emphasis:\n\n! **Each message you send MUST contain exactly ONE question.** This is the most\nimportant rule in this file. After the user answers, send the NEXT question in\na new message. Repeat until all questions for their track are answered.\n\n- ⊗ Include two or more questions in the same message under any circumstances\n- ⊗ List upcoming questions — only show the current one\n- ~ Provide numbered answer options with an \"other\" choice where appropriate\n- ! Mark which option is RECOMMENDED when showing choices\n- ~ Use structured question tools only when visible option labels preserve the canonical numbers and returns map to numeric selections or exact displayed option text.\n\n### Question Sequence\n\n**Step 0 — Opening (all users):**\nAsk: \"How deep do you want to go?\"\n 1. I'm technical — ask me everything\n 2. I have some opinions but keep it simple\n 3. Just pick good defaults — I care about the product, not the tools\n\nWait for answer. Then follow the track below.\n\n**Track 1 (technical) — 7 steps:**\n- Step 1: Ask their name\n- Step 2: Ask strategy preference (show Available Strategies numbered list from the Available Strategies section, with descriptions and recommended marker; fallback — projects can override)\n- Step 3: Ask coverage threshold (default 85%; fallback — projects can override)\n- Step 4: Ask for custom rules — if user has rules, collect them one per line (empty line to finish); if none, skip\n- Step 5a: Present SOUL.md and ask whether to include it (default: yes):\n > **SOUL.md** — Results-first agent persona (inspired by Winston Wolf). Enforces assess-before-acting,\n > finish-what-you-start, right-tool-for-the-job, and play-the-long-game. Keeps the AI decisive and\n > concise. Includes a named persona ('Vinston') — drop if you prefer to define your own agent personality.\n > Include SOUL.md? (Y/n)\n- Step 5b: Present morals.md and ask whether to include it (default: yes):\n > **morals.md** — Epistemic honesty rules. No presenting speculation as fact, label unverified claims,\n > self-correct when wrong. Foundational trust rules for any AI agent. Strongly recommended.\n > Include morals.md? (Y/n)\n- Step 5c: Present code-field.md and ask whether to include it (default: yes):\n > **code-field.md** — Pre-code assumption protocol. Requires stating assumptions and naming failure modes\n > before writing a single line. Fights the 'it compiles, ship it' instinct. Based on NeoVertex1 context-field.\n > Include code-field.md? (Y/n)\n\n**Track 2 (middle ground) — 2 steps:**\n- Step 1: Ask their name\n- Step 2: Ask for custom rules — if user has rules, collect them one per line (empty line to finish); if none, skip\n- Set defaults without asking: strategy = \"interview\", coverage = 85%, all meta-guidelines included\n\n**Track 3 (non-technical) — 2 steps:**\n- Step 1: Ask their name\n- Step 2: Ask what they're building (brief description — used for PROJECT-DEFINITION.vbrief.json later)\n- Set defaults: strategy = \"interview\", coverage = 85%, all meta-guidelines included\n\n### Output Path\n\nResolve using Platform Detection above. Write to the platform-appropriate path\n(or `$DEFT_USER_PATH` if set). Create parent directories as needed.\n\n### Template\n\n```markdown\n# User Preferences\n\nLegend (from RFC2119): !=MUST, ~=SHOULD, ≉=SHOULD NOT, ⊗=MUST NOT, ?=MAY.\n\n**deft_version**: 0.20.0\n\n## Personal (always wins)\n\nSettings in this section have HIGHEST precedence — override all other deft rules,\nincluding PROJECT-DEFINITION.vbrief.json.\n\n**Name**: Address the user as: **{name}**\n\n**Custom Rules**:\n{custom rules or \"No custom rules defined yet.\"}\n\n## Defaults (fallback)\n\nSettings in this section are fallback defaults. PROJECT-DEFINITION.vbrief.json overrides these\nfor project-scoped settings (strategy, coverage).\n\n**Default Strategy**: [{strategy name}](../strategies/{strategy-file}.md)\n\n{If coverage != 85: \"**Coverage**: ! ≥{N}% test coverage\"}\n\n{If any experimental rules selected:\n\"## Experimental Rules\n\n{one line per selected rule, e.g.:\n- ! Use meta/SOUL.md for strategic context and purpose-driven guidance\n- ! Use meta/morals.md for ethical AI development principles\n- ~ Use meta/code-field.md for advanced architecture patterns}\"}\n\n---\n\n**Note**: Edit this file anytime to update your preferences.\n**See**: [../../main.md](../../../main.md) for framework defaults.\n```\n\n### Then\n\n- ! Emit a structured-tool question asking whether to continue to Phase 2 (project configuration) only when the host preserves numeric labels; otherwise emit the deterministic numbered menu in chat. Options: `1. Yes (continue)`, `2. Not now (exit setup)`, `3. Discuss`, `4. Back (revisit previous phase)`. The numeric labels MUST remain visible and be returned as numeric selections or exact displayed option text.\n- ⊗ Ask the phase-transition question as unnumbered conversational prose or through a structured UI that hides the canonical numeric labels -- it is a deterministic menu and MUST preserve visible numbers (#478, #1563).\n\n---\n\n## Phase 2 — Project Configuration (PROJECT-DEFINITION.vbrief.json)\n\n**Goal:** Project-specific configuration — tech stack, type, quality standards — written as a vBRIEF file at `./vbrief/PROJECT-DEFINITION.vbrief.json`.\n\n! **Path Resolution Anchor**: Resolve ALL paths relative to the user's working directory (pwd) at skill entry -- never relative to the skill file location, AGENTS.md location, or any framework directory (e.g. `./deft/`). When deft is cloned as a subdirectory, the skill file lives inside the clone but all project artifacts (`./vbrief/PROJECT-DEFINITION.vbrief.json`, build files, etc.) must be resolved from the user's pwd.\n\n- ~ Skip if `./vbrief/PROJECT-DEFINITION.vbrief.json` exists (or `$DEFT_PROJECT_PATH` if set) and user doesn't want to replace\n- ⊗ Count `./deft/PROJECT-DEFINITION.vbrief.json` or `./deft/core/project.md` as the user's project config — those are framework-internal\n\n### Inference\n\n- ! Before asking, infer from codebase — look for `package.json`, `go.mod`, `requirements.txt`, `Cargo.toml`, `pyproject.toml`, `*.csproj`\n- ! Use inferences to pre-fill answers and confirm — don't ask blind\n- ⊗ Look inside `./deft/` for build files (`go.mod`, `package.json`, `pyproject.toml`, `Cargo.toml`, `*.csproj`, etc.) — those are framework-internal. Only inspect files at the project root and its non-`deft` subdirectories.\n- ⊗ Run git commands inside `./deft/` to determine project identity — that directory is the framework repo, not the user's project.\n- ~ If no build files are found at the project root, default the project name to the current directory name and ask for confirmation.\n\n### Track Detection\n\n! If Phase 1 was skipped (USER.md already existed), the user's track is unknown.\nBefore asking any Phase 2 questions, ask the depth question:\n\n> \"How deep do you want to go?\"\n> 1. I'm technical — ask me everything\n> 2. I have some opinions but keep it simple\n> 3. Just pick good defaults — I care about the product, not the tools\n\nWait for answer. Then follow the corresponding track in the Question Sequence below.\n\n⊗ Assume Track 1 (technical) because USER.md exists or contains strategy/coverage fields.\n⊗ Infer the track from USER.md content — always ask.\n\n### Defaults in Agentic Mode\n\n! When a question has a USER.md default, phrase it as:\n> \"{Field}: **{value}** from USER.md — keep this, or enter a different value?\"\n\n! Accept any affirmative response (\"keep\", \"yes\", \"same\", \"default\", ✓) as confirmation to use the default.\n⊗ Phrase defaults as \"press Enter to keep\" — there is no Enter in conversational mode.\n\n### Interview Rules (same as Phase 1)\n\n! **Each message MUST contain exactly ONE question.** The Phase 1 interview rules\napply here too. Do not combine questions. See `skills/deft-directive-interview/SKILL.md` for the canonical deterministic interview loop.\n\n### Question Sequence\n\n**Track 1 (technical) — 8 steps:**\n- Step 1: Ask project name (infer from build files or directory name, confirm)\n- Step 2: Ask project type (CLI, TUI, Desktop App, REST API, Web App, Library, other)\n- Step 3: Ask deployment platform:\n 1. Cross-platform (Linux / macOS / Windows)\n 2. Windows-native\n 3. macOS-native\n 4. Linux / Unix\n 5. Embedded / low-resource\n 6. Web / Cloud\n 7. Mobile (iOS / Android)\n 8. Other / not sure\n- Step 4: Ask languages — show a filtered shortlist (3–4 recommendations) based on project type + platform. If codebase markers exist (`go.mod`, `pyproject.toml`, etc.), skip and confirm: \"Detected {lang} — correct?\"\n - If user selects \"Other\": show remaining plausible languages for the type+platform context (Tier 2)\n - If still not found: free text input (Tier 3)\n - If entered language has no deft `languages/{lang}.md` standards file, warn: \"deft doesn't have a standards file for {lang} yet — general defaults will be used. Continue?\"\n- Step 5: Ask tech stack (frameworks, libraries)\n- Step 6: Ask strategy (default to USER.md Defaults; ask if this project needs different — show Available Strategies numbered list with descriptions and recommended marker)\n- Step 7: Ask coverage (default to USER.md Defaults; ask if this project needs different)\n- Step 8: Ask for project-specific rules (optional, same one-per-line format as Phase 1 custom rules)\n- Step 9: Ask branching preference (typed `plan.policy.allowDirectCommitsToMaster` flag per #746):\n\n ! Render this as a deterministic numbered menu. Default `1. Branch-based`. Final two options MUST be `Discuss` and `Back` per [`../../contracts/deterministic-questions.md`](../../contracts/deterministic-questions.md):\n\n > \"Do you prefer branch-based workflow (create a feature branch for every change) or\n > trunk-based (commit directly to master)? Branch-based is the default and recommended\n > for teams; trunk-based is common for solo projects.\"\n > 1. Branch-based ★ (recommended -- default; enforces feature branches via the deft branch-protection policy)\n > 2. Trunk-based (direct commits to master) -- see capability-cost disclosure below\n > 3. Discuss\n > 4. Back\n\n ! **Capability-cost disclosure (#746):** When the user picks option 2 (trunk-based), the agent MUST present the capability-cost disclosure verbatim BEFORE writing the typed flag, then re-prompt for explicit confirmation:\n\n > \"Capability-cost disclosure -- enabling direct commits to the default branch turns OFF the deft branch-protection policy. The pre-commit + pre-push hooks will no longer block default-branch commits, `task verify:branch` will pass on the default branch, and the skill-level guards in deft-directive-{swarm,review-cycle,pre-pr,release} will not halt for default-branch work. The change is reversible (`task policy:enforce-branches`) and is recorded to meta/policy-changes.log for auditability. The CI sanity check (head_ref != base_ref) remains independent and will continue to flag master->master PRs. Are you sure?\"\n > 1. Yes, opt out -- write `plan.policy.allowDirectCommitsToMaster = true`\n > 2. No, keep branch-protection enforced -- write `plan.policy.allowDirectCommitsToMaster = false`\n > 3. Discuss\n > 4. Back\n\n ! Default to option 2 (enforce). Explicit affirmative on option 1 is required to opt out -- a broad `proceed` does NOT satisfy this gate. The same affirmative-only rule applies as in `/deft:change` (`yes`, `confirmed`, `approve`).\n\n ! Write the answer to `plan.policy.allowDirectCommitsToMaster` (typed boolean) on the PROJECT-DEFINITION vBRIEF. Default `false` (enforce branches) when the user picks option 2 OR omits the question entirely. Writing this typed surface is what the framework reads going forward; agents MUST NOT write the legacy free-form `Allow direct commits to master:` narrative key (#746 part A migrates the legacy narrative away).\n\n ! **Re-running the interview detects the existing flag (#746 part G2):** If `vbrief/PROJECT-DEFINITION.vbrief.json` already exists and has `plan.policy.allowDirectCommitsToMaster` set, the interview MUST surface the current value (e.g. \"Current setting: `allowDirectCommitsToMaster=false` (branch-protection ON)\") and ask whether to keep it or change it before re-prompting. Do not silently overwrite an existing typed value.\n\n ! **Slash-command alternatives (#746 part G2):** Once the project is set up, the typed flag can also be flipped via slash commands wrapping `task policy:*`:\n - `/deft:policy:show` -- display the current resolved policy and source\n - `/deft:policy:enforce-branches` -- set `allowDirectCommitsToMaster=false`\n - `/deft:policy:allow-direct-commits` -- set `allowDirectCommitsToMaster=true` (requires `--confirm` to apply)\n\n Each transition is recorded to `meta/policy-changes.log` for auditability.\n\n**Track 2 (middle ground) — 4 steps:**\n- Step 1: Ask project name (infer from build files or directory name, confirm)\n- Step 2: Ask project type (CLI, TUI, Desktop App, REST API, Web App, Library, other)\n- Step 3: Ask languages (show detected, confirm or adjust; if none detected, infer from type and ask)\n- Step 4: Ask strategy (default to USER.md Defaults; ask if this project needs different — show Available Strategies numbered list with descriptions and recommended marker)\n- Default coverage to USER.md Defaults without asking\n\n**Track 3 (non-technical) — 1 step:**\n- Step 1: Present summary of inferences: \"Based on your project: {name} ({type}), built with {stack}. Look right?\"\n- ⊗ Ask about strategy or coverage — use Phase 1 defaults\n\n### Output Path\n\n`./vbrief/PROJECT-DEFINITION.vbrief.json` (or `$DEFT_PROJECT_PATH` if set). Create `./vbrief/` directory and lifecycle subfolders (`proposed/`, `pending/`, `active/`, `completed/`, `cancelled/`) if they don't exist.\n\n### GitHub PR Template Scaffolding (#531)\n\n! Before writing `PROJECT-DEFINITION.vbrief.json`, offer to scaffold a default GitHub PR template so downstream skills (`deft-directive-refinement` Pre-Flight, `deft-directive-pre-pr`) can satisfy their `.github/PULL_REQUEST_TEMPLATE.md` checks without blocking.\n\n1. ! Ask the user with a deterministic numbered menu: \"Create a default GitHub PR template at `.github/PULL_REQUEST_TEMPLATE.md`?\" Options: `1. Yes`, `2. No`, `3. Discuss`, `4. Back`. Use a structured question tool only if those numeric labels remain visible and are returned as numeric selections or exact displayed option text.\n2. ! If the user accepts AND `.github/PULL_REQUEST_TEMPLATE.md` does NOT already exist: copy `templates/PULL_REQUEST_TEMPLATE.md` (shipped with deft) to `./.github/PULL_REQUEST_TEMPLATE.md` in the consumer project. Create `.github/` if it does not exist.\n3. ! If the file already exists, do NOT overwrite it — report that it is present and continue.\n4. ~ If the user declines, note that `deft-directive-refinement` Pre-Flight will offer to scaffold later when needed.\n\n⊗ Overwrite an existing `.github/PULL_REQUEST_TEMPLATE.md` without explicit user approval.\n\n### Headless Coverage Warning — display-bound GUI entry points (#1027)\n\n! The trigger is a **display-bound GUI event loop** (pygame, tkinter, PyQt/PySide, Kivy, Electron) that cannot run without a real display — typically a **Desktop App** project type, or a TUI that embeds such a GUI. Terminal-UI frameworks (textual, urwid, blessed, ncurses) run in the terminal and DO support headless testing (e.g. textual's `App.run_async()` + `Pilot`), so a standard TUI is NOT in scope — do not omit its coverage. The concrete commands below assume a **Python** GUI stack (pygame/tkinter); the same \"omit the un-runnable loop, test the logic\" principle applies to non-Python desktop stacks (Electron/JS, .NET/WPF, Qt/C++) using that language's own headless-test and coverage-exclusion tooling. When the Phase 2 project type resolves to a display-bound GUI project, warn the user BEFORE writing `PROJECT-DEFINITION.vbrief.json` (adapt the wording to the project's language):\n\n> \"Heads up: pygame/tkinter event loops can't be tested headlessly, so the display-bound entry point (e.g. `src/ui.py`) reports near-zero coverage and drags the overall percentage below the 85% threshold. I recommend excluding the UI entry point from coverage measurement and keeping it thin — push testable logic (state, scoring, input handling) into separate modules.\"\n\n! When scaffolding or advising on `pyproject.toml` for a display-bound GUI project, add the display-bound entry point to `[tool.coverage.run] omit` so `task check` measures logic modules only:\n\n```toml\n[tool.coverage.run]\nomit = [\n \"*/tests/*\",\n \"*/venv/*\",\n \"*/.venv/*\",\n \"src/ui.py\", # display-bound pygame/tkinter event loop -- cannot run headlessly (#1027)\n]\n```\n\n- ! Keep the omit narrow — exclude only the event-loop shell, never a module that also holds business logic. If logic and the loop are mixed, recommend refactoring the logic into a separate, fully-tested module first.\n- ~ For a Python project, point the user at `languages/python.md` (the `Headless GUI / event-loop testing` section under Patterns) for the headless-test pattern (`SDL_VIDEODRIVER=dummy`) and the full coverage-omit rationale; for a non-Python GUI stack, apply the same principle with that language's headless-test and coverage-exclusion tooling.\n- ⊗ Apply the omit to a headless-capable terminal-UI project (textual/urwid/blessed/ncurses) — those frameworks test headlessly, so omitting them hides measurable coverage, the opposite of the intended effect.\n- ⊗ Silently accept the default 85% coverage gate for a display-bound GUI project without surfacing the headless blind spot — the agent reports an inflated per-session coverage that collapses when the full `src/` is measured (the 2026-05-10 tic-tac-toe desktop-UI swarm recurrence).\n\n### Template\n\n! The output MUST conform to the canonical vBRIEF v0.6 schema (`vbrief/schemas/vbrief-core.schema.json`, strict `const: \"0.6\"`). See [`../../conventions/references.md`](../../conventions/references.md).\n\n```json\n{\n \"vBRIEFInfo\": {\n \"version\": \"0.6\",\n \"author\": \"agent:deft-directive-setup\",\n \"description\": \"Project identity gestalt\",\n \"created\": \"{ISO-8601 timestamp}\"\n },\n \"plan\": {\n \"title\": \"{Project Name}\",\n \"status\": \"running\",\n \"narratives\": {\n \"Overview\": \"{Brief project description}\",\n \"TechStack\": \"{project type} using {languages} — {tech stack details}\",\n \"Strategy\": \"Use {strategy name} for this project\",\n \"Quality\": \"Run task check before every commit. Achieve >= {coverage}% coverage overall + per-module. Store secrets in secrets/ dir.\",\n \"ProjectRules\": \"{Any rules the user specified, or 'No project-specific rules defined.'}\",\n \"Branching\": \"{If trunk-based: 'Allow direct commits to master: true', else omit or 'Branch-based workflow (default)'}\",\n \"DeftVersion\": \"0.20.0\"\n },\n \"items\": []\n }\n}\n```\n\n- ! All `narratives` values MUST be plain strings — never objects or arrays\n- ! `items` starts empty — populated as scope vBRIEFs are created in lifecycle folders\n\n### Then\n\n- ! Emit a structured-tool question asking whether to continue to Phase 3 (specification) only when the host preserves numeric labels; otherwise emit the deterministic numbered menu in chat. Options: `1. Yes (continue)`, `2. Not now (exit setup)`, `3. Discuss`, `4. Back (revisit previous phase)`. The numeric labels MUST remain visible and be returned as numeric selections or exact displayed option text.\n- ⊗ Ask the phase-transition question as unnumbered conversational prose or through a structured UI that hides the canonical numeric labels -- it is a deterministic menu and MUST preserve visible numbers (#478, #1563).\n\n### Follow-up: triage onboarding (#1143)\n\n- ~ After Phase 2 writes `PROJECT-DEFINITION.vbrief.json`, recommend `task triage:welcome` to the user as the single chained command for picking up the v0.27 triage surface. The N3 ritual (#1143) is the consolidating onboarding step for the #1119 governance swarm verbs (`task triage:bootstrap` / `task triage:scope` / `plan.policy.wipCap` writes / `task scope:demote --batch` relief / `task triage:summary`); without it consumers must learn each verb individually from the v0.27 release notes.\n- ~ `task triage:welcome` is idempotent and detection-bound -- each phase emits an informational stderr line and skips when its precondition is already satisfied, so a re-run after a partial completion resumes cleanly. The destructive phases (subscription / `wipCap` writes, optional WIP-relief invocation) are gated by numbered-menu prompts per [`../../contracts/deterministic-questions.md`](../../contracts/deterministic-questions.md). See [`../../UPGRADING.md`](../../UPGRADING.md) `## From v0.26.x -> v0.27` for the full walkthrough.\n- ? The recommendation is informational, not a hard gate -- consumers who plan to wire triage manually MAY skip the ritual and call the individual verbs in any order; the framework defaults stay fail-open per the umbrella `#1119 §12 framework-vs-consumer-config boundary`.\n\n---\n\n## Phase 3 — Specification\n\n**Goal:** Generate an implementable spec using the strategy chosen in Phase 2, producing scope vBRIEFs in `vbrief/proposed/` and PROJECT-DEFINITION narratives for human approval — greenfield v0.20 does not create `specification.vbrief.json`.\n\n! **Path Resolution Anchor**: Same rule as Phase 2 -- resolve ALL paths relative to the user's pwd at skill entry, never relative to the skill file, AGENTS.md, or any framework directory.\n\n- ~ Skip if user already has scope vBRIEFs in `./vbrief/` they're happy with\n- ! Check `./vbrief/specification.vbrief.json` or `./vbrief/proposed/` for existing scope vBRIEFs\n- ⊗ Count ANY file inside `./deft/` as the project's spec — those are framework-internal\n (e.g. `deft/PROJECT.md`, `deft/specs/`, `deft/templates/`, `deft/core/project.md`\n are all part of the framework, NOT the user's project)\n\n### Onboarding Question\n\n! Before proceeding with the strategy gate, ask the onboarding question:\n\n> \"Are you adding a scope to this project or starting a new specification?\"\n> 1. Adding scope to existing project [default if `./vbrief/specification.vbrief.json` exists or scope vBRIEFs found in lifecycle folders]\n> 2. Starting a new project specification [default if no specification or scope vBRIEFs exist]\n\n- ! Default based on repo state: if specification.vbrief.json exists or any lifecycle folder has scope vBRIEFs, default to \"Adding scope\"; otherwise default to \"Starting new\"\n- ! If adding scope: skip the full interview, create a new scope vBRIEF in `./vbrief/proposed/` with the user's description, then exit\n- ! If starting new: proceed to the Strategy Gate below\n\n### ⚠️ MANDATORY: Strategy Gate — Do This First\n\n! **STOP.** You MUST determine the correct strategy before doing anything else.\n\n1. ! Open `./vbrief/PROJECT-DEFINITION.vbrief.json` (the file written in Phase 2)\n2. ! Find the `narratives.Strategy` value\n3. ! Extract the strategy name from the narrative\n\n**Dispatch:**\n\n- **interview** (or default) → Continue to the Sizing Gate below ✅\n- **anything else** (discuss, yolo, speckit, research, brownfield, map, etc.) →\n 1. ! Read `deft/strategies/{strategy-name}.md` **right now, in this same turn**\n 2. ! Begin the strategy's workflow immediately — ask its first question\n 3. ! **STOP reading this section** — do NOT use the interview process below\n\n- ⊗ Default to interview without reading PROJECT-DEFINITION.vbrief.json\n- ⊗ Continue reading below when PROJECT-DEFINITION.vbrief.json specifies a non-interview strategy\n- ⊗ Assume interview because the sections below describe the interview process\n- ⊗ Fabricate justification for using interview when the user chose a different strategy\n- ⊗ Announce the strategy choice and then stop — you must immediately read the file and start\n\n---\n\n*⬇️ Everything below applies ONLY to the interview strategy. If your strategy is anything else, STOP — follow your strategy file instead.*\n\n### Sizing Gate (interview and yolo strategies only)\n\n! After hearing what the user wants to build and their feature list, determine\nproject complexity per [strategies/interview.md](../../strategies/interview.md#sizing-gate).\n\n- ! Check `PROJECT-DEFINITION.vbrief.json` narratives for `Light` or `Full` — if declared, use that path\n- ! If not declared, propose a size and **ask the user to confirm in a dedicated message**\n- ! **Wait for the user's response** before asking any interview questions\n- ⊗ Combine the sizing proposal with the first interview question\n- ⊗ Proceed to interview questions before the user has confirmed the path\n\n**Light** (small/medium): Interview → `specification.vbrief.json` with slim narratives (Overview + Architecture) → scope vBRIEFs in `vbrief/proposed/`.\n**Full** (large/complex): Interview → rich narratives in `specification.vbrief.json` (user approval) → scope vBRIEFs with traceability.\n\n### Interview Process (interview strategy)\n\nPer [strategies/interview.md](../../strategies/interview.md#interview-rules-shared-by-both-paths):\n\n- ! Ask what to build and features first\n- ! Ask **ONE** focused, non-trivial question per step\n- ~ Provide numbered options with an \"other\" choice\n- ! Mark which option is RECOMMENDED\n- ⊗ Ask multiple questions at once\n- ⊗ Make assumptions without clarifying\n- ~ Use structured question tools for interview questions only when they preserve visible numeric option labels and return numeric selections or exact displayed option text; otherwise render the numbered menu in chat.\n\n**Question Areas:**\n- ! Missing decisions (language, framework, deployment)\n- ! Edge cases (errors, boundaries, failure modes)\n- ! Implementation details (architecture, patterns, libraries)\n- ! Requirements (performance, security, scalability)\n- ! UX/constraints (users, timeline, compatibility)\n- ! Tradeoffs (simplicity vs features, speed vs safety)\n\n**Non-Technical Users:**\n- ~ Adjust vocabulary: \"How do you want to store data?\" not \"What database engine?\"\n- ~ \"Will other apps talk to this?\" not \"REST or GraphQL?\"\n\n**Completion:**\n- ! Continue until little ambiguity remains\n- ! Spec must be comprehensive enough to implement\n\n### Output — Light Path\n\n1. ! Write `./vbrief/specification.vbrief.json` with `\"vBRIEFInfo\": { \"version\": \"0.6\" }`, `status: draft`, and slim narratives:\n - `Overview`: Brief project summary\n - `Architecture`: System design description\n2. ! Create scope vBRIEFs in `./vbrief/proposed/` for each identified work item\n - Each scope vBRIEF follows the `YYYY-MM-DD-descriptive-slug.vbrief.json` filename convention (slug rules in [`../../conventions/vbrief-filenames.md`](../../conventions/vbrief-filenames.md))\n - Each MUST use `\"vBRIEFInfo\": { \"version\": \"0.6\" }`\n - Each MUST include embedded Requirements (FR-N, NFR-N) in its `narrative`\n - Each task SHOULD reference which FR/NFR it implements via `narrative.Traces`\n - When the scope originates from a GitHub issue, include a `references` entry in the canonical form (see [`../../conventions/references.md`](../../conventions/references.md)):\n ```json\n \"references\": [\n {\n \"uri\": \"https://github.com/{owner}/{repo}/issues/{N}\",\n \"type\": \"x-vbrief/github-issue\",\n \"title\": \"Issue #{N}: {issue title}\"\n }\n ]\n ```\n3. ! Summarize decisions, ask user to review the vBRIEF narratives\n4. ! On approval, update `specification.vbrief.json` status to `approved`\n- ⊗ Create a separate PRD.md on the Light path\n- ⊗ Generate an authoritative PRD.md — if needed, users run `task prd:render`\n\n! The vBRIEF files MUST conform to `vbrief/schemas/vbrief-core.schema.json` (v0.6):\n\n- ! All `narratives` and `narrative` values MUST be plain strings — never objects or arrays\n- ! Nested children within a PlanItem use `items` (v0.6 preferred field); `subItems` is the deprecated legacy alias kept for backward compatibility only\n- ⊗ Mix `items` and `subItems` on the same PlanItem — pick one (prefer `items`)\n\n### Output — Full Path\n\n1. ! Write rich narratives to `./vbrief/specification.vbrief.json` with `\"vBRIEFInfo\": { \"version\": \"0.6\" }`, `plan.status: draft`, and these narrative keys:\n - `ProblemStatement`: What problem this project solves\n - `Goals`: High-level project goals\n - `UserStories`: User stories in standard format\n - `Requirements`: Structured requirements (FR-N: ..., NFR-N: ...)\n - `SuccessMetrics`: Measurable success criteria\n - `Architecture`: System design and technical architecture\n - `Overview`: Brief project summary\n2. ! **Human approval gate**: Present the vBRIEF draft narratives to the user for review — reviewing the `specification.vbrief.json` narratives IS the approval step (replaces the former PRD.md review). The user may request changes before approving.\n3. ! On approval, update `status` to `approved` and proceed to downstream generation\n4. ! Create scope vBRIEFs in `./vbrief/proposed/` with traceability to requirement IDs from the narratives\n- ! Scope vBRIEFs MUST trace tasks back to requirement IDs (FR-1, NFR-1) from the `Requirements` narrative\n- ⊗ Generate an authoritative PRD.md — if needed, users run `task prd:render`\n\n**Spec Structure (both paths):**\n- ! Overview, Architecture\n- ! Implementation Plan: scope vBRIEFs in `vbrief/proposed/` with phases and dependencies\n- ! Explicit dependency mapping between scopes (via vBRIEF `edges` or `references`)\n- ~ Scopes designed for parallel work by multiple agents\n- ! Testing Strategy and Deployment captured in narratives\n- ⊗ Write code — specification only\n\n### Lifecycle Bridge to Downstream Skills (#1025)\n\n! Scope vBRIEFs created by Phase 3 (both Light and Full paths) AND by the Onboarding Question \"Adding scope to existing project\" branch land in `vbrief/proposed/` with `plan.status: proposed`. This is the canonical deposit point per the deft lifecycle (`proposed -> pending -> active -> completed`). The #810 implementation-intent gate (`task vbrief:preflight`) and the deft-directive-swarm Phase 0 Step 1 preflight BOTH require candidate vBRIEFs to live in `vbrief/active/` with `plan.status == \"running\"` before any agent can dispatch against them; setup deliberately stops at `proposed/` because the lifecycle commitment (promote + activate) belongs to the downstream skill, not the setup interview.\n\n! Surface this bridge to the user in the Phase 3 → next-skill handoff so they are not surprised by a wholesale preflight rejection downstream:\n\n - **If the next step is `skills/deft-directive-swarm/SKILL.md`**: the swarm skill's Phase 0 Step 0.5 (Lifecycle Bridge -- Promote and Activate Proposed Scope vBRIEFs) is the canonical bridge. The monitor will scan `vbrief/proposed/` and `vbrief/pending/`, present in-scope candidates, and run `task scope:promote -- <path>` then `task scope:activate -- <path>` on explicit user approval. No manual operator action is required ahead of the swarm invocation.\n - **If the next step is `skills/deft-directive-refinement/SKILL.md`**: the refinement skill's Phase 4 (Promote/Demote) owns the same `task scope:promote` / `task scope:activate` surface and runs the bridge as part of the refinement loop. The refinement skill MAY leave vBRIEFs in `pending/` deliberately when they are queued for prioritisation rather than immediate dispatch.\n - **If the user wants to invoke an implementation agent directly via `skills/deft-directive-build/SKILL.md` or `start_agent`**: the bridge MUST be run manually before dispatch -- `task scope:promote -- vbrief/proposed/<file>` then `task scope:activate -- vbrief/pending/<file>`. Both commands are idempotent and exit 0 on no-op (see `scripts/scope_lifecycle.py`). The #810 preflight gate (`task vbrief:preflight -- <active-path>`) will exit 0 only after the activate step.\n\n⊗ Auto-run `task scope:promote` or `task scope:activate` from the setup skill on the Phase 3 outputs. The lifecycle commitment belongs to the user (\"I am ready to swarm/build on this scope\"), not the setup interview; silent promotion would clear the #810 implementation-intent gate without explicit user authorisation and bypass the deterministic-questions contract that protects every other Phase 3 transition.\n\n⊗ Drop the user at the end of Phase 3 with scope vBRIEFs in `vbrief/proposed/` and no forward pointer to the bridge. Without this section the user discovers the gap at runtime when the swarm Phase 0 Step 1 preflight rejects every candidate (`Invalid transition: 'activate' requires file in pending/`), as in the originating 2026-05-10 first-session consumer tic-tac-toe swarm (issue #1025).\n\n### End-of-Phase-3 Export Prompt (project:export-spec)\n\n! After scope vBRIEFs are written to `vbrief/proposed/` and PROJECT-DEFINITION is populated, but BEFORE handing off to `deft-directive-build` (or advancing speckit Phase 3 → Phase 4), ask the user whether to generate human-readable exports. Greenfield v0.20 projects export via `task project:export-spec` (not legacy `task spec:render`). This replaces the invisible skip-if-absent behavior of `task check` (#398), closes the greenfield gap (#433), and is the Phase 3 → Phase 4 transition gate required by [strategies/speckit.md Post-Phase 3 Transition Gate](../../strategies/speckit.md#post-phase-3-transition-gate-export-for-review) (#432 / #2013).\n\n1. ! Prompt: \"Your scope vBRIEFs are ready. Generate a stakeholder-facing spec export and/or `PRD.md` now? (recommended for stakeholder review)\"\n 1. Yes — export spec (+ PRD if selected)\n 2. Spec export only (`SPECIFICATION.md`)\n 3. `PRD.md` only\n 4. Skip — I'll export later with `task project:export-spec` / `task prd:render`\n2. ! Run the selected export command(s):\n - `task project:export-spec` → writes `SPECIFICATION.md` from PROJECT-DEFINITION + lifecycle scopes (greenfield default; stakeholder audience)\n - `task project:export-spec -- --audience=internal` → same export but includes proposed scopes under `## Scope outlook` (use for setup/speckit internal handoff when proposed scopes need visibility)\n - `task prd:render` → writes `PRD.md` (optional stakeholder review)\n - Legacy `task spec:render` — migrated trees only (when `vbrief/specification.vbrief.json` exists); do NOT use on greenfield v0.20 projects\n3. ! If the user picked a speckit-strategy project: export is **mandatory** at this boundary — invoke `task project:export-spec` (with `--audience=internal` when proposed scopes exist) even if the user declined the prompt, because speckit Phase 3 → Phase 4 is gated on **export succeeded** (exit 0), not on `specification.vbrief.json` approval.\n4. ! Confirm to the user which files were written and remind them that direct edits to `SPECIFICATION.md` / `PRD.md` are overwritten on the next export — edit vBRIEF narratives in `vbrief/proposed/` and PROJECT-DEFINITION instead.\n5. ~ If the user skipped export and is NOT on a speckit strategy, no-op and continue.\n\n⊗ Advance a speckit project to Phase 4 without a successful `task project:export-spec` at this gate — export must succeed (exit 0) for the Phase 3 transition criterion.\n⊗ Silently skip the prompt — greenfield users who never open a PR will miss the exports without it.\n⊗ Invoke legacy `task spec:render` on a greenfield v0.20 project — use `task project:export-spec` instead (#2013).\n\n### Handoff to deft-directive-build\n\n- ! Emit a structured-tool question asking whether to continue to the build phase only when the host preserves numeric labels; otherwise emit the deterministic numbered menu in chat. Options: `1. Yes (continue)`, `2. Not now (exit setup)`, `3. Discuss`, `4. Back (revisit previous phase)`. The numeric labels MUST remain visible and be returned as numeric selections or exact displayed option text.\n- ~ If platform supports skill invocation and the user picks Yes, invoke `skills/deft-directive-build/SKILL.md`\n- ⊗ Leave user with a dead end -- always offer the next step via the structured-tool phase-transition question\n- ⊗ Ask the handoff-to-build question as unnumbered conversational prose or through a structured UI that hides the canonical numeric labels -- it is a deterministic menu and MUST preserve visible numbers (#478, #1563).\n\n## Warp Auto-Approve Warning\n\n! **Recommended Warp setting**: Before running deft-directive-setup, ensure Warp's AI autonomy is set to **\"Always ask\"** in **AI -> Profile Settings**. When set to a higher autonomy level (e.g. \"Auto-run\"), Warp may silently self-answer interview questions without user input, producing garbage USER.md/PROJECT-DEFINITION.vbrief.json with no error or warning. The post-interview confirmation gate (below) is the last line of defense, but prevention is better than detection.\n\n## Post-Interview Confirmation Gate\n\n! After completing ALL interview questions for any phase (Phase 1, Phase 2, or Phase 3), but BEFORE writing any files:\n\n1. ! Display a **summary of all captured values** in a clearly formatted list -- include every field that will be written to the output file (e.g. name, strategy, coverage, languages, project type, custom rules, etc.)\n2. ! Ask the user for explicit confirmation: \"These are the values I captured. Write files? (yes/no)\"\n3. ! Accept only explicit affirmative responses (`yes`, `confirmed`, `approve`) -- reject vague responses (`proceed`, `do it`, `go ahead`) the same way `/deft:change` does\n4. ! If the user says `no`: re-display the values and ask which ones to correct, then re-confirm before writing\n5. ! If any value appears to be auto-generated filler (e.g. repeated default text, placeholder strings, or values that echo the question prompt), warn the user explicitly: \"Some values look like they may have been auto-filled rather than provided by you. Please review carefully.\"\n\n⊗ Write USER.md, PROJECT-DEFINITION.vbrief.json, specification.vbrief.json, or any other deft-directive-setup artifact without first displaying captured values and receiving explicit user confirmation.\n⊗ Treat a broad \"proceed\" or \"continue\" as confirmation to write files -- the user must explicitly confirm the displayed values.\n\n? **Yolo strategy carve-out**: When the user's chosen strategy is `yolo` (auto-pilot), the confirmation gate still applies but the agent (Johnbot) may self-confirm on the user's behalf by displaying the summary and immediately proceeding -- the user has already opted into auto-pilot by selecting yolo. The summary must still be displayed so the user can interrupt if values look wrong.\n\n## Anti-Patterns\n\n- ! When deft-directive-setup generates or updates USER.md or PROJECT-DEFINITION.vbrief.json, the `deft_version` field MUST be set to the current framework version\n- ⊗ Generate a USER.md or PROJECT-DEFINITION.vbrief.json without including the `deft_version` field\n- ⊗ Explore codebase before Phase 1 questions\n- ⊗ Read framework files before first question\n- ⊗ Batch multiple questions into one message — ask one at a time, interview style\n- ⊗ Ask jargon-heavy questions to non-technical users\n- ⊗ Ask about things inferable from codebase (Phase 2+)\n- ⊗ Skip phases without asking\n- ⊗ Generate files without confirming content\n- ⊗ Present choices through a host UI that replaces the canonical numbers with alphabetic affordances or unlabeled buttons\n- ⊗ Resolve paths relative to the skill file, AGENTS.md, or framework directory instead of the user's pwd at skill entry\n- ⊗ Generate an authoritative PRD.md — PRD.md is a read-only export via `task prd:render`, never a source of truth\n",
206
+ "body": "# Deft Directive Setup\n\nAgent-driven alternative to `.deft/core/run bootstrap && .deft/core/run project && .deft/core/run spec`.\n\nLegend (from RFC2119): !=MUST, ~=SHOULD, ≉=SHOULD NOT, ⊗=MUST NOT, ?=MAY.\n\n## When to Use\n\n- User says \"set up deft\", \"configure deft\", or \"bootstrap my project\"\n- User asks to create USER.md, PROJECT-DEFINITION.vbrief.json, or a specification\n- User clones a deft-enabled repo for the first time with no config\n\n## Pre-Cutover Detection Guard\n\n! Before proceeding with any setup phase, detect whether the project uses the pre-v0.20 document model and redirect to migration if so.\n\n### Detection Criteria\n\nA project is **pre-cutover** if ANY of the following are true. This prose mirrors the executable helper in `scripts/_precutover.py`; when in doubt, the helper is canonical.\n\n1. `SPECIFICATION.md` exists and is neither a deprecation redirect nor a current generated spec export. A current generated spec export contains `<!-- Purpose: rendered specification -->` and `<!-- Source of truth: vbrief/specification.vbrief.json -->`, and `vbrief/specification.vbrief.json` plus all five lifecycle folders exist.\n2. `PROJECT.md` exists and contains neither the legacy `<!-- deft:deprecated-redirect -->` sentinel NOR the current `Purpose: deprecation redirect` canonical-banner marker (same one-release-cycle grace window).\n3. `vbrief/specification.vbrief.json` exists but the lifecycle folders (`vbrief/proposed/`, `vbrief/pending/`, `vbrief/active/`, `vbrief/completed/`, `vbrief/cancelled/`) do NOT exist\n\n### Action on Detection\n\n! If pre-cutover state is detected, **stop immediately** and display an actionable message pointing at the frozen-release migration path (#2068):\n\n> \"This project uses the pre-v0.20 document model. Current npm releases no longer ship in-product `task migrate:vbrief`. Follow UPGRADING.md § Frozen pre-v0.20 document-model migration: pin framework v0.59.0 (frozen Go installer or git tag), install Python 3.11+ and uv, run `task migrate:vbrief` once from that payload, then upgrade to current npm.\"\n\n! Include specific details about what was detected:\n\n- Missing lifecycle folders: \"Create lifecycle folders via the frozen-release migrator on v0.59.0, or manually add `vbrief/{proposed,pending,active,completed,cancelled}/` after migrating narratives\"\n- `SPECIFICATION.md` with real content: \"SPECIFICATION.md contains non-redirect content — migrate on pinned v0.59.0 before upgrading to current npm\"\n- `PROJECT.md` with real content: \"PROJECT.md contains non-redirect content — migrate on pinned v0.59.0 before upgrading to current npm\"\n- Missing `PROJECT-DEFINITION.vbrief.json`: \"Run `task project:render` after document-model migration completes\"\n\n### Preflight (optional diagnostic)\n\n~ Run `task migrate:preflight` to confirm pre-cutover state and print the frozen-release guidance. It does **not** run migration.\n\n⊗ Offer to run `task migrate:vbrief` from the current npm deposit — the migrator is not bundled on current releases (#2068).\n⊗ Proceed with setup phases when pre-cutover artifacts are detected — always redirect to the frozen migration path first.\n⊗ Silently ignore pre-cutover artifacts — the user must be informed with an actionable command to fix the state.\n\n### Greenfield Projects (No Migration Needed)\n\n! For new projects (no existing `SPECIFICATION.md`, `PROJECT.md`, or `vbrief/specification.vbrief.json`), the guard passes silently and setup proceeds normally.\n\n! Greenfield setup creates the full vBRIEF-centric structure from scratch:\n\n1. `./vbrief/` directory with all 5 lifecycle subdirectories: `proposed/`, `pending/`, `active/`, `completed/`, `cancelled/`\n2. `./vbrief/PROJECT-DEFINITION.vbrief.json` generated from Phase 2 interview results\n3. First scope vBRIEF created in `proposed/` or `pending/` depending on Phase 3 interview outcome\n\n~ This is already handled by Phase 2 Output Path (creates `./vbrief/` and lifecycle subfolders) and Phase 3 Output (creates scope vBRIEFs in lifecycle folders). The guard ensures migrating projects are redirected before reaching these phases.\n\n### Migration safety flags (frozen v0.59.0 release only)\n\nWhen guiding an operator through migration on the pinned release, mention the migrator safety affordances (#497, #506 D7):\n\n- **`task migrate:vbrief -- --dry-run` (preview)** on v0.59.0\n- **Dirty-tree guard** — migrator refuses when the working tree is dirty unless `--force`\n- **`task migrate:vbrief -- --rollback`** on v0.59.0 to restore `.premigrate.*` backups\n\n⊗ Offer in-product migration from a current npm deposit — use the frozen path (#2068).\n\n## Deterministic Questions Contract\n\n! Every numbered-menu prompt rendered in this skill (Phase 1 depth question, Phase 2 project type / deployment / language / strategy / branching gates, Phase 3 onboarding question, end-of-phase transition prompts, post-interview confirmation gate) MUST follow [`../../contracts/deterministic-questions.md`](../../contracts/deterministic-questions.md): render the canonical numbered menu in chat unless the host UI visibly preserves numeric option labels and returns numeric selections or exact displayed option text. The final two numbered options MUST be `Discuss` and `Back`, in that order. The Discuss-pause semantic is documented verbatim there -- on `Discuss` selection the agent MUST halt the in-progress sequence immediately, prompt `What would you like to discuss?`, and resume only on an explicit user signal (re-asks original question, says `resume`/`continue`, or re-issues prior selection). Implicit resumption is forbidden. Fallback chat replies MUST map only to the displayed number or exact displayed option text; do not infer from alphabetic host affordances.\n\n## Platform Detection\n\n! Before resolving any config paths, detect the host OS from your environment context:\n\n| Platform | USER.md default path |\n|--------------------|-------------------------------------------------------------------|\n| Windows | `%APPDATA%\\deft\\USER.md` (e.g. `C:\\Users\\{user}\\AppData\\Roaming\\deft\\USER.md`) |\n| Unix (macOS/Linux) | `~/.config/deft/USER.md` |\n\n- ! If `$DEFT_USER_PATH` is set, it takes precedence on any platform\n- ! Create parent directories as needed when writing USER.md\n- ~ `$DEFT_PROJECT_PATH` overrides the default project config path (`./vbrief/PROJECT-DEFINITION.vbrief.json`) if set\n\n## Agent Behavior\n\n**Flow:**\n- ! Start asking immediately — everything you need is in THIS file\n- ⊗ Explore the codebase, read framework files, or gather context before asking\n- ? Read `deft/main.md` or language files LATER when generating output\n\n**Interaction:**\n- ~ Use structured question tools only when their visible option labels preserve the canonical numbers (for example, `1. Yes`) and their return value is the numeric selection or exact displayed option text.\n- ! Fall back to the numbered chat menu when the host UI may replace numbers with alphabetic affordances, unlabeled buttons, or any other non-canonical choice labels.\n- ⊗ Infer deterministic answers from host-added letters or shortcuts unless those letters were actually displayed in the canonical menu labels.\n\n**Defaults:**\n- ! Communicate that deft ships with best-in-class standards for 20+ languages\n- ! Frame setup as \"tell me your overrides\" — not \"configure everything\"\n- ~ \"Deft has solid opinions on how code should be written and tested — I just need a few things about you and your project.\"\n\n**Adapt to Technical Level:**\n- ! First question gauges whether user is technical or non-technical\n- ! Technical user: ask about languages, strategy, coverage directly — they'll have opinions\n- ! Non-technical user: skip jargon, use sensible defaults, ask about what they're building not how\n- ⊗ Ask non-technical users about coverage thresholds, strategies, or framework choices\n\n## Available Languages\n\nC, C++, C#, Dart, Delphi, Elixir, Go, Java, JavaScript, Julia, Kotlin,\nOffice.js (Excel JavaScript API), Python, R, Rust, SQL, Swift, TypeScript,\nVBA (Excel macros), VHDL, Visual Basic (.NET), Zig, 6502-DASM\n\n- ? Read `deft/languages/{name}.md` when generating output — not before asking\n\n## Available Strategies\n\n~ When presenting strategies to the user, always use this numbered list format (not a plain table).\n~ Always include the chaining note below the list.\n! Always show the FULL strategy list at every chaining gate — never remove a strategy because it was previously run.\n~ If a strategy has been run already, indicate it with a note e.g. `(run 1x)` but keep it selectable.\n\n1. **interview** ★ (recommended) — Structured interview with sizing gate: Light or Full path\n2. **yolo** — Auto-pilot interview — Johnbot picks all recommended options\n3. **map** — Analyze existing codebase conventions before adding features\n4. **discuss** — Front-load decisions and alignment before planning\n5. **probe** — Adversarially stress-test the plan; surface assumptions, edge cases, and risks before spec\n6. **research** — Investigate the domain before planning\n7. **speckit** — Five-phase spec-driven workflow for large/complex projects\n\n> 💡 Strategies can be chained — after one completes, you'll be asked if you want to run another.\n\n---\n\n## Phase 1 — User Preferences (USER.md)\n\n**Goal:** Personal preferences file with two sections:\n- **Personal** — always wins over everything (name, custom rules)\n- **Defaults** — fallback values that PROJECT-DEFINITION.vbrief.json can override (strategy, coverage)\n\n- ~ Skip if USER.md exists at the platform-appropriate path (see Platform Detection) and user doesn't want to overwrite\n- ⊗ Scan filesystem beyond checking that one path\n\n### USER.md Freshness Detection\n\n! When an existing USER.md is found (returning user), check its `deft_version` field before skipping Phase 1:\n\n1. ! If `deft_version` is **missing**: the USER.md predates versioning -- treat as stale\n2. ! If `deft_version` is present but **differs from the current framework version** (0.20.0): check whether any expected fields are missing from the USER.md\n3. ! If fields are missing: query the user for each missing field individually -- do NOT re-run the full Phase 1 interview\n4. ! After completing any field queries (even if none were needed), write the current `deft_version` (0.20.0) to USER.md\n5. ~ If `deft_version` matches the current version and all expected fields are present: no action needed (USER.md is fresh)\n\nExpected USER.md fields: **Name**, **Custom Rules**, **Default Strategy**, and optionally **Coverage** and **Experimental Rules**.\n\n⊗ Re-run the full Phase 1 interview when only individual fields are missing from a stale USER.md -- query missing fields individually instead.\n\n### Interview Rules\n\n! This phase follows the deterministic interview loop defined in `skills/deft-directive-interview/SKILL.md`. The core rules (one question per turn, numbered options with stated default, explicit \"other\" escape, depth gate, default acceptance, confirmation gate, structured handoff) apply here. Key points repeated for emphasis:\n\n! **Each message you send MUST contain exactly ONE question.** This is the most\nimportant rule in this file. After the user answers, send the NEXT question in\na new message. Repeat until all questions for their track are answered.\n\n- ⊗ Include two or more questions in the same message under any circumstances\n- ⊗ List upcoming questions — only show the current one\n- ~ Provide numbered answer options with an \"other\" choice where appropriate\n- ! Mark which option is RECOMMENDED when showing choices\n- ~ Use structured question tools only when visible option labels preserve the canonical numbers and returns map to numeric selections or exact displayed option text.\n\n### Question Sequence\n\n**Step 0 — Opening (all users):**\nAsk: \"How deep do you want to go?\"\n 1. I'm technical — ask me everything\n 2. I have some opinions but keep it simple\n 3. Just pick good defaults — I care about the product, not the tools\n\nWait for answer. Then follow the track below.\n\n**Track 1 (technical) — 7 steps:**\n- Step 1: Ask their name\n- Step 2: Ask strategy preference (show Available Strategies numbered list from the Available Strategies section, with descriptions and recommended marker; fallback — projects can override)\n- Step 3: Ask coverage threshold (default 85%; fallback — projects can override)\n- Step 4: Ask for custom rules — if user has rules, collect them one per line (empty line to finish); if none, skip\n- Step 5a: Present SOUL.md and ask whether to include it (default: yes):\n > **SOUL.md** — Results-first agent persona (inspired by Winston Wolf). Enforces assess-before-acting,\n > finish-what-you-start, right-tool-for-the-job, and play-the-long-game. Keeps the AI decisive and\n > concise. Includes a named persona ('Vinston') — drop if you prefer to define your own agent personality.\n > Include SOUL.md? (Y/n)\n- Step 5b: Present morals.md and ask whether to include it (default: yes):\n > **morals.md** — Epistemic honesty rules. No presenting speculation as fact, label unverified claims,\n > self-correct when wrong. Foundational trust rules for any AI agent. Strongly recommended.\n > Include morals.md? (Y/n)\n- Step 5c: Present code-field.md and ask whether to include it (default: yes):\n > **code-field.md** — Pre-code assumption protocol. Requires stating assumptions and naming failure modes\n > before writing a single line. Fights the 'it compiles, ship it' instinct. Based on NeoVertex1 context-field.\n > Include code-field.md? (Y/n)\n\n**Track 2 (middle ground) — 2 steps:**\n- Step 1: Ask their name\n- Step 2: Ask for custom rules — if user has rules, collect them one per line (empty line to finish); if none, skip\n- Set defaults without asking: strategy = \"interview\", coverage = 85%, all meta-guidelines included\n\n**Track 3 (non-technical) — 2 steps:**\n- Step 1: Ask their name\n- Step 2: Ask what they're building (brief description — used for PROJECT-DEFINITION.vbrief.json later)\n- Set defaults: strategy = \"interview\", coverage = 85%, all meta-guidelines included\n\n### Output Path\n\nResolve using Platform Detection above. Write to the platform-appropriate path\n(or `$DEFT_USER_PATH` if set). Create parent directories as needed.\n\n### Template\n\n```markdown\n# User Preferences\n\nLegend (from RFC2119): !=MUST, ~=SHOULD, ≉=SHOULD NOT, ⊗=MUST NOT, ?=MAY.\n\n**deft_version**: 0.20.0\n\n## Personal (always wins)\n\nSettings in this section have HIGHEST precedence — override all other deft rules,\nincluding PROJECT-DEFINITION.vbrief.json.\n\n**Name**: Address the user as: **{name}**\n\n**Custom Rules**:\n{custom rules or \"No custom rules defined yet.\"}\n\n## Defaults (fallback)\n\nSettings in this section are fallback defaults. PROJECT-DEFINITION.vbrief.json overrides these\nfor project-scoped settings (strategy, coverage).\n\n**Default Strategy**: [{strategy name}](../strategies/{strategy-file}.md)\n\n{If coverage != 85: \"**Coverage**: ! ≥{N}% test coverage\"}\n\n{If any experimental rules selected:\n\"## Experimental Rules\n\n{one line per selected rule, e.g.:\n- ! Use meta/SOUL.md for strategic context and purpose-driven guidance\n- ! Use meta/morals.md for ethical AI development principles\n- ~ Use meta/code-field.md for advanced architecture patterns}\"}\n\n---\n\n**Note**: Edit this file anytime to update your preferences.\n**See**: [../../main.md](../../../main.md) for framework defaults.\n```\n\n### Then\n\n- ! Emit a structured-tool question asking whether to continue to Phase 2 (project configuration) only when the host preserves numeric labels; otherwise emit the deterministic numbered menu in chat. Options: `1. Yes (continue)`, `2. Not now (exit setup)`, `3. Discuss`, `4. Back (revisit previous phase)`. The numeric labels MUST remain visible and be returned as numeric selections or exact displayed option text.\n- ⊗ Ask the phase-transition question as unnumbered conversational prose or through a structured UI that hides the canonical numeric labels -- it is a deterministic menu and MUST preserve visible numbers (#478, #1563).\n\n---\n\n## Phase 2 — Project Configuration (PROJECT-DEFINITION.vbrief.json)\n\n**Goal:** Project-specific configuration — tech stack, type, quality standards — written as a vBRIEF file at `./vbrief/PROJECT-DEFINITION.vbrief.json`.\n\n! **Path Resolution Anchor**: Resolve ALL paths relative to the user's working directory (pwd) at skill entry -- never relative to the skill file location, AGENTS.md location, or any framework directory (e.g. `./deft/`). When deft is cloned as a subdirectory, the skill file lives inside the clone but all project artifacts (`./vbrief/PROJECT-DEFINITION.vbrief.json`, build files, etc.) must be resolved from the user's pwd.\n\n- ~ Skip if `./vbrief/PROJECT-DEFINITION.vbrief.json` exists (or `$DEFT_PROJECT_PATH` if set) and user doesn't want to replace\n- ⊗ Count `./deft/PROJECT-DEFINITION.vbrief.json` or `./deft/core/project.md` as the user's project config — those are framework-internal\n\n### Inference\n\n- ! Before asking, infer from codebase — look for `package.json`, `go.mod`, `requirements.txt`, `Cargo.toml`, `pyproject.toml`, `*.csproj`\n- ! Use inferences to pre-fill answers and confirm — don't ask blind\n- ⊗ Look inside `./deft/` for build files (`go.mod`, `package.json`, `pyproject.toml`, `Cargo.toml`, `*.csproj`, etc.) — those are framework-internal. Only inspect files at the project root and its non-`deft` subdirectories.\n- ⊗ Run git commands inside `./deft/` to determine project identity — that directory is the framework repo, not the user's project.\n- ~ If no build files are found at the project root, default the project name to the current directory name and ask for confirmation.\n\n### Track Detection\n\n! If Phase 1 was skipped (USER.md already existed), the user's track is unknown.\nBefore asking any Phase 2 questions, ask the depth question:\n\n> \"How deep do you want to go?\"\n> 1. I'm technical — ask me everything\n> 2. I have some opinions but keep it simple\n> 3. Just pick good defaults — I care about the product, not the tools\n\nWait for answer. Then follow the corresponding track in the Question Sequence below.\n\n⊗ Assume Track 1 (technical) because USER.md exists or contains strategy/coverage fields.\n⊗ Infer the track from USER.md content — always ask.\n\n### Defaults in Agentic Mode\n\n! When a question has a USER.md default, phrase it as:\n> \"{Field}: **{value}** from USER.md — keep this, or enter a different value?\"\n\n! Accept any affirmative response (\"keep\", \"yes\", \"same\", \"default\", ✓) as confirmation to use the default.\n⊗ Phrase defaults as \"press Enter to keep\" — there is no Enter in conversational mode.\n\n### Interview Rules (same as Phase 1)\n\n! **Each message MUST contain exactly ONE question.** The Phase 1 interview rules\napply here too. Do not combine questions. See `skills/deft-directive-interview/SKILL.md` for the canonical deterministic interview loop.\n\n### Question Sequence\n\n**Track 1 (technical) — 8 steps:**\n- Step 1: Ask project name (infer from build files or directory name, confirm)\n- Step 2: Ask project type (CLI, TUI, Desktop App, REST API, Web App, Library, other)\n- Step 3: Ask deployment platform:\n 1. Cross-platform (Linux / macOS / Windows)\n 2. Windows-native\n 3. macOS-native\n 4. Linux / Unix\n 5. Embedded / low-resource\n 6. Web / Cloud\n 7. Mobile (iOS / Android)\n 8. Other / not sure\n- Step 4: Ask languages — show a filtered shortlist (3–4 recommendations) based on project type + platform. If codebase markers exist (`go.mod`, `pyproject.toml`, etc.), skip and confirm: \"Detected {lang} — correct?\"\n - If user selects \"Other\": show remaining plausible languages for the type+platform context (Tier 2)\n - If still not found: free text input (Tier 3)\n - If entered language has no deft `languages/{lang}.md` standards file, warn: \"deft doesn't have a standards file for {lang} yet — general defaults will be used. Continue?\"\n- Step 5: Ask tech stack (frameworks, libraries)\n- Step 6: Ask strategy (default to USER.md Defaults; ask if this project needs different — show Available Strategies numbered list with descriptions and recommended marker)\n- Step 7: Ask coverage (default to USER.md Defaults; ask if this project needs different)\n- Step 8: Ask for project-specific rules (optional, same one-per-line format as Phase 1 custom rules)\n- Step 9: Ask branching preference (typed `plan.policy.allowDirectCommitsToMaster` flag per #746):\n\n ! Render this as a deterministic numbered menu. Default `1. Branch-based`. Final two options MUST be `Discuss` and `Back` per [`../../contracts/deterministic-questions.md`](../../contracts/deterministic-questions.md):\n\n > \"Do you prefer branch-based workflow (create a feature branch for every change) or\n > trunk-based (commit directly to master)? Branch-based is the default and recommended\n > for teams; trunk-based is common for solo projects.\"\n > 1. Branch-based ★ (recommended -- default; enforces feature branches via the deft branch-protection policy)\n > 2. Trunk-based (direct commits to master) -- see capability-cost disclosure below\n > 3. Discuss\n > 4. Back\n\n ! **Capability-cost disclosure (#746):** When the user picks option 2 (trunk-based), the agent MUST present the capability-cost disclosure verbatim BEFORE writing the typed flag, then re-prompt for explicit confirmation:\n\n > \"Capability-cost disclosure -- enabling direct commits to the default branch turns OFF the deft branch-protection policy. The pre-commit + pre-push hooks will no longer block default-branch commits, `task verify:branch` will pass on the default branch, and the skill-level guards in deft-directive-{swarm,review-cycle,pre-pr,release} will not halt for default-branch work. The change is reversible (`task policy:enforce-branches`) and is recorded to meta/policy-changes.log for auditability. The CI sanity check (head_ref != base_ref) remains independent and will continue to flag master->master PRs. Are you sure?\"\n > 1. Yes, opt out -- write `plan.policy.allowDirectCommitsToMaster = true`\n > 2. No, keep branch-protection enforced -- write `plan.policy.allowDirectCommitsToMaster = false`\n > 3. Discuss\n > 4. Back\n\n ! Default to option 2 (enforce). Explicit affirmative on option 1 is required to opt out -- a broad `proceed` does NOT satisfy this gate. The same affirmative-only rule applies as in `/deft:change` (`yes`, `confirmed`, `approve`).\n\n ! Write the answer to `plan.policy.allowDirectCommitsToMaster` (typed boolean) on the PROJECT-DEFINITION vBRIEF. Default `false` (enforce branches) when the user picks option 2 OR omits the question entirely. Writing this typed surface is what the framework reads going forward; agents MUST NOT write the legacy free-form `Allow direct commits to master:` narrative key (#746 part A migrates the legacy narrative away).\n\n ! **Re-running the interview detects the existing flag (#746 part G2):** If `vbrief/PROJECT-DEFINITION.vbrief.json` already exists and has `plan.policy.allowDirectCommitsToMaster` set, the interview MUST surface the current value (e.g. \"Current setting: `allowDirectCommitsToMaster=false` (branch-protection ON)\") and ask whether to keep it or change it before re-prompting. Do not silently overwrite an existing typed value.\n\n ! **Slash-command alternatives (#746 part G2):** Once the project is set up, the typed flag can also be flipped via slash commands wrapping `task policy:*`:\n - `/deft:policy:show` -- display the current resolved policy and source\n - `/deft:policy:enforce-branches` -- set `allowDirectCommitsToMaster=false`\n - `/deft:policy:allow-direct-commits` -- set `allowDirectCommitsToMaster=true` (requires `--confirm` to apply)\n\n Each transition is recorded to `meta/policy-changes.log` for auditability.\n\n**Track 2 (middle ground) — 4 steps:**\n- Step 1: Ask project name (infer from build files or directory name, confirm)\n- Step 2: Ask project type (CLI, TUI, Desktop App, REST API, Web App, Library, other)\n- Step 3: Ask languages (show detected, confirm or adjust; if none detected, infer from type and ask)\n- Step 4: Ask strategy (default to USER.md Defaults; ask if this project needs different — show Available Strategies numbered list with descriptions and recommended marker)\n- Default coverage to USER.md Defaults without asking\n\n**Track 3 (non-technical) — 1 step:**\n- Step 1: Present summary of inferences: \"Based on your project: {name} ({type}), built with {stack}. Look right?\"\n- ⊗ Ask about strategy or coverage — use Phase 1 defaults\n\n### Output Path\n\n`./vbrief/PROJECT-DEFINITION.vbrief.json` (or `$DEFT_PROJECT_PATH` if set). Create `./vbrief/` directory and lifecycle subfolders (`proposed/`, `pending/`, `active/`, `completed/`, `cancelled/`) if they don't exist.\n\n### GitHub PR Template Scaffolding (#531)\n\n! Before writing `PROJECT-DEFINITION.vbrief.json`, offer to scaffold a default GitHub PR template so downstream skills (`deft-directive-refinement` Pre-Flight, `deft-directive-pre-pr`) can satisfy their `.github/PULL_REQUEST_TEMPLATE.md` checks without blocking.\n\n1. ! Ask the user with a deterministic numbered menu: \"Create a default GitHub PR template at `.github/PULL_REQUEST_TEMPLATE.md`?\" Options: `1. Yes`, `2. No`, `3. Discuss`, `4. Back`. Use a structured question tool only if those numeric labels remain visible and are returned as numeric selections or exact displayed option text.\n2. ! If the user accepts AND `.github/PULL_REQUEST_TEMPLATE.md` does NOT already exist: copy `templates/PULL_REQUEST_TEMPLATE.md` (shipped with deft) to `./.github/PULL_REQUEST_TEMPLATE.md` in the consumer project. Create `.github/` if it does not exist.\n3. ! If the file already exists, do NOT overwrite it — report that it is present and continue.\n4. ~ If the user declines, note that `deft-directive-refinement` Pre-Flight will offer to scaffold later when needed.\n\n⊗ Overwrite an existing `.github/PULL_REQUEST_TEMPLATE.md` without explicit user approval.\n\n### Headless Coverage Warning — display-bound GUI entry points (#1027)\n\n! The trigger is a **display-bound GUI event loop** (pygame, tkinter, PyQt/PySide, Kivy, Electron) that cannot run without a real display — typically a **Desktop App** project type, or a TUI that embeds such a GUI. Terminal-UI frameworks (textual, urwid, blessed, ncurses) run in the terminal and DO support headless testing (e.g. textual's `App.run_async()` + `Pilot`), so a standard TUI is NOT in scope — do not omit its coverage. The concrete commands below assume a **Python** GUI stack (pygame/tkinter); the same \"omit the un-runnable loop, test the logic\" principle applies to non-Python desktop stacks (Electron/JS, .NET/WPF, Qt/C++) using that language's own headless-test and coverage-exclusion tooling. When the Phase 2 project type resolves to a display-bound GUI project, warn the user BEFORE writing `PROJECT-DEFINITION.vbrief.json` (adapt the wording to the project's language):\n\n> \"Heads up: pygame/tkinter event loops can't be tested headlessly, so the display-bound entry point (e.g. `src/ui.py`) reports near-zero coverage and drags the overall percentage below the 85% threshold. I recommend excluding the UI entry point from coverage measurement and keeping it thin — push testable logic (state, scoring, input handling) into separate modules.\"\n\n! When scaffolding or advising on `pyproject.toml` for a display-bound GUI project, add the display-bound entry point to `[tool.coverage.run] omit` so `task check` measures logic modules only:\n\n```toml\n[tool.coverage.run]\nomit = [\n \"*/tests/*\",\n \"*/venv/*\",\n \"*/.venv/*\",\n \"src/ui.py\", # display-bound pygame/tkinter event loop -- cannot run headlessly (#1027)\n]\n```\n\n- ! Keep the omit narrow — exclude only the event-loop shell, never a module that also holds business logic. If logic and the loop are mixed, recommend refactoring the logic into a separate, fully-tested module first.\n- ~ For a Python project, point the user at `languages/python.md` (the `Headless GUI / event-loop testing` section under Patterns) for the headless-test pattern (`SDL_VIDEODRIVER=dummy`) and the full coverage-omit rationale; for a non-Python GUI stack, apply the same principle with that language's headless-test and coverage-exclusion tooling.\n- ⊗ Apply the omit to a headless-capable terminal-UI project (textual/urwid/blessed/ncurses) — those frameworks test headlessly, so omitting them hides measurable coverage, the opposite of the intended effect.\n- ⊗ Silently accept the default 85% coverage gate for a display-bound GUI project without surfacing the headless blind spot — the agent reports an inflated per-session coverage that collapses when the full `src/` is measured (the 2026-05-10 tic-tac-toe desktop-UI swarm recurrence).\n\n### Template\n\n! The output MUST conform to the canonical vBRIEF v0.6 schema (`vbrief/schemas/vbrief-core.schema.json`, strict `const: \"0.6\"`). See [`../../conventions/references.md`](../../conventions/references.md).\n\n```json\n{\n \"vBRIEFInfo\": {\n \"version\": \"0.6\",\n \"author\": \"agent:deft-directive-setup\",\n \"description\": \"Project identity gestalt\",\n \"created\": \"{ISO-8601 timestamp}\"\n },\n \"plan\": {\n \"title\": \"{Project Name}\",\n \"status\": \"running\",\n \"narratives\": {\n \"Overview\": \"{Brief project description}\",\n \"TechStack\": \"{project type} using {languages} — {tech stack details}\",\n \"Strategy\": \"Use {strategy name} for this project\",\n \"Quality\": \"Run task check before every commit. Achieve >= {coverage}% coverage overall + per-module. Store secrets in secrets/ dir.\",\n \"ProjectRules\": \"{Any rules the user specified, or 'No project-specific rules defined.'}\",\n \"Branching\": \"{If trunk-based: 'Allow direct commits to master: true', else omit or 'Branch-based workflow (default)'}\",\n \"DeftVersion\": \"0.20.0\"\n },\n \"items\": []\n }\n}\n```\n\n- ! All `narratives` values MUST be plain strings — never objects or arrays\n- ! `items` starts empty — populated as scope vBRIEFs are created in lifecycle folders\n\n### Then\n\n- ! Emit a structured-tool question asking whether to continue to Phase 3 (specification) only when the host preserves numeric labels; otherwise emit the deterministic numbered menu in chat. Options: `1. Yes (continue)`, `2. Not now (exit setup)`, `3. Discuss`, `4. Back (revisit previous phase)`. The numeric labels MUST remain visible and be returned as numeric selections or exact displayed option text.\n- ⊗ Ask the phase-transition question as unnumbered conversational prose or through a structured UI that hides the canonical numeric labels -- it is a deterministic menu and MUST preserve visible numbers (#478, #1563).\n\n### Follow-up: triage onboarding (#1143)\n\n- ~ After Phase 2 writes `PROJECT-DEFINITION.vbrief.json`, recommend `task triage:welcome` to the user as the single chained command for picking up the v0.27 triage surface. The N3 ritual (#1143) is the consolidating onboarding step for the #1119 governance swarm verbs (`task triage:bootstrap` / `task triage:scope` / `plan.policy.wipCap` writes / `task scope:demote --batch` relief / `task triage:summary`); without it consumers must learn each verb individually from the v0.27 release notes.\n- ~ `task triage:welcome` is idempotent and detection-bound -- each phase emits an informational stderr line and skips when its precondition is already satisfied, so a re-run after a partial completion resumes cleanly. The destructive phases (subscription / `wipCap` writes, optional WIP-relief invocation) are gated by numbered-menu prompts per [`../../contracts/deterministic-questions.md`](../../contracts/deterministic-questions.md). See [`../../UPGRADING.md`](../../UPGRADING.md) `## From v0.26.x -> v0.27` for the full walkthrough.\n- ? The recommendation is informational, not a hard gate -- consumers who plan to wire triage manually MAY skip the ritual and call the individual verbs in any order; the framework defaults stay fail-open per the umbrella `#1119 §12 framework-vs-consumer-config boundary`.\n\n---\n\n## Phase 3 — Specification\n\n**Goal:** Generate an implementable spec using the strategy chosen in Phase 2, producing scope vBRIEFs in `vbrief/proposed/` and PROJECT-DEFINITION narratives for human approval — greenfield v0.20 does not create `specification.vbrief.json`.\n\n! **Path Resolution Anchor**: Same rule as Phase 2 -- resolve ALL paths relative to the user's pwd at skill entry, never relative to the skill file, AGENTS.md, or any framework directory.\n\n- ~ Skip if user already has scope vBRIEFs in `./vbrief/` they're happy with\n- ! Check `./vbrief/specification.vbrief.json` or `./vbrief/proposed/` for existing scope vBRIEFs\n- ⊗ Count ANY file inside `./deft/` as the project's spec — those are framework-internal\n (e.g. `deft/PROJECT.md`, `deft/specs/`, `deft/templates/`, `deft/core/project.md`\n are all part of the framework, NOT the user's project)\n\n### Onboarding Question\n\n! Before proceeding with the strategy gate, ask the onboarding question:\n\n> \"Are you adding a scope to this project or starting a new specification?\"\n> 1. Adding scope to existing project [default if `./vbrief/specification.vbrief.json` exists or scope vBRIEFs found in lifecycle folders]\n> 2. Starting a new project specification [default if no specification or scope vBRIEFs exist]\n\n- ! Default based on repo state: if specification.vbrief.json exists or any lifecycle folder has scope vBRIEFs, default to \"Adding scope\"; otherwise default to \"Starting new\"\n- ! If adding scope: skip the full interview, create a new scope vBRIEF in `./vbrief/proposed/` with the user's description, then exit\n- ! If starting new: proceed to the Strategy Gate below\n\n### ⚠️ MANDATORY: Strategy Gate — Do This First\n\n! **STOP.** You MUST determine the correct strategy before doing anything else.\n\n1. ! Open `./vbrief/PROJECT-DEFINITION.vbrief.json` (the file written in Phase 2)\n2. ! Find the `narratives.Strategy` value\n3. ! Extract the strategy name from the narrative\n\n**Dispatch:**\n\n- **interview** (or default) → Continue to the Sizing Gate below ✅\n- **anything else** (discuss, yolo, speckit, research, brownfield, map, etc.) →\n 1. ! Read `deft/strategies/{strategy-name}.md` **right now, in this same turn**\n 2. ! Begin the strategy's workflow immediately — ask its first question\n 3. ! **STOP reading this section** — do NOT use the interview process below\n\n- ⊗ Default to interview without reading PROJECT-DEFINITION.vbrief.json\n- ⊗ Continue reading below when PROJECT-DEFINITION.vbrief.json specifies a non-interview strategy\n- ⊗ Assume interview because the sections below describe the interview process\n- ⊗ Fabricate justification for using interview when the user chose a different strategy\n- ⊗ Announce the strategy choice and then stop — you must immediately read the file and start\n\n---\n\n*⬇️ Everything below applies ONLY to the interview strategy. If your strategy is anything else, STOP — follow your strategy file instead.*\n\n### Sizing Gate (interview and yolo strategies only)\n\n! After hearing what the user wants to build and their feature list, determine\nproject complexity per [strategies/interview.md](../../strategies/interview.md#sizing-gate).\n\n- ! Check `PROJECT-DEFINITION.vbrief.json` narratives for `Light` or `Full` — if declared, use that path\n- ! If not declared, propose a size and **ask the user to confirm in a dedicated message**\n- ! **Wait for the user's response** before asking any interview questions\n- ⊗ Combine the sizing proposal with the first interview question\n- ⊗ Proceed to interview questions before the user has confirmed the path\n\n**Light** (small/medium): Interview → `specification.vbrief.json` with slim narratives (Overview + Architecture) → scope vBRIEFs in `vbrief/proposed/`.\n**Full** (large/complex): Interview → rich narratives in `specification.vbrief.json` (user approval) → scope vBRIEFs with traceability.\n\n### Interview Process (interview strategy)\n\nPer [strategies/interview.md](../../strategies/interview.md#interview-rules-shared-by-both-paths):\n\n- ! Ask what to build and features first\n- ! Ask **ONE** focused, non-trivial question per step\n- ~ Provide numbered options with an \"other\" choice\n- ! Mark which option is RECOMMENDED\n- ⊗ Ask multiple questions at once\n- ⊗ Make assumptions without clarifying\n- ~ Use structured question tools for interview questions only when they preserve visible numeric option labels and return numeric selections or exact displayed option text; otherwise render the numbered menu in chat.\n\n**Question Areas:**\n- ! Missing decisions (language, framework, deployment)\n- ! Edge cases (errors, boundaries, failure modes)\n- ! Implementation details (architecture, patterns, libraries)\n- ! Requirements (performance, security, scalability)\n- ! UX/constraints (users, timeline, compatibility)\n- ! Tradeoffs (simplicity vs features, speed vs safety)\n\n**Non-Technical Users:**\n- ~ Adjust vocabulary: \"How do you want to store data?\" not \"What database engine?\"\n- ~ \"Will other apps talk to this?\" not \"REST or GraphQL?\"\n\n**Completion:**\n- ! Continue until little ambiguity remains\n- ! Spec must be comprehensive enough to implement\n\n### Output — Light Path\n\n1. ! Write `./vbrief/specification.vbrief.json` with `\"vBRIEFInfo\": { \"version\": \"0.6\" }`, `status: draft`, and slim narratives:\n - `Overview`: Brief project summary\n - `Architecture`: System design description\n2. ! Create scope vBRIEFs in `./vbrief/proposed/` for each identified work item\n - Each scope vBRIEF follows the `YYYY-MM-DD-descriptive-slug.vbrief.json` filename convention (slug rules in [`../../conventions/vbrief-filenames.md`](../../conventions/vbrief-filenames.md))\n - Each MUST use `\"vBRIEFInfo\": { \"version\": \"0.6\" }`\n - Each MUST include embedded Requirements (FR-N, NFR-N) in its `narrative`\n - Each task SHOULD reference which FR/NFR it implements via `narrative.Traces`\n - When the scope originates from a GitHub issue, include a `references` entry in the canonical form (see [`../../conventions/references.md`](../../conventions/references.md)):\n ```json\n \"references\": [\n {\n \"uri\": \"https://github.com/{owner}/{repo}/issues/{N}\",\n \"type\": \"x-vbrief/github-issue\",\n \"title\": \"Issue #{N}: {issue title}\"\n }\n ]\n ```\n3. ! Summarize decisions, ask user to review the vBRIEF narratives\n4. ! On approval, update `specification.vbrief.json` status to `approved`\n- ⊗ Create a separate PRD.md on the Light path\n- ⊗ Generate an authoritative PRD.md — if needed, users run `task prd:render`\n\n! The vBRIEF files MUST conform to `vbrief/schemas/vbrief-core.schema.json` (v0.6):\n\n- ! All `narratives` and `narrative` values MUST be plain strings — never objects or arrays\n- ! Nested children within a PlanItem use `items` (v0.6 preferred field); `subItems` is the deprecated legacy alias kept for backward compatibility only\n- ⊗ Mix `items` and `subItems` on the same PlanItem — pick one (prefer `items`)\n\n### Output — Full Path\n\n1. ! Write rich narratives to `./vbrief/specification.vbrief.json` with `\"vBRIEFInfo\": { \"version\": \"0.6\" }`, `plan.status: draft`, and these narrative keys:\n - `ProblemStatement`: What problem this project solves\n - `Goals`: High-level project goals\n - `UserStories`: User stories in standard format\n - `Requirements`: Structured requirements (FR-N: ..., NFR-N: ...)\n - `SuccessMetrics`: Measurable success criteria\n - `Architecture`: System design and technical architecture\n - `Overview`: Brief project summary\n2. ! **Human approval gate**: Present the vBRIEF draft narratives to the user for review — reviewing the `specification.vbrief.json` narratives IS the approval step (replaces the former PRD.md review). The user may request changes before approving.\n3. ! On approval, update `status` to `approved` and proceed to downstream generation\n4. ! Create scope vBRIEFs in `./vbrief/proposed/` with traceability to requirement IDs from the narratives\n- ! Scope vBRIEFs MUST trace tasks back to requirement IDs (FR-1, NFR-1) from the `Requirements` narrative\n- ⊗ Generate an authoritative PRD.md — if needed, users run `task prd:render`\n\n**Spec Structure (both paths):**\n- ! Overview, Architecture\n- ! Implementation Plan: scope vBRIEFs in `vbrief/proposed/` with phases and dependencies\n- ! Explicit dependency mapping between scopes (via vBRIEF `edges` or `references`)\n- ~ Scopes designed for parallel work by multiple agents\n- ! Testing Strategy and Deployment captured in narratives\n- ⊗ Write code — specification only\n\n### Lifecycle Bridge to Downstream Skills (#1025)\n\n! Scope vBRIEFs created by Phase 3 (both Light and Full paths) AND by the Onboarding Question \"Adding scope to existing project\" branch land in `vbrief/proposed/` with `plan.status: proposed`. This is the canonical deposit point per the deft lifecycle (`proposed -> pending -> active -> completed`). The #810 implementation-intent gate (`task vbrief:preflight`) and the deft-directive-swarm Phase 0 Step 1 preflight BOTH require candidate vBRIEFs to live in `vbrief/active/` with `plan.status == \"running\"` before any agent can dispatch against them; setup deliberately stops at `proposed/` because the lifecycle commitment (promote + activate) belongs to the downstream skill, not the setup interview.\n\n! Surface this bridge to the user in the Phase 3 → next-skill handoff so they are not surprised by a wholesale preflight rejection downstream:\n\n - **If the next step is `skills/deft-directive-swarm/SKILL.md`**: the swarm skill's Phase 0 Step 0.5 (Lifecycle Bridge -- Promote and Activate Proposed Scope vBRIEFs) is the canonical bridge. The monitor will scan `vbrief/proposed/` and `vbrief/pending/`, present in-scope candidates, and run `task scope:promote -- <path>` then `task scope:activate -- <path>` on explicit user approval. No manual operator action is required ahead of the swarm invocation.\n - **If the next step is `skills/deft-directive-refinement/SKILL.md`**: the refinement skill's Phase 4 (Promote/Demote) owns the same `task scope:promote` / `task scope:activate` surface and runs the bridge as part of the refinement loop. The refinement skill MAY leave vBRIEFs in `pending/` deliberately when they are queued for prioritisation rather than immediate dispatch.\n - **If the user wants to invoke an implementation agent directly via `skills/deft-directive-build/SKILL.md` or `start_agent`**: the bridge MUST be run manually before dispatch -- `task scope:promote -- vbrief/proposed/<file>` then `task scope:activate -- vbrief/pending/<file>`. Both commands are idempotent and exit 0 on no-op (see `scripts/scope_lifecycle.py`). The #810 preflight gate (`task vbrief:preflight -- <active-path>`) will exit 0 only after the activate step.\n\n⊗ Auto-run `task scope:promote` or `task scope:activate` from the setup skill on the Phase 3 outputs. The lifecycle commitment belongs to the user (\"I am ready to swarm/build on this scope\"), not the setup interview; silent promotion would clear the #810 implementation-intent gate without explicit user authorisation and bypass the deterministic-questions contract that protects every other Phase 3 transition.\n\n⊗ Drop the user at the end of Phase 3 with scope vBRIEFs in `vbrief/proposed/` and no forward pointer to the bridge. Without this section the user discovers the gap at runtime when the swarm Phase 0 Step 1 preflight rejects every candidate (`Invalid transition: 'activate' requires file in pending/`), as in the originating 2026-05-10 first-session consumer tic-tac-toe swarm (issue #1025).\n\n### End-of-Phase-3 Export Prompt (project:export-spec)\n\n! After scope vBRIEFs are written to `vbrief/proposed/` and PROJECT-DEFINITION is populated, but BEFORE handing off to `deft-directive-build` (or advancing speckit Phase 3 → Phase 4), ask the user whether to generate human-readable exports. Greenfield v0.20 projects export via `task project:export-spec` (not legacy `task spec:render`). This replaces the invisible skip-if-absent behavior of `task check` (#398), closes the greenfield gap (#433), and is the Phase 3 → Phase 4 transition gate required by [strategies/speckit.md Post-Phase 3 Transition Gate](../../strategies/speckit.md#post-phase-3-transition-gate-export-for-review) (#432 / #2013).\n\n1. ! Prompt: \"Your scope vBRIEFs are ready. Generate a stakeholder-facing spec export and/or `PRD.md` now? (recommended for stakeholder review)\"\n 1. Yes — export spec (+ PRD if selected)\n 2. Spec export only (`SPECIFICATION.md`)\n 3. `PRD.md` only\n 4. Skip — I'll export later with `task project:export-spec` / `task prd:render`\n2. ! Run the selected export command(s):\n - `task project:export-spec` → writes `SPECIFICATION.md` from PROJECT-DEFINITION + lifecycle scopes (greenfield default; stakeholder audience)\n - `task project:export-spec -- --audience=internal` → same export but includes proposed scopes under `## Scope outlook` (use for setup/speckit internal handoff when proposed scopes need visibility)\n - `task prd:render` → writes `PRD.md` (optional stakeholder review)\n - Legacy `task spec:render` — migrated trees only (when `vbrief/specification.vbrief.json` exists); do NOT use on greenfield v0.20 projects\n3. ! If the user picked a speckit-strategy project: export is **mandatory** at this boundary — invoke `task project:export-spec` (with `--audience=internal` when proposed scopes exist) even if the user declined the prompt, because speckit Phase 3 → Phase 4 is gated on **export succeeded** (exit 0), not on `specification.vbrief.json` approval.\n4. ! Confirm to the user which files were written and remind them that direct edits to `SPECIFICATION.md` / `PRD.md` are overwritten on the next export — edit vBRIEF narratives in `vbrief/proposed/` and PROJECT-DEFINITION instead.\n5. ~ If the user skipped export and is NOT on a speckit strategy, no-op and continue.\n\n⊗ Advance a speckit project to Phase 4 without a successful `task project:export-spec` at this gate — export must succeed (exit 0) for the Phase 3 transition criterion.\n⊗ Silently skip the prompt — greenfield users who never open a PR will miss the exports without it.\n⊗ Invoke legacy `task spec:render` on a greenfield v0.20 project — use `task project:export-spec` instead (#2013).\n\n### Handoff to deft-directive-build\n\n- ! Emit a structured-tool question asking whether to continue to the build phase only when the host preserves numeric labels; otherwise emit the deterministic numbered menu in chat. Options: `1. Yes (continue)`, `2. Not now (exit setup)`, `3. Discuss`, `4. Back (revisit previous phase)`. The numeric labels MUST remain visible and be returned as numeric selections or exact displayed option text.\n- ~ If platform supports skill invocation and the user picks Yes, invoke `skills/deft-directive-build/SKILL.md`\n- ⊗ Leave user with a dead end -- always offer the next step via the structured-tool phase-transition question\n- ⊗ Ask the handoff-to-build question as unnumbered conversational prose or through a structured UI that hides the canonical numeric labels -- it is a deterministic menu and MUST preserve visible numbers (#478, #1563).\n\n## Warp Auto-Approve Warning\n\n! **Recommended Warp setting**: Before running deft-directive-setup, ensure Warp's AI autonomy is set to **\"Always ask\"** in **AI -> Profile Settings**. When set to a higher autonomy level (e.g. \"Auto-run\"), Warp may silently self-answer interview questions without user input, producing garbage USER.md/PROJECT-DEFINITION.vbrief.json with no error or warning. The post-interview confirmation gate (below) is the last line of defense, but prevention is better than detection.\n\n## Post-Interview Confirmation Gate\n\n! After completing ALL interview questions for any phase (Phase 1, Phase 2, or Phase 3), but BEFORE writing any files:\n\n1. ! Display a **summary of all captured values** in a clearly formatted list -- include every field that will be written to the output file (e.g. name, strategy, coverage, languages, project type, custom rules, etc.)\n2. ! Ask the user for explicit confirmation: \"These are the values I captured. Write files? (yes/no)\"\n3. ! Accept only explicit affirmative responses (`yes`, `confirmed`, `approve`) -- reject vague responses (`proceed`, `do it`, `go ahead`) the same way `/deft:change` does\n4. ! If the user says `no`: re-display the values and ask which ones to correct, then re-confirm before writing\n5. ! If any value appears to be auto-generated filler (e.g. repeated default text, placeholder strings, or values that echo the question prompt), warn the user explicitly: \"Some values look like they may have been auto-filled rather than provided by you. Please review carefully.\"\n\n⊗ Write USER.md, PROJECT-DEFINITION.vbrief.json, specification.vbrief.json, or any other deft-directive-setup artifact without first displaying captured values and receiving explicit user confirmation.\n⊗ Treat a broad \"proceed\" or \"continue\" as confirmation to write files -- the user must explicitly confirm the displayed values.\n\n? **Yolo strategy carve-out**: When the user's chosen strategy is `yolo` (auto-pilot), the confirmation gate still applies but the agent (Johnbot) may self-confirm on the user's behalf by displaying the summary and immediately proceeding -- the user has already opted into auto-pilot by selecting yolo. The summary must still be displayed so the user can interrupt if values look wrong.\n\n## Anti-Patterns\n\n- ! When deft-directive-setup generates or updates USER.md or PROJECT-DEFINITION.vbrief.json, the `deft_version` field MUST be set to the current framework version\n- ⊗ Generate a USER.md or PROJECT-DEFINITION.vbrief.json without including the `deft_version` field\n- ⊗ Explore codebase before Phase 1 questions\n- ⊗ Read framework files before first question\n- ⊗ Batch multiple questions into one message — ask one at a time, interview style\n- ⊗ Ask jargon-heavy questions to non-technical users\n- ⊗ Ask about things inferable from codebase (Phase 2+)\n- ⊗ Skip phases without asking\n- ⊗ Generate files without confirming content\n- ⊗ Present choices through a host UI that replaces the canonical numbers with alphabetic affordances or unlabeled buttons\n- ⊗ Resolve paths relative to the skill file, AGENTS.md, or framework directory instead of the user's pwd at skill entry\n- ⊗ Generate an authoritative PRD.md — PRD.md is a read-only export via `task prd:render`, never a source of truth\n",
207
207
  "frontmatter_extra": null
208
208
  },
209
209
  {
@@ -231,7 +231,7 @@
231
231
  ],
232
232
  "path": "skills/deft-directive-sync/SKILL.md",
233
233
  "version": "0.1",
234
- "body": "# Deft Directive Sync\n\nSession-start framework sync -- pull latest deft submodule updates, validate vBRIEF lifecycle structure, and detect stale origins.\n\n> **Canonical bootstrap / update path (#761 npm cutover):** Install and upgrade via npm: `npm i -g @deftai/directive` (install) or `npm i -g @deftai/directive@latest` (upgrade); Node >= 20 is required. For machines without Node, the frozen legacy Go installer (`deft-install` / platform-specific `install-*` from GitHub Releases) is a no-Node bootstrap bridge (#1912) -- migrate to npm once Node is available. After a session start the canonical `scripts/doctor.py --session --json` (`deft doctor` / `task doctor`) reports install + payload state and, when the manifest sha shows the payload is stale, recommends `npm i -g @deftai/directive@latest`. Legacy `run upgrade` / `task upgrade` are metadata-only acknowledgment (they do NOT replace the payload), and git-submodule / `task framework:doctor` paths are back-compat only -- the submodule sync in Phases 1-2 below is the legacy update flow, de-emphasized in UPGRADING.md / README. See UPGRADING.md and #761 / #1912.\n\nLegend (from RFC2119): !=MUST, ~=SHOULD, ≉=SHOULD NOT, ⊗=MUST NOT, ?=MAY.\n\n## Platform Requirements\n\n! This skill requires **GitHub** as the SCM platform and the **GitHub CLI (`gh`)** to be installed and authenticated. Origin freshness checks (Phase 5) fetch issue data via `gh issue view`.\n\n## When to Use\n\n- User says \"good morning\", \"update deft\", \"update vbrief\", or \"sync frameworks\"\n- Beginning of a new session where framework updates may be available\n- After a known upstream deft release\n\n## Framework Events Emitted Here\n\n! When this skill responds to a context-window shift or an explicit \"are you using Deft?\" probe (per AGENTS.md Deft Alignment Confirmation), emit the paired `session:interrupted` -> `session:resumed` framework events via `scripts/_events.py` so observability of agent-runtime state transitions is structural, not prose-only:\n\n- ! Before re-confirming alignment: `python -m scripts._events emit session:interrupted --session-id <id> --reason context-window-shift`\n- ! Immediately after the alignment confirmation line: `python -m scripts._events emit session:resumed --session-id <id> --interrupted-id <id-from-prior-emit>`\n- ⊗ Emit a `session:resumed` whose `interrupted_id` does not reference a prior `session:interrupted` -- such records are orphan and rejected by `scripts._events.validate_pairing` (#635 events behavioral wiring)\n\n## Pre-Cutover Detection Guard\n\n! Before proceeding with sync, detect whether the project uses the pre-v0.20 document model and report model state.\n\n### Detection Criteria\n\nA project is **pre-cutover** if ANY of the following are true. This prose mirrors the executable helper in `scripts/_precutover.py`; when in doubt, the helper is canonical.\n\n1. `SPECIFICATION.md` exists and is neither a deprecation redirect nor a current generated spec export. A current generated spec export contains `<!-- Purpose: rendered specification -->` and `<!-- Source of truth: vbrief/specification.vbrief.json -->`, and `vbrief/specification.vbrief.json` plus all five lifecycle folders exist.\n2. `PROJECT.md` exists and contains neither the legacy `<!-- deft:deprecated-redirect -->` sentinel NOR the current `Purpose: deprecation redirect` canonical-banner marker (real content, not a deprecation redirect)\n3. `vbrief/specification.vbrief.json` exists but the lifecycle folders (`vbrief/proposed/`, `vbrief/pending/`, `vbrief/active/`, `vbrief/completed/`, `vbrief/cancelled/`) do NOT exist\n\n### Action on Detection\n\n! If pre-cutover state is detected, display the actionable migration message, then **skip Phases 1-6** and proceed directly to Phase 7 with the Document Model line set to \"pre-v0.20 (legacy)\":\n\n> \"This project uses the pre-v0.20 document model. Run `task migrate:vbrief` to upgrade to the vBRIEF-centric model.\"\n\n! Include specific details about what was detected:\n\n- Missing lifecycle folders: \"Run `task migrate:vbrief` to create the lifecycle folder structure\"\n- `SPECIFICATION.md` with real content: \"SPECIFICATION.md contains non-redirect content -- this file is deprecated; use scope vBRIEFs in `vbrief/` instead\"\n- `PROJECT.md` with real content: \"PROJECT.md contains non-redirect content -- this file is deprecated; use `PROJECT-DEFINITION.vbrief.json` instead\"\n- Missing `PROJECT-DEFINITION.vbrief.json`: \"Run `task project:render` to generate the project definition\"\n- Scope vBRIEF in wrong folder: \"Status is '{status}' but file is in {folder}/ -- run `task scope:activate <file>` to fix\"\n\n### Model State in Sync Output\n\n! Include a **Document Model** line in the Phase 7 summary:\n\n- Pre-cutover detected: \"**Document Model**: pre-v0.20 (legacy) -- run `task migrate:vbrief` to upgrade\"\n- Post-cutover (lifecycle folders present, no stale artifacts): \"**Document Model**: v0.20+ (vBRIEF-centric) -- OK\"\n- Post-cutover with tampered placeholders: \"**Document Model**: v0.20+ with warnings -- SPECIFICATION.md or PROJECT.md contains non-redirect content\"\n\n⊗ Skip model state detection during sync -- always report the document model state.\n⊗ Silently ignore pre-cutover artifacts -- the user must be informed with an actionable command to fix the state.\n\n## Phase 1 -- Pre-flight\n\n! Check that the deft/ submodule working tree is clean before attempting any update.\n\n1. ! Run `git -C deft status --porcelain`\n2. ! If output is non-empty (dirty working tree): **stop** and ask user whether to stash (`git -C deft stash`) or abort the sync entirely. Do NOT proceed with a dirty submodule.\n3. ! Record the current DEFT commit for later comparison:\n ```\n git -C deft log --oneline -1\n ```\n4. ! Present the current state to the user:\n - Current DEFT commit (hash + subject)\n - Clean/dirty status\n - Confirmation that pre-flight passed (or the blocker if dirty)\n\n## Phase 2 -- Update DEFT Submodule\n\n1. ! Run the submodule update:\n ```\n git submodule update --remote --merge deft\n ```\n2. ! Show what changed by comparing before/after:\n ```\n git -C deft log --oneline <old-hash>..HEAD\n ```\n3. ~ If no new commits, report \"deft submodule already up to date\" and proceed to Phase 3.\n\n## Phase 3 -- Structure Validation\n\n! Validate the vBRIEF lifecycle folder structure and project files.\n\n### 3a: Lifecycle Folder Structure\n\n! Verify all required lifecycle folders exist:\n\n1. ! Check that the following directories exist under `./vbrief/`:\n - `proposed/`\n - `pending/`\n - `active/`\n - `completed/`\n - `cancelled/`\n2. ! Report any missing folders with a clear warning:\n - \"WARNING: vbrief/{folder}/ does not exist -- lifecycle structure is incomplete\"\n3. ~ If folders are missing, suggest running `task migrate:vbrief` or creating them manually\n\n### 3b: PROJECT-DEFINITION.vbrief.json Validation\n\n! Validate the project identity gestalt file:\n\n1. ! Check that `./vbrief/PROJECT-DEFINITION.vbrief.json` exists\n - If missing: \"WARNING: PROJECT-DEFINITION.vbrief.json not found -- run `task project:render` to create\"\n2. ! If the file exists, validate it is well-formed:\n - Valid JSON (`python3 -m json.tool` or equivalent)\n - Top-level `vBRIEFInfo` envelope with `version` field equal to `\"0.6\"`\n - `plan` object with `title`, `status`, and `items` fields present\n - `plan.narratives` values are plain strings (not objects or arrays)\n3. ! **Freshness check**: Compare `vBRIEFInfo.updated` (or `vBRIEFInfo.created` if no `updated`) against recent scope completions:\n - Scan `vbrief/completed/` for vBRIEFs with `vBRIEFInfo.updated` timestamps newer than the PROJECT-DEFINITION timestamp\n - If stale: \"WARNING: PROJECT-DEFINITION.vbrief.json may be stale -- {N} scopes completed since last update. Run `task project:render` to refresh.\"\n\n### 3c: Validate Root-Level vBRIEF Files\n\n! Validate all `./vbrief/*.vbrief.json` files at the vbrief root:\n\n1. ! Check each file is valid JSON\n2. ! Verify structural conformance:\n - Top-level `vBRIEFInfo` envelope with `version` field present\n - `plan` object with `title`, `status`, and `items` fields present\n - `plan.status` values from valid enum: draft, proposed, approved, pending, running, completed, blocked, cancelled\n3. ~ Use `task vbrief:validate` if available for deeper validation\n4. ! Report any validation failures with file name and specific violation\n\n⊗ Overwrite or modify project-level `./vbrief/*.vbrief.json` files -- those are project data, not framework files. Report issues and let the user decide how to fix them.\n\n## Phase 4 -- Lifecycle Consistency Check\n\n! Verify that each scope vBRIEF's `plan.status` matches its folder location.\n\n1. ! Scan all scope vBRIEFs in lifecycle folders (`proposed/`, `pending/`, `active/`, `completed/`, `cancelled/`)\n2. ! For each vBRIEF, check `plan.status` against the expected statuses for its folder:\n - `proposed/`: status should be `draft` or `proposed`\n - `pending/`: status should be `approved` or `pending`\n - `active/`: status should be `running` or `blocked`\n - `completed/`: status should be `completed`\n - `cancelled/`: status should be `cancelled`\n3. ! Report any mismatches:\n - \"MISMATCH: {filename} in {folder}/ has status '{status}' -- expected one of [{expected_statuses}]\"\n4. ~ Per vbrief.md convention, trust the status field and suggest correcting the folder location:\n - \"Suggested fix: move {filename} to {correct_folder}/ (status '{status}' is authoritative)\"\n\n⊗ Auto-move vBRIEFs to fix folder/status mismatches -- report only; user decides during refinement or ad-hoc\n\n## Phase 5 -- Origin Freshness (RFC D12)\n\n! For vBRIEFs with external origin references, detect staleness and externally-closed origins.\n\n### Step 1: Scan Origins\n\n1. ! For each vBRIEF in `proposed/` and `pending/` with a `github-issue` reference in `plan.references` or top-level `references`:\n - Extract the issue number from the reference URL or `id` field\n - Fetch the issue: `gh issue view {N} --repo {owner/repo} --json updatedAt,state`\n2. ! Compare the issue's `updatedAt` against the vBRIEF's `vBRIEFInfo.updated` (or `vBRIEFInfo.created` if no `updated` field)\n\n### Step 2: Categorize and Report\n\n1. ! **Stale origins** -- issue `updatedAt` is newer than vBRIEF `updated` timestamp:\n - \"{N} vBRIEFs have origins updated since last sync\"\n - List each: \"{filename}: Issue #{N} updated {time_delta} ago\"\n2. ! **Externally closed origins** -- issue state is `CLOSED`:\n - \"{N} vBRIEFs have origins that were closed externally\"\n - List each: \"{filename}: Issue #{N} is closed ({close_reason})\"\n3. ~ **Current origins** -- no changes detected (report count only)\n\n### Step 3: Recommendation\n\n- ! Report only -- never auto-update vBRIEFs based on origin changes\n- ~ If stale or externally-closed vBRIEFs are found, suggest: \"Run a refinement session (`skills/deft-directive-refinement/SKILL.md`) to reconcile stale origins with user approval.\"\n\n⊗ Auto-update vBRIEFs based on origin freshness checks -- report only; user decides during refinement\n\n## Phase 6 -- Framework Sync\n\nAfter structure validation, sync framework-level assets.\n\n### 6a: Check AGENTS.md freshness\n\n~ Compare the project's `AGENTS.md` against the deft template (if a template exists in the updated `deft/` submodule):\n\n1. ~ Diff the structure (section headings, key rules) rather than expecting byte-identical content\n2. ~ Report any new sections or rules added upstream that are missing locally\n3. ~ Do NOT auto-overwrite -- present differences and let the user decide\n\n### 6b: Check codebase MAP freshness\n\n~ If `./.planning/codebase/MAP.md` exists, or `PROJECT-DEFINITION.vbrief.json` declares a `projectionManifest[]` entry with `kind: \"codebase-map\"`, run `task verify:codebase-map-fresh` when the command resolves. If it reports drift, recommend `task codebase:map` and note that the generated MAP is advisory unless the operator asked to refresh projections.\n\n- ! Keep `plan.architecture.codeStructure` and configured provider artifacts authoritative; the MAP is a generated projection.\n- ⊗ Auto-edit canonical vBRIEF metadata to make the MAP fresh during sync -- report drift and let the operator choose a follow-up.\n\n### 6c: List new skills\n\n! Compare the `skills/` directory before and after the update:\n\n1. ! List any new skill directories added in the update\n2. ~ For each new skill, read its frontmatter `description` field and present a one-liner\n3. ~ Mention if any existing skills were updated (changed files)\n\n## Phase 6d -- Legacy Artifact Review (post-migration, one-time)\n\n! If `vbrief/migration/LEGACY-REPORT.md` exists (and has NOT been renamed to `LEGACY-REPORT.reviewed.md`), walk the operator through each captured legacy section and record their disposition inline in the same file. This phase surfaces the non-canonical content that `task migrate:vbrief` preserved via the `LegacyArtifacts` narrative mechanism (#505).\n\n### Detection\n\n1. ! Check for `vbrief/migration/LEGACY-REPORT.md` in the project root.\n2. ! If the file is absent or `LEGACY-REPORT.reviewed.md` exists (reviewed form), skip Phase 6d silently and proceed to Phase 7.\n3. ! If `LEGACY-REPORT.md` is present and has NOT been renamed, begin the review loop below.\n\n### Review loop\n\n1. ! Present the report summary (sources + per-bucket section counts) to the user.\n2. ! For each captured section listed under `## specification.vbrief.json -> LegacyArtifacts`, `## PROJECT-DEFINITION.vbrief.json -> LegacyArtifacts`, and `## PRD.md content (flagged: hand-edited)`:\n - Restate the section title, source file + line range, and size.\n - Offer exactly three disposition options: **Keep** (leave inside `LegacyArtifacts`), **Fold into {suggested narrative}** (move into a canonical narrative key), or **Drop** (remove from `LegacyArtifacts`, with explicit user confirmation).\n - ~ If a sidecar pointer is present (`vbrief/legacy/{stem}-{slug}.md`), open the sidecar for the user before offering options so the full content is visible.\n3. ! Record each disposition inline in the same `LEGACY-REPORT.md` file under a new `## Reviewed` section with one entry per legacy item: original section, user's decision, target location (if folded) or confirmation note (if kept/dropped), and the reviewer's timestamp.\n4. ! For a **Fold** decision, the agent updates the target vBRIEF's narrative key AND deletes only the corresponding section from the `LegacyArtifacts` narrative -- never the file.\n5. ! For a **Drop** decision, the agent removes only the corresponding section from the `LegacyArtifacts` narrative.\n6. ! Once all sections carry a recorded disposition, rename the file to `LEGACY-REPORT.reviewed.md`. The file is kept so the audit trail remains -- ⊗ MUST NOT delete either form.\n\n### Anti-patterns\n\n- ⊗ Delete `LEGACY-REPORT.md` or `LEGACY-REPORT.reviewed.md` -- these are the migration audit trail and MUST persist.\n- ⊗ Auto-dispose of legacy artifacts without user input -- every section requires an explicit decision.\n- ⊗ Rename to `.reviewed.md` before every captured section has a recorded disposition in the `## Reviewed` section.\n- ⊗ Drop a legacy section without explicit user confirmation (even if the section looks obviously stale).\n- ⊗ Silently delete sidecar files under `vbrief/legacy/` -- they are referenced from `LegacyArtifacts` and are part of the audit trail.\n\n## Phase 7 -- Summary\n\n! Present a consolidated summary to the user covering:\n\n1. **DEFT version change**: old commit -> new commit (or \"already up to date\")\n2. **Structure validation**: lifecycle folders status (all present / missing folders listed)\n3. **PROJECT-DEFINITION status**: valid / missing / stale (with freshness details)\n4. **vBRIEF validation results**: pass/fail per file, with details on any failures\n5. **Lifecycle consistency**: all consistent / N mismatches found (with details)\n6. **Origin freshness**: N stale / N externally-closed / N current (with details)\n7. **Document Model**: pre-v0.20 (legacy) / v0.20+ (vBRIEF-centric) OK / v0.20+ with warnings (see Pre-Cutover Detection Guard)\n8. **AGENTS.md status**: current / has upstream changes / needs review\n9. **Codebase MAP status**: current / stale / absent / not configured (advisory)\n10. **New skills**: list any newly added skills with descriptions\n\n! Ask the user: \"Shall I commit the submodule update?\" -- do NOT auto-commit.\n\n? If the user confirms, commit with message:\n```\nchore(deft): update deft submodule to <short-hash>\n```\n\n## Anti-Patterns\n\n- ⊗ Auto-commit submodule changes without user approval\n- ⊗ Overwrite project-level `./vbrief/*.vbrief.json` files -- those are project data\n- ⊗ Skip the pre-flight dirty check -- a dirty submodule can cause merge conflicts or data loss\n- ⊗ Include a separate fetch of the vBRIEF schema from upstream deftai/vBRIEF -- that is a CI concern (see #128), not a user sync task\n- ⊗ Auto-move vBRIEFs to fix folder/status mismatches -- report only; never auto-fix\n- ⊗ Auto-update vBRIEFs based on origin freshness -- report only; user decides during refinement\n",
234
+ "body": "# Deft Directive Sync\n\nSession-start framework sync -- pull latest deft submodule updates, validate vBRIEF lifecycle structure, and detect stale origins.\n\n> **Canonical bootstrap / update path (#761 npm cutover):** Install and upgrade via npm: `npm i -g @deftai/directive` (install) or `npm i -g @deftai/directive@latest` (upgrade); Node >= 20 is required. For machines without Node, the frozen legacy Go installer (`deft-install` / platform-specific `install-*` from GitHub Releases) is a no-Node bootstrap bridge (#1912) -- migrate to npm once Node is available. After a session start the canonical `scripts/doctor.py --session --json` (`deft doctor` / `task doctor`) reports install + payload state and, when the manifest sha shows the payload is stale, recommends `npm i -g @deftai/directive@latest`. Legacy `run upgrade` / `task upgrade` are metadata-only acknowledgment (they do NOT replace the payload), and git-submodule / `task framework:doctor` paths are back-compat only -- the submodule sync in Phases 1-2 below is the legacy update flow, de-emphasized in UPGRADING.md / README. See UPGRADING.md and #761 / #1912.\n\nLegend (from RFC2119): !=MUST, ~=SHOULD, ≉=SHOULD NOT, ⊗=MUST NOT, ?=MAY.\n\n## Platform Requirements\n\n! This skill requires **GitHub** as the SCM platform and the **GitHub CLI (`gh`)** to be installed and authenticated. Origin freshness checks (Phase 5) fetch issue data via `gh issue view`.\n\n## When to Use\n\n- User says \"good morning\", \"update deft\", \"update vbrief\", or \"sync frameworks\"\n- Beginning of a new session where framework updates may be available\n- After a known upstream deft release\n\n## Framework Events Emitted Here\n\n! When this skill responds to a context-window shift or an explicit \"are you using Deft?\" probe (per AGENTS.md Deft Alignment Confirmation), emit the paired `session:interrupted` -> `session:resumed` framework events via `scripts/_events.py` so observability of agent-runtime state transitions is structural, not prose-only:\n\n- ! Before re-confirming alignment: `python -m scripts._events emit session:interrupted --session-id <id> --reason context-window-shift`\n- ! Immediately after the alignment confirmation line: `python -m scripts._events emit session:resumed --session-id <id> --interrupted-id <id-from-prior-emit>`\n- ⊗ Emit a `session:resumed` whose `interrupted_id` does not reference a prior `session:interrupted` -- such records are orphan and rejected by `scripts._events.validate_pairing` (#635 events behavioral wiring)\n\n## Pre-Cutover Detection Guard\n\n! Before proceeding with sync, detect whether the project uses the pre-v0.20 document model and report model state.\n\n### Detection Criteria\n\nA project is **pre-cutover** if ANY of the following are true. This prose mirrors the executable helper in `scripts/_precutover.py`; when in doubt, the helper is canonical.\n\n1. `SPECIFICATION.md` exists and is neither a deprecation redirect nor a current generated spec export. A current generated spec export contains `<!-- Purpose: rendered specification -->` and `<!-- Source of truth: vbrief/specification.vbrief.json -->`, and `vbrief/specification.vbrief.json` plus all five lifecycle folders exist.\n2. `PROJECT.md` exists and contains neither the legacy `<!-- deft:deprecated-redirect -->` sentinel NOR the current `Purpose: deprecation redirect` canonical-banner marker (real content, not a deprecation redirect)\n3. `vbrief/specification.vbrief.json` exists but the lifecycle folders (`vbrief/proposed/`, `vbrief/pending/`, `vbrief/active/`, `vbrief/completed/`, `vbrief/cancelled/`) do NOT exist\n\n### Action on Detection\n\n! If pre-cutover state is detected, display the actionable migration message, then **skip Phases 1-6** and proceed directly to Phase 7 with the Document Model line set to \"pre-v0.20 (legacy)\":\n\n> \"This project uses the pre-v0.20 document model. Current npm releases no longer ship in-product `task migrate:vbrief` (#2068). Follow UPGRADING.md § Frozen pre-v0.20 document-model migration: pin framework v0.59.0, install Python 3.11+ and uv, run `task migrate:vbrief` once from that payload, then upgrade to current npm.\"\n\n! Include specific details about what was detected:\n\n- Missing lifecycle folders: \"Create lifecycle folders via the frozen v0.59.0 migrator (#2068), or manually add `vbrief/{proposed,pending,active,completed,cancelled}/` after migrating narratives\"\n- `SPECIFICATION.md` with real content: \"SPECIFICATION.md contains non-redirect content -- this file is deprecated; use scope vBRIEFs in `vbrief/` instead\"\n- `PROJECT.md` with real content: \"PROJECT.md contains non-redirect content -- this file is deprecated; use `PROJECT-DEFINITION.vbrief.json` instead\"\n- Missing `PROJECT-DEFINITION.vbrief.json`: \"Run `task project:render` to generate the project definition\"\n- Scope vBRIEF in wrong folder: \"Status is '{status}' but file is in {folder}/ -- run `task scope:activate <file>` to fix\"\n\n### Model State in Sync Output\n\n! Include a **Document Model** line in the Phase 7 summary:\n\n- Pre-cutover detected: \"**Document Model**: pre-v0.20 (legacy) -- follow UPGRADING.md § Frozen pre-v0.20 document-model migration (#2068)\"\n- Post-cutover (lifecycle folders present, no stale artifacts): \"**Document Model**: v0.20+ (vBRIEF-centric) -- OK\"\n- Post-cutover with tampered placeholders: \"**Document Model**: v0.20+ with warnings -- SPECIFICATION.md or PROJECT.md contains non-redirect content\"\n\n⊗ Skip model state detection during sync -- always report the document model state.\n⊗ Silently ignore pre-cutover artifacts -- the user must be informed with an actionable command to fix the state.\n\n## Phase 1 -- Pre-flight\n\n! Check that the deft/ submodule working tree is clean before attempting any update.\n\n1. ! Run `git -C deft status --porcelain`\n2. ! If output is non-empty (dirty working tree): **stop** and ask user whether to stash (`git -C deft stash`) or abort the sync entirely. Do NOT proceed with a dirty submodule.\n3. ! Record the current DEFT commit for later comparison:\n ```\n git -C deft log --oneline -1\n ```\n4. ! Present the current state to the user:\n - Current DEFT commit (hash + subject)\n - Clean/dirty status\n - Confirmation that pre-flight passed (or the blocker if dirty)\n\n## Phase 2 -- Update DEFT Submodule\n\n1. ! Run the submodule update:\n ```\n git submodule update --remote --merge deft\n ```\n2. ! Show what changed by comparing before/after:\n ```\n git -C deft log --oneline <old-hash>..HEAD\n ```\n3. ~ If no new commits, report \"deft submodule already up to date\" and proceed to Phase 3.\n\n## Phase 3 -- Structure Validation\n\n! Validate the vBRIEF lifecycle folder structure and project files.\n\n### 3a: Lifecycle Folder Structure\n\n! Verify all required lifecycle folders exist:\n\n1. ! Check that the following directories exist under `./vbrief/`:\n - `proposed/`\n - `pending/`\n - `active/`\n - `completed/`\n - `cancelled/`\n2. ! Report any missing folders with a clear warning:\n - \"WARNING: vbrief/{folder}/ does not exist -- lifecycle structure is incomplete\"\n3. ~ If folders are missing, suggest `task migrate:preflight` and the frozen v0.59.0 migrator path (#2068), or creating them manually after migration\n\n### 3b: PROJECT-DEFINITION.vbrief.json Validation\n\n! Validate the project identity gestalt file:\n\n1. ! Check that `./vbrief/PROJECT-DEFINITION.vbrief.json` exists\n - If missing: \"WARNING: PROJECT-DEFINITION.vbrief.json not found -- run `task project:render` to create\"\n2. ! If the file exists, validate it is well-formed:\n - Valid JSON (`python3 -m json.tool` or equivalent)\n - Top-level `vBRIEFInfo` envelope with `version` field equal to `\"0.6\"`\n - `plan` object with `title`, `status`, and `items` fields present\n - `plan.narratives` values are plain strings (not objects or arrays)\n3. ! **Freshness check**: Compare `vBRIEFInfo.updated` (or `vBRIEFInfo.created` if no `updated`) against recent scope completions:\n - Scan `vbrief/completed/` for vBRIEFs with `vBRIEFInfo.updated` timestamps newer than the PROJECT-DEFINITION timestamp\n - If stale: \"WARNING: PROJECT-DEFINITION.vbrief.json may be stale -- {N} scopes completed since last update. Run `task project:render` to refresh.\"\n\n### 3c: Validate Root-Level vBRIEF Files\n\n! Validate all `./vbrief/*.vbrief.json` files at the vbrief root:\n\n1. ! Check each file is valid JSON\n2. ! Verify structural conformance:\n - Top-level `vBRIEFInfo` envelope with `version` field present\n - `plan` object with `title`, `status`, and `items` fields present\n - `plan.status` values from valid enum: draft, proposed, approved, pending, running, completed, blocked, cancelled\n3. ~ Use `task vbrief:validate` if available for deeper validation\n4. ! Report any validation failures with file name and specific violation\n\n⊗ Overwrite or modify project-level `./vbrief/*.vbrief.json` files -- those are project data, not framework files. Report issues and let the user decide how to fix them.\n\n## Phase 4 -- Lifecycle Consistency Check\n\n! Verify that each scope vBRIEF's `plan.status` matches its folder location.\n\n1. ! Scan all scope vBRIEFs in lifecycle folders (`proposed/`, `pending/`, `active/`, `completed/`, `cancelled/`)\n2. ! For each vBRIEF, check `plan.status` against the expected statuses for its folder:\n - `proposed/`: status should be `draft` or `proposed`\n - `pending/`: status should be `approved` or `pending`\n - `active/`: status should be `running` or `blocked`\n - `completed/`: status should be `completed`\n - `cancelled/`: status should be `cancelled`\n3. ! Report any mismatches:\n - \"MISMATCH: {filename} in {folder}/ has status '{status}' -- expected one of [{expected_statuses}]\"\n4. ~ Per vbrief.md convention, trust the status field and suggest correcting the folder location:\n - \"Suggested fix: move {filename} to {correct_folder}/ (status '{status}' is authoritative)\"\n\n⊗ Auto-move vBRIEFs to fix folder/status mismatches -- report only; user decides during refinement or ad-hoc\n\n## Phase 5 -- Origin Freshness (RFC D12)\n\n! For vBRIEFs with external origin references, detect staleness and externally-closed origins.\n\n### Step 1: Scan Origins\n\n1. ! For each vBRIEF in `proposed/` and `pending/` with a `github-issue` reference in `plan.references` or top-level `references`:\n - Extract the issue number from the reference URL or `id` field\n - Fetch the issue: `gh issue view {N} --repo {owner/repo} --json updatedAt,state`\n2. ! Compare the issue's `updatedAt` against the vBRIEF's `vBRIEFInfo.updated` (or `vBRIEFInfo.created` if no `updated` field)\n\n### Step 2: Categorize and Report\n\n1. ! **Stale origins** -- issue `updatedAt` is newer than vBRIEF `updated` timestamp:\n - \"{N} vBRIEFs have origins updated since last sync\"\n - List each: \"{filename}: Issue #{N} updated {time_delta} ago\"\n2. ! **Externally closed origins** -- issue state is `CLOSED`:\n - \"{N} vBRIEFs have origins that were closed externally\"\n - List each: \"{filename}: Issue #{N} is closed ({close_reason})\"\n3. ~ **Current origins** -- no changes detected (report count only)\n\n### Step 3: Recommendation\n\n- ! Report only -- never auto-update vBRIEFs based on origin changes\n- ~ If stale or externally-closed vBRIEFs are found, suggest: \"Run a refinement session (`skills/deft-directive-refinement/SKILL.md`) to reconcile stale origins with user approval.\"\n\n⊗ Auto-update vBRIEFs based on origin freshness checks -- report only; user decides during refinement\n\n## Phase 6 -- Framework Sync\n\nAfter structure validation, sync framework-level assets.\n\n### 6a: Check AGENTS.md freshness\n\n~ Compare the project's `AGENTS.md` against the deft template (if a template exists in the updated `deft/` submodule):\n\n1. ~ Diff the structure (section headings, key rules) rather than expecting byte-identical content\n2. ~ Report any new sections or rules added upstream that are missing locally\n3. ~ Do NOT auto-overwrite -- present differences and let the user decide\n\n### 6b: Check codebase MAP freshness\n\n~ If `./.planning/codebase/MAP.md` exists, or `PROJECT-DEFINITION.vbrief.json` declares a `projectionManifest[]` entry with `kind: \"codebase-map\"`, run `task verify:codebase-map-fresh` when the command resolves. If it reports drift, recommend `task codebase:map` and note that the generated MAP is advisory unless the operator asked to refresh projections.\n\n- ! Keep `plan.architecture.codeStructure` and configured provider artifacts authoritative; the MAP is a generated projection.\n- ⊗ Auto-edit canonical vBRIEF metadata to make the MAP fresh during sync -- report drift and let the operator choose a follow-up.\n\n### 6c: List new skills\n\n! Compare the `skills/` directory before and after the update:\n\n1. ! List any new skill directories added in the update\n2. ~ For each new skill, read its frontmatter `description` field and present a one-liner\n3. ~ Mention if any existing skills were updated (changed files)\n\n## Phase 6d -- Legacy Artifact Review (post-migration, one-time)\n\n! If `vbrief/migration/LEGACY-REPORT.md` exists (and has NOT been renamed to `LEGACY-REPORT.reviewed.md`), walk the operator through each captured legacy section and record their disposition inline in the same file. This phase surfaces the non-canonical content that `task migrate:vbrief` preserved via the `LegacyArtifacts` narrative mechanism (#505).\n\n### Detection\n\n1. ! Check for `vbrief/migration/LEGACY-REPORT.md` in the project root.\n2. ! If the file is absent or `LEGACY-REPORT.reviewed.md` exists (reviewed form), skip Phase 6d silently and proceed to Phase 7.\n3. ! If `LEGACY-REPORT.md` is present and has NOT been renamed, begin the review loop below.\n\n### Review loop\n\n1. ! Present the report summary (sources + per-bucket section counts) to the user.\n2. ! For each captured section listed under `## specification.vbrief.json -> LegacyArtifacts`, `## PROJECT-DEFINITION.vbrief.json -> LegacyArtifacts`, and `## PRD.md content (flagged: hand-edited)`:\n - Restate the section title, source file + line range, and size.\n - Offer exactly three disposition options: **Keep** (leave inside `LegacyArtifacts`), **Fold into {suggested narrative}** (move into a canonical narrative key), or **Drop** (remove from `LegacyArtifacts`, with explicit user confirmation).\n - ~ If a sidecar pointer is present (`vbrief/legacy/{stem}-{slug}.md`), open the sidecar for the user before offering options so the full content is visible.\n3. ! Record each disposition inline in the same `LEGACY-REPORT.md` file under a new `## Reviewed` section with one entry per legacy item: original section, user's decision, target location (if folded) or confirmation note (if kept/dropped), and the reviewer's timestamp.\n4. ! For a **Fold** decision, the agent updates the target vBRIEF's narrative key AND deletes only the corresponding section from the `LegacyArtifacts` narrative -- never the file.\n5. ! For a **Drop** decision, the agent removes only the corresponding section from the `LegacyArtifacts` narrative.\n6. ! Once all sections carry a recorded disposition, rename the file to `LEGACY-REPORT.reviewed.md`. The file is kept so the audit trail remains -- ⊗ MUST NOT delete either form.\n\n### Anti-patterns\n\n- ⊗ Delete `LEGACY-REPORT.md` or `LEGACY-REPORT.reviewed.md` -- these are the migration audit trail and MUST persist.\n- ⊗ Auto-dispose of legacy artifacts without user input -- every section requires an explicit decision.\n- ⊗ Rename to `.reviewed.md` before every captured section has a recorded disposition in the `## Reviewed` section.\n- ⊗ Drop a legacy section without explicit user confirmation (even if the section looks obviously stale).\n- ⊗ Silently delete sidecar files under `vbrief/legacy/` -- they are referenced from `LegacyArtifacts` and are part of the audit trail.\n\n## Phase 7 -- Summary\n\n! Present a consolidated summary to the user covering:\n\n1. **DEFT version change**: old commit -> new commit (or \"already up to date\")\n2. **Structure validation**: lifecycle folders status (all present / missing folders listed)\n3. **PROJECT-DEFINITION status**: valid / missing / stale (with freshness details)\n4. **vBRIEF validation results**: pass/fail per file, with details on any failures\n5. **Lifecycle consistency**: all consistent / N mismatches found (with details)\n6. **Origin freshness**: N stale / N externally-closed / N current (with details)\n7. **Document Model**: pre-v0.20 (legacy) / v0.20+ (vBRIEF-centric) OK / v0.20+ with warnings (see Pre-Cutover Detection Guard)\n8. **AGENTS.md status**: current / has upstream changes / needs review\n9. **Codebase MAP status**: current / stale / absent / not configured (advisory)\n10. **New skills**: list any newly added skills with descriptions\n\n! Ask the user: \"Shall I commit the submodule update?\" -- do NOT auto-commit.\n\n? If the user confirms, commit with message:\n```\nchore(deft): update deft submodule to <short-hash>\n```\n\n## Anti-Patterns\n\n- ⊗ Auto-commit submodule changes without user approval\n- ⊗ Overwrite project-level `./vbrief/*.vbrief.json` files -- those are project data\n- ⊗ Skip the pre-flight dirty check -- a dirty submodule can cause merge conflicts or data loss\n- ⊗ Include a separate fetch of the vBRIEF schema from upstream deftai/vBRIEF -- that is a CI concern (see #128), not a user sync task\n- ⊗ Auto-move vBRIEFs to fix folder/status mismatches -- report only; never auto-fix\n- ⊗ Auto-update vBRIEFs based on origin freshness -- report only; user decides during refinement\n",
235
235
  "frontmatter_extra": "triggers:\n - good morning\n - update deft\n - update vbrief\n - sync frameworks"
236
236
  },
237
237
  {
@@ -246,7 +246,7 @@
246
246
  ],
247
247
  "path": "skills/deft-directive-triage/SKILL.md",
248
248
  "version": "0.1",
249
- "body": "# Deft Directive Triage\n\nTriage-cache hygiene + \"what's next?\" queue selection. Operates against the unified `.deft-cache/github-issue/` mirror (#883 Story 2) and the append-only `vbrief/.eval/candidates.jsonl` audit log (#845 Story 2); writes only via the canonical `task triage:*` verbs.\n\nLegend (from RFC2119): !=MUST, ~=SHOULD, ≉=SHOULD NOT, ⊗=MUST NOT, ?=MAY.\n\n## Platform Requirements\n\n! Requires **GitHub** as the SCM platform and the **GitHub CLI (`gh`)** authenticated against the active project's repo -- the cache surface (`task cache:fetch-all`) and the read-side gate (`task verify:cache-fresh`) both depend on it.\n\n## Deterministic Questions Contract\n\n! Every numbered-menu prompt rendered in this skill (Phase 2 candidate selection, Phase 3 per-item decision walk) ! MUST follow [`../../contracts/deterministic-questions.md`](../../contracts/deterministic-questions.md): render the canonical numbered menu in chat unless the host UI visibly preserves numeric option labels and returns numeric selections or exact displayed option text. The final two numbered options are `Discuss` and `Back`, in that order, and the Discuss-pause semantic from the contract applies verbatim -- on `Discuss` the agent halts the in-progress sequence and resumes only on an explicit user signal.\n\n## Phase 0 -- Sync\n\n! Probe cache freshness before doing any classification or selection. Stale cache reads produce stale decisions; the gate is the contract.\n\n1. ! Run `task verify:cache-fresh` (D5 / #1127). Exit 0 -> proceed to Phase 1. Exit 1 (stale or blocked) -> refresh per the printed remediation. Exit 2 (no bootstrap) -> run `task triage:bootstrap` first.\n2. ~ Refresh path: `task cache:fetch-all -- --source=github-issue --repo OWNER/NAME` for an already-bootstrapped project (idempotent, TTL-aware, re-applies the #883 scanner v2 quarantine rules); `task triage:bootstrap` for a first-time seed.\n3. ~ If `vbrief/active/*.vbrief.json` references are in play, run `task triage:refresh-active` to compare cached `meta.json.fetched_at` against live upstream `updatedAt` and surface drift before the queue is rendered.\n4. ~ When the one-liner emitted by the session-start ritual carries a `[scope-drift] N` segment (D14 / #1133), run `task triage:scope-drift` to see the per-label / per-milestone breakdown of upstream signals on cached open issues that fall outside the active `plan.policy.triageScope[]` subscription. The output documents both opt-in (`task triage:subscribe -- --label=<L>`) and opt-out (`task triage:scope-drift -- --ignore-label=<L>`) paths -- pick one before walking the queue so the cohort reflects the operator's current intent rather than a stale subscription.\n5. ⊗ Walk the queue against a stale cache -- the audit log will record decisions against bodies the operator never actually saw.\n\n## Phase 1 -- Classify\n\n! Inspect the auto-classification audit log so manually-decided items are not re-walked, and surface anomalies before the queue render.\n\n1. ! Run `task triage:classify --list` (D10 / #1129) to render the effective universal + consumer auto-classification rules and the active hold-marker list.\n2. ! Walk recent entries in `vbrief/.eval/candidates.jsonl` for anomalies: classifier disagreements against the operator's prior decisions, repeated `defer` cycles on the same issue, or `needs-ac` records older than the freshness window. Surface anomalies to the operator before Phase 2; do NOT auto-fix.\n3. ~ When the operator wants to widen / narrow the corpus, consult `task triage:scope --list` (D12 / #1131) to see the active `plan.policy.triageScope[]` subscription. Subscription edits belong in PROJECT-DEFINITION.vbrief.json, not in this skill.\n4. ~ Issue-label hygiene: labels feed triage queue ranking, issue gauges, hygiene sweeps, and lifecycle reconciliation. When this skill exposes an unlabeled issue or a downstream issue-creation step, recommend choosing one or more suitable labels from the repository's existing label set via `gh label list` or the labels API, or explicitly note that no label was applied. This is a recommendation, not a gate.\n5. ⊗ Re-classify items already terminally decided (accept / reject / mark-duplicate) without explicit operator approval -- the audit log is append-only and supersession runs through Layer 5 (`task triage:reset <N>`), not through silent re-walks.\n6. ⊗ Block issue creation solely because no label was selected, or invent ad hoc labels outside the repository's existing label set.\n\n## Phase 2 -- Present\n\n! Render the ranked queue before suggesting any specific issue. The cache-as-authoritative rule in AGENTS.md (`## Cache-as-authoritative work selection (#1149)`) is binding: the agent ! MUST consult `task triage:queue` and surface the result before proposing work from memory.\n\n1. ! Run `task triage:queue --limit=N` (D11 / #1128) -- default `N=10` per the umbrella Current Shape v3 WIP cap. Output is grouped `[RESUME]` -> `[URGENT]` -> untriaged -> other; within-group ordering follows the consumer-supplied `plan.policy.triageRankingLabels[]` (framework default empty per §12 boundary), tiebroken by `updated_at` descending.\n2. ! For per-item detail, run `task triage:show <N>` -- prints the cached upstream payload, the latest triage decision, the audit timeline, and the active-vBRIEF reference flag. Exit 0 on hit, 1 on cache miss (re-sync per Phase 0).\n3. ~ Present the ranked queue verbatim; do NOT silently re-rank, drop, or annotate beyond what the canonical renderer emits. If the operator wants a different ordering they edit `plan.policy.triageRankingLabels[]` and re-run.\n4. ⊗ Recommend a specific issue without consulting `task triage:queue` first, or recommend an issue absent from the queue without first running `task triage:show` to surface why (cache miss / outside subscription / terminal decision).\n\n## Phase 3 -- Decide\n\n! Walk per-item decisions through the canonical `task triage:*` verbs. The skill does NOT reimplement the audit-log append, schema validation, or `vbrief/proposed/` write inline -- the tasks are the canonical implementation (mirrors the #537 ingest-task discipline).\n\nFor each candidate the operator selects from the Phase 2 queue, render the canonical numbered action menu and dispatch the matching verb:\n\n```\nWhat would you like to do with this candidate?\n 1. Accept -- `task triage:accept <N>` (writes proposed/ vBRIEF + audit-log entry)\n 2. Reject -- `task triage:reject <N>` (audit-log entry only; terminal)\n 3. Defer -- `task triage:defer <N> [--resume-on <event>]` (non-terminal; resurfaces)\n 4. Needs-AC -- `task triage:needs-ac <N>` (non-terminal; flags missing acceptance criteria)\n 5. Mark duplicate -- `task triage:mark-duplicate <N> <of-issue>` (terminal; cross-links target)\n 6. Discuss\n 7. Back\n```\n\n- ! `--resume-on <event>` on `task triage:defer` (D3 / #1123 -- ships in parallel; reference but do not hard-depend) records a resume condition with the defer entry; the resume condition surfaces in `task triage:queue` once met. When D3 has not landed yet, omit the flag -- the verb stays terminal-shape-compatible.\n- ! Map user replies only to the displayed number (`1`-`7`) or exact displayed option text. ⊗ Do NOT infer from alphabetic host affordances or bare letters such as `d` / `b` unless those letters were visibly rendered as choices.\n- ! On `Discuss`, halt the action sequence immediately, prompt `What would you like to discuss?`, and resume only on an explicit user signal. ⊗ Implicit resumption.\n- ! On `Back`, un-buffer the prior candidate's selection and re-render its action menu -- permitted only before the action has dispatched to a `task triage:*` command. Once dispatched, the audit entry is committed; revisions go through Layer 5 (`task triage:reset`).\n- ~ Bulk patterns: `task triage:bulk-{accept,reject,defer,needs-ac}` (#845 Story 4) for clear label-driven sweeps; bulk results still flow through the audit log so history stays coherent.\n- ⊗ Write to `vbrief/proposed/` directly -- only `task triage:accept` (which delegates to `task issue:ingest`) is authorised for that surface.\n\n## Phase 4 -- Audit\n\n! Confirm the session's decisions landed coherently before exiting the skill.\n\n1. ! Run `task triage:audit --format=json` (D11 / #1128) -- emits the stable `{generated_at, repo, vbrief_staleness, entry_count, entries: [...]}` schema; pipe through `jq` to surface this session's appended entries. For historical look-back, add the #1180 filters: `task triage:audit --since=30d --action=demote --format=json | jq` answers \"how many demotes in the last 30 days?\" in one call. `--since=<window>` accepts the framework duration grammar (`Nd` / `Nh` / `Nm` / `Nw` / `Ns` or ISO-8601 `PnDTnHnMnS`); `--action=<verb>` filters to a single decision verb (`accept` / `reject` / `defer` / `needs-ac` / `mark-duplicate` / `reset` / `resume-eligible`). Both filters compose with `--format=text` and `--format=json`. The framework deliberately does NOT compute trend lines or apply falsification gates -- the contract is read raw, transform with `jq`.\n2. ! Run `task triage:summary` (D2 / #1122) -- prints the canonical one-liner `[triage] N untriaged · S stale-defer · M in-flight · WIP X/Y [⚠] [· [scope-drift] N]`. The WIP cap default is 10 per the umbrella Current Shape v3 (overridable via typed `plan.policy.wipCap`). The `⚠` glyph fires only at-or-above cap. The `[scope-drift] N` segment (D14 / #1133) appears only when at least one unsubscribed label/milestone meets the framework `_DRIFT_MIN_ISSUES = 3` threshold; suppressed at zero.\n3. ~ When the summary surfaces a non-zero `[scope-drift] N` (D14 / #1133), surface it to the operator alongside `task triage:scope-drift` output and the matching `task triage:subscribe` / `task triage:unsubscribe` / `task triage:scope-drift -- --ignore-label=<L>` remediation. Subscription mutations record a `subscription-change` audit entry under `vbrief/.eval/subscription-history.jsonl` (sidecar of the existing `candidates.jsonl` audit surface) so future operators can replay how the subscription evolved. After every mutation, run `task triage:bootstrap -- --resume` to backfill newly-subscribed entries / mark newly-out-of-scope entries.\n4. ~ When the audit surfaces a stale acceptance (`accept` decision whose issue is no longer referenced by any `vbrief/active/`), surface it to the operator -- the typical fix is a fresh ingest via `task issue:ingest -- <N>` or a `task triage:reset <N>` if the acceptance was in error.\n5. ⊗ Skip the Phase 4 audit -- silent exit leaves the operator without a record of what landed in `vbrief/proposed/` this session, which is the typical recurrence vector for \"what did I just accept?\" confusion.\n\n## Reversibility\n\n! To undo a decision, run `task triage:reset <N>`. This writes a `reset` audit entry referencing the prior decision id; history is **never** deleted. `task triage:reset` is the canonical Layer 5 reversibility verb (resolves the V3 audit from 2026-05-13). After a reset, the candidate re-enters the untriaged group on the next `task triage:queue` render so it can be re-walked through Phase 3.\n\n⊗ Edit or delete prior entries in `vbrief/.eval/candidates.jsonl` to \"undo\" a decision -- the log is append-only by design and any external mutation breaks the `merge=union` rebase ergonomic (#1144 / N4).\n\n## Anti-Patterns\n\n- ⊗ Recommend a specific issue without first consulting `task triage:queue` (binding under AGENTS.md `## Cache-as-authoritative work selection (#1149)`).\n- ⊗ Walk the queue against a stale cache (Phase 0 gate skipped).\n- ⊗ Reimplement audit-log append / `proposed/` write inline -- the `task triage:*` verbs own those surfaces (#845, #883).\n- ⊗ Treat `defer` / `needs-ac` as terminal -- they intentionally resurface on the next pass.\n- ⊗ Edit `vbrief/.eval/candidates.jsonl` directly to revoke a decision -- use `task triage:reset <N>`.\n\n## EXIT\n\n! When the operator opts out (queue exhausted, mid-session stop, or explicit \"done\"), confirm skill exit with the canonical phrasing: `deft-directive-triage complete -- exiting skill.`\n\n! Provide chaining instructions:\n\n- **Ingestion / evaluation of accepted items**: chain into `skills/deft-directive-refinement/SKILL.md` -- refinement's Phase 1 ingests the `vbrief/proposed/` items this skill just wrote into the rest of the lifecycle.\n- **Cohort dispatch**: chain into `skills/deft-directive-swarm/SKILL.md` -- swarm Phase 0 is queue-driven (N2 / #1142) and consumes the same `task triage:queue` ordering you just walked.\n- **Fresh-state refresh before re-entry**: run `task cache:fetch-all -- --source=github-issue --repo OWNER/NAME` then re-enter this skill when ready to continue.\n\n⊗ Exit silently without the canonical confirmation + chaining instruction -- the Skill Completion Gate in AGENTS.md is binding.\n\n## References\n\n- Umbrella: #1119 (Wave-1 D6, this skill)\n- D2 #1122 (`task triage:summary`), D3 #1123 (`--resume-on`, parallel), D5 #1127 (`task verify:cache-fresh`), D10 #1129 (auto-classification), D11 #1128 (`task triage:queue` / `triage:show` / `triage:audit`), D12 #1131 (subscription scope)\n- Layer 5 reversibility verb: `scripts/triage_actions.py::reset` (already shipped under #845)\n- Sibling skills: `skills/deft-directive-refinement/SKILL.md`, `skills/deft-directive-swarm/SKILL.md`, `skills/deft-directive-sync/SKILL.md`\n- Stub author (replaced): #1149 (N9)\n",
249
+ "body": "# Deft Directive Triage\n\nTriage-cache hygiene + \"what's next?\" queue selection. Operates against the unified `.deft-cache/github-issue/` mirror (#883 Story 2) and the append-only `vbrief/.eval/candidates.jsonl` audit log (#845 Story 2); writes only via the canonical `task triage:*` verbs.\n\nLegend (from RFC2119): !=MUST, ~=SHOULD, ≉=SHOULD NOT, ⊗=MUST NOT, ?=MAY.\n\n## Platform Requirements\n\n! Requires **GitHub** as the SCM platform and the **GitHub CLI (`gh`)** authenticated against the active project's repo -- the cache surface (`task cache:fetch-all`) and the read-side gate (`task verify:cache-fresh`) both depend on it.\n\n## Deterministic Questions Contract\n\n! Every numbered-menu prompt rendered in this skill (Phase 2 candidate selection, Phase 3 per-item decision walk) ! MUST follow [`../../contracts/deterministic-questions.md`](../../contracts/deterministic-questions.md): render the canonical numbered menu in chat unless the host UI visibly preserves numeric option labels and returns numeric selections or exact displayed option text. The final two numbered options are `Discuss` and `Back`, in that order, and the Discuss-pause semantic from the contract applies verbatim -- on `Discuss` the agent halts the in-progress sequence and resumes only on an explicit user signal.\n\n## Phase 0 -- Sync\n\n! Probe cache freshness before doing any classification or selection. Stale cache reads produce stale decisions; the gate is the contract.\n\n1. ! Run `task verify:cache-fresh` (D5 / #1127). Exit 0 -> proceed to Phase 1. Exit 1 (stale or blocked) -> refresh per the printed remediation. Exit 2 (no bootstrap) -> run `task triage:bootstrap` first.\n2. ~ Refresh path: `task cache:fetch-all -- --source=github-issue --repo OWNER/NAME` for an already-bootstrapped project (idempotent, TTL-aware, re-applies the #883 scanner v2 quarantine rules); `task triage:bootstrap` for a first-time seed.\n3. ~ If `vbrief/active/*.vbrief.json` references are in play, run `task triage:refresh-active` to compare cached `meta.json.fetched_at` against live upstream `updatedAt` and surface drift before the queue is rendered.\n4. ~ When the one-liner emitted by the session-start ritual carries a `[scope-drift] N` segment (D14 / #1133), run `task triage:scope-drift` to see the per-label / per-milestone breakdown of upstream signals on cached open issues that fall outside the active `plan.policy.triageScope[]` subscription. The output documents both opt-in (`task triage:subscribe -- --label=<L>`) and opt-out (`task triage:scope-drift -- --ignore-label=<L>`) paths -- pick one before walking the queue so the cohort reflects the operator's current intent rather than a stale subscription.\n5. ⊗ Walk the queue against a stale cache -- the audit log will record decisions against bodies the operator never actually saw.\n\n## Phase 1 -- Classify\n\n! Inspect the auto-classification audit log so manually-decided items are not re-walked, and surface anomalies before the queue render.\n\n1. ! Run `task triage:classify --list` (D10 / #1129) to render the effective universal + consumer auto-classification rules and the active hold-marker list.\n2. ! Walk recent entries in `vbrief/.eval/candidates.jsonl` for anomalies: classifier disagreements against the operator's prior decisions, repeated `defer` cycles on the same issue, or `needs-ac` records older than the freshness window. Surface anomalies to the operator before Phase 2; do NOT auto-fix.\n3. ~ When the operator wants to widen / narrow the corpus, consult `task triage:scope --list` (D12 / #1131) to see the active `plan.policy.triageScope[]` subscription. Subscription edits belong in PROJECT-DEFINITION.vbrief.json, not in this skill.\n4. ~ Issue-label hygiene: labels feed triage queue ranking, issue gauges, hygiene sweeps, and lifecycle reconciliation. When this skill exposes an unlabeled issue or a downstream issue-creation step, recommend choosing one or more suitable labels from the repository's existing label set via `gh label list` or the labels API, or explicitly note that no label was applied. This is a recommendation, not a gate.\n5. ⊗ Re-classify items already terminally decided (accept / reject / mark-duplicate) without explicit operator approval -- the audit log is append-only and supersession runs through Layer 5 (`task triage:reset <N>`), not through silent re-walks.\n6. ⊗ Block issue creation solely because no label was selected, or invent ad hoc labels outside the repository's existing label set.\n\n## Phase 2 -- Present\n\n! Render the ranked queue before suggesting any specific issue. The cache-as-authoritative rule in AGENTS.md (`## Cache-as-authoritative work selection (#1149)`) is binding: the agent ! MUST consult `task triage:queue` and surface the result before proposing work from memory.\n\n1. ! Run `task triage:queue --limit=N` (D11 / #1128) -- default `N=10` per the umbrella Current Shape v3 WIP cap. Output is grouped `[RESUME]` -> `[URGENT]` -> untriaged -> other; within-group ordering follows the consumer-supplied `plan.policy.triageRankingLabels[]` (framework default empty per §12 boundary), tiebroken by `updated_at` descending.\n2. ! For per-item detail, run `task triage:show <N>` -- prints the cached upstream payload, the latest triage decision, the audit timeline, and the active-vBRIEF reference flag. Exit 0 on hit, 1 on cache miss (re-sync per Phase 0).\n3. ~ Present the ranked queue verbatim; do NOT silently re-rank, drop, or annotate beyond what the canonical renderer emits. If the operator wants a different ordering they edit `plan.policy.triageRankingLabels[]` and re-run.\n4. ⊗ Recommend a specific issue without consulting `task triage:queue` first, or recommend an issue absent from the queue without first running `task triage:show` to surface why (cache miss / outside subscription / terminal decision).\n\n## Phase 3 -- Decide\n\n! Walk per-item decisions through the canonical `task triage:*` verbs. The skill does NOT reimplement the audit-log append, schema validation, or `vbrief/proposed/` write inline -- the tasks are the canonical implementation (mirrors the #537 ingest-task discipline).\n\nFor each candidate the operator selects from the Phase 2 queue, render the canonical numbered action menu and dispatch the matching verb:\n\n```\nWhat would you like to do with this candidate?\n 1. Accept -- `task triage:accept <N>` (writes proposed/ vBRIEF + audit-log entry)\n 2. Reject -- `task triage:reject <N>` (audit-log entry only; terminal)\n 3. Defer -- `task triage:defer <N> [--resume-on <event>]` (non-terminal; resurfaces)\n 4. Needs-AC -- `task triage:needs-ac <N>` (non-terminal; flags missing acceptance criteria)\n 5. Mark duplicate -- `task triage:mark-duplicate <N> <of-issue>` (terminal; cross-links target)\n 6. Discuss\n 7. Back\n```\n\n- ! `--resume-on <event>` on `task triage:defer` (D3 / #1123 -- ships in parallel; reference but do not hard-depend) records a resume condition with the defer entry; the resume condition surfaces in `task triage:queue` once met. When D3 has not landed yet, omit the flag -- the verb stays terminal-shape-compatible.\n- ! Map user replies only to the displayed number (`1`-`7`) or exact displayed option text. ⊗ Do NOT infer from alphabetic host affordances or bare letters such as `d` / `b` unless those letters were visibly rendered as choices.\n- ! On `Discuss`, halt the action sequence immediately, prompt `What would you like to discuss?`, and resume only on an explicit user signal. ⊗ Implicit resumption.\n- ! On `Back`, un-buffer the prior candidate's selection and re-render its action menu -- permitted only before the action has dispatched to a `task triage:*` command. Once dispatched, the audit entry is committed; revisions go through Layer 5 (`task triage:reset`).\n- ~ Bulk patterns: `task triage:bulk-{accept,reject,defer,needs-ac}` (#845 Story 4) for clear label-driven sweeps; bulk results still flow through the audit log so history stays coherent.\n- ⊗ Write to `vbrief/proposed/` directly -- only `task triage:accept` (which delegates to `task issue:ingest`) is authorised for that surface.\n\n## Phase 4 -- Audit\n\n! Confirm the session's decisions landed coherently before exiting the skill.\n\n1. ! Run `task triage:audit --format=json` (D11 / #1128) -- emits the stable `{generated_at, repo, vbrief_staleness, entry_count, entries: [...]}` schema; pipe through `jq` to surface this session's appended entries. For historical look-back, add the #1180 filters: `task triage:audit --since=30d --action=demote --format=json | jq` answers \"how many demotes in the last 30 days?\" in one call. `--since=<window>` accepts the framework duration grammar (`Nd` / `Nh` / `Nm` / `Nw` / `Ns` or ISO-8601 `PnDTnHnMnS`); `--action=<verb>` filters to a single decision verb (`accept` / `reject` / `defer` / `needs-ac` / `mark-duplicate` / `reset` / `resume-eligible`). Both filters compose with `--format=text` and `--format=json`. The framework deliberately does NOT compute trend lines or apply falsification gates -- the contract is read raw, transform with `jq`.\n2. ! Run `task triage:summary` (D2 / #1122) -- prints the canonical one-liner `[triage] N untriaged · S stale-defer · M in-flight · WIP X/Y [⚠] [· [scope-drift] N]`. The WIP cap default is 10 per the umbrella Current Shape v3 (overridable via typed `plan.policy.wipCap`). The `⚠` glyph fires only at-or-above cap. The `[scope-drift] N` segment (D14 / #1133) appears only when at least one unsubscribed label/milestone meets the framework `_DRIFT_MIN_ISSUES = 3` threshold; suppressed at zero.\n3. ~ When the summary surfaces a non-zero `[scope-drift] N` (D14 / #1133), surface it to the operator alongside `task triage:scope-drift` output and the matching `task triage:subscribe` / `task triage:unsubscribe` / `task triage:scope-drift -- --ignore-label=<L>` remediation. Subscription mutations record a `subscription-change` audit entry under `vbrief/.eval/subscription-history.jsonl` (sidecar of the existing `candidates.jsonl` audit surface) so future operators can replay how the subscription evolved. After every mutation, run `task triage:bootstrap -- --resume` to backfill newly-subscribed entries / mark newly-out-of-scope entries.\n4. ~ When the audit surfaces a stale acceptance (`accept` decision whose issue is no longer referenced by any `vbrief/active/`), surface it to the operator -- the typical fix is a fresh ingest via `task issue:ingest -- <N>` or a `task triage:reset <N>` if the acceptance was in error.\n5. ⊗ Skip the Phase 4 audit -- silent exit leaves the operator without a record of what landed in `vbrief/proposed/` this session, which is the typical recurrence vector for \"what did I just accept?\" confusion.\n\n! Before reporting an umbrella or epic's current status during triage (what is done, what blocks, wave order), fetch `repos/<owner>/<repo>/issues/<N>/comments` via REST, read the `## Current shape (as of pass-N)` comment and any linked context/`LockedDecisions` vBRIEF — never conclude status from the issue body alone (claim-cites-state-surface, #2066 / AGENTS.md #1152).\n\n## Reversibility\n\n! To undo a decision, run `task triage:reset <N>`. This writes a `reset` audit entry referencing the prior decision id; history is **never** deleted. `task triage:reset` is the canonical Layer 5 reversibility verb (resolves the V3 audit from 2026-05-13). After a reset, the candidate re-enters the untriaged group on the next `task triage:queue` render so it can be re-walked through Phase 3.\n\n⊗ Edit or delete prior entries in `vbrief/.eval/candidates.jsonl` to \"undo\" a decision -- the log is append-only by design and any external mutation breaks the `merge=union` rebase ergonomic (#1144 / N4).\n\n## Anti-Patterns\n\n- ⊗ Recommend a specific issue without first consulting `task triage:queue` (binding under AGENTS.md `## Cache-as-authoritative work selection (#1149)`).\n- ⊗ Walk the queue against a stale cache (Phase 0 gate skipped).\n- ⊗ Reimplement audit-log append / `proposed/` write inline -- the `task triage:*` verbs own those surfaces (#845, #883).\n- ⊗ Treat `defer` / `needs-ac` as terminal -- they intentionally resurface on the next pass.\n- ⊗ Edit `vbrief/.eval/candidates.jsonl` directly to revoke a decision -- use `task triage:reset <N>`.\n\n## EXIT\n\n! When the operator opts out (queue exhausted, mid-session stop, or explicit \"done\"), confirm skill exit with the canonical phrasing: `deft-directive-triage complete -- exiting skill.`\n\n! Provide chaining instructions:\n\n- **Ingestion / evaluation of accepted items**: chain into `skills/deft-directive-refinement/SKILL.md` -- refinement's Phase 1 ingests the `vbrief/proposed/` items this skill just wrote into the rest of the lifecycle.\n- **Cohort dispatch**: chain into `skills/deft-directive-swarm/SKILL.md` -- swarm Phase 0 is queue-driven (N2 / #1142) and consumes the same `task triage:queue` ordering you just walked.\n- **Fresh-state refresh before re-entry**: run `task cache:fetch-all -- --source=github-issue --repo OWNER/NAME` then re-enter this skill when ready to continue.\n\n⊗ Exit silently without the canonical confirmation + chaining instruction -- the Skill Completion Gate in AGENTS.md is binding.\n\n## References\n\n- Umbrella: #1119 (Wave-1 D6, this skill)\n- D2 #1122 (`task triage:summary`), D3 #1123 (`--resume-on`, parallel), D5 #1127 (`task verify:cache-fresh`), D10 #1129 (auto-classification), D11 #1128 (`task triage:queue` / `triage:show` / `triage:audit`), D12 #1131 (subscription scope)\n- Layer 5 reversibility verb: `scripts/triage_actions.py::reset` (already shipped under #845)\n- Sibling skills: `skills/deft-directive-refinement/SKILL.md`, `skills/deft-directive-swarm/SKILL.md`, `skills/deft-directive-sync/SKILL.md`\n- Stub author (replaced): #1149 (N9)\n",
250
250
  "frontmatter_extra": "triggers:\n - triage\n - triage hygiene\n - work the cache\n - what's next\n - whats next\n - what should I work on\n - queue\n - build a cohort\n - build cohort"
251
251
  },
252
252
  {