@deftai/directive-content 0.110.0 → 0.111.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.
Files changed (35) hide show
  1. package/SKILL.md +13 -13
  2. package/Taskfile.yml +16 -15
  3. package/commands.md +9 -7
  4. package/contracts/design-critique.md +20 -3
  5. package/conventions/machine-generated-banner.md +9 -9
  6. package/conventions/rule-ownership.json +3 -3
  7. package/docs/scope-provenance.md +2 -0
  8. package/main.md +22 -22
  9. package/package.json +1 -1
  10. package/packs/rules/rules-pack-0.1.json +1 -1
  11. package/packs/skills/skills-pack-0.1.json +3 -3
  12. package/skills/deft-directive-design-critique/SKILL.md +2 -1
  13. package/skills/deft-directive-release/SKILL.md +22 -17
  14. package/skills/deft-directive-review-cycle/SKILL.md +45 -12
  15. package/skills/deft-directive-swarm/references/core-phase-0.md +2 -1
  16. package/skills/deft-directive-swarm/references/core-phase-3.md +1 -1
  17. package/skills/deft-directive-swarm/references/host-grok-build.md +15 -1
  18. package/tasks/policy.yml +2 -2
  19. package/tasks/scope.yml +16 -25
  20. package/tasks/triage-actions.yml +3 -4
  21. package/tasks/triage-bootstrap.yml +2 -2
  22. package/tasks/triage-bulk.yml +6 -7
  23. package/tasks/triage-classify.yml +2 -2
  24. package/tasks/triage-queue.yml +2 -2
  25. package/tasks/triage-reconcile.yml +2 -2
  26. package/tasks/triage-scope-drift.yml +2 -2
  27. package/tasks/triage-scope.yml +2 -2
  28. package/tasks/triage-smoketest.yml +3 -3
  29. package/tasks/triage-subscribe.yml +2 -2
  30. package/tasks/triage-summary.yml +2 -2
  31. package/tasks/triage-welcome.yml +2 -2
  32. package/tasks/verify.yml +14 -1
  33. package/templates/agent-prompt-preamble.md +4 -1
  34. package/templates/agents-entry.md +4 -4
  35. package/templates/design-critique-brief.md +2 -0
package/SKILL.md CHANGED
@@ -45,20 +45,20 @@ as your FIRST and ONLY response — no summary, no menu, no preamble:
45
45
 
46
46
  Then continue with `skills/deft-directive-setup/SKILL.md` Phase 1 for remaining questions.
47
47
 
48
- **If USER.md exists but `./vbrief/PROJECT-DEFINITION.vbrief.json` is missing**: Skip to
48
+ **If USER.md exists but `./xbrief/PROJECT-DEFINITION.xbrief.json` is missing**: Skip to
49
49
  `skills/deft-directive-setup/SKILL.md` Phase 2.
50
50
 
51
- **If USER.md and `./vbrief/PROJECT-DEFINITION.vbrief.json` both exist but no scope vBRIEFs in `./vbrief/` lifecycle folders**:
51
+ **If USER.md and `./xbrief/PROJECT-DEFINITION.xbrief.json` both exist but no scope xBRIEFs in `./xbrief/` lifecycle folders**:
52
52
  Skip to `skills/deft-directive-setup/SKILL.md` Phase 3. Start the specification interview
53
53
  imediately — ask what to build and features as the first question.
54
54
 
55
55
  ### ⊗ Project Root vs Framework Internals
56
56
 
57
- ! When checking for project-level files (`PROJECT-DEFINITION.vbrief.json`, scope vBRIEFs,
58
- `PRD.md`), ONLY look at `./vbrief/` and its lifecycle subdirectories.
57
+ ! When checking for project-level files (`PROJECT-DEFINITION.xbrief.json`, scope xBRIEFs,
58
+ `PRD.md`), ONLY look at `./xbrief/` and its lifecycle subdirectories.
59
59
 
60
- - ! `./vbrief/PROJECT-DEFINITION.vbrief.json` — the user's project config
61
- - ! `./vbrief/proposed/`, `./vbrief/pending/`, `./vbrief/active/`, `./vbrief/completed/` — scope vBRIEFs in lifecycle folders
60
+ - ! `./xbrief/PROJECT-DEFINITION.xbrief.json` — the user's project config
61
+ - ! `./xbrief/proposed/`, `./xbrief/pending/`, `./xbrief/active/`, `./xbrief/completed/` — scope xBRIEFs in lifecycle folders
62
62
  - ⊗ Count ANY file inside `.deft/core/` (canonical) or `./deft/` (legacy pre-v0.27) as a project-level artifact — those are
63
63
  framework-internal (e.g. `.deft/core/PROJECT.md`, `.deft/core/specs/`, `.deft/core/templates/`
64
64
  are all part of the framework, NOT the user's project)
@@ -75,7 +75,7 @@ USER.md has two sections with different precedence:
75
75
  ```
76
76
  USER.md Personal ← HIGHEST (name, custom rules — always wins)
77
77
 
78
- PROJECT-DEFINITION.vbrief.json ← Project-specific (strategy, coverage, languages, tech stack)
78
+ PROJECT-DEFINITION.xbrief.json ← Project-specific (strategy, coverage, languages, tech stack)
79
79
 
80
80
  USER.md Defaults ← Fallback defaults (used when PROJECT-DEFINITION doesn't specify)
81
81
 
@@ -85,11 +85,11 @@ USER.md Defaults ← Fallback defaults (used when PROJECT-DEFINITION doesn
85
85
 
86
86
  main.md ← General AI behavior
87
87
 
88
- scope vBRIEFs ← LOWEST precedence (requirements in lifecycle folders)
88
+ scope xBRIEFs ← LOWEST precedence (requirements in lifecycle folders)
89
89
  ```
90
90
 
91
91
  **IMPORTANT**: USER.md `Personal` section always wins. For project-scoped settings
92
- (strategy, coverage, languages), `PROJECT-DEFINITION.vbrief.json` overrides USER.md `Defaults`.
92
+ (strategy, coverage, languages), `PROJECT-DEFINITION.xbrief.json` overrides USER.md `Defaults`.
93
93
 
94
94
  ## File Reading Strategy (Lazy Loading)
95
95
 
@@ -97,7 +97,7 @@ scope vBRIEFs ← LOWEST precedence (requirements in lifecycle folders)
97
97
 
98
98
  1. **Always start with**: `.deft/core/main.md` (general guidelines)
99
99
  2. **Check for**: `~/.config/deft/USER.md` (personal overrides - highest precedence)
100
- 3. **Check for**: `./vbrief/PROJECT-DEFINITION.vbrief.json` (project-specific rules)
100
+ 3. **Check for**: `./xbrief/PROJECT-DEFINITION.xbrief.json` (project-specific rules)
101
101
  4. **Then read language-specific** only if working with that language:
102
102
  - `.deft/core/languages/python.md`
103
103
  - `.deft/core/languages/go.md`
@@ -128,8 +128,8 @@ See `.deft/core/tools/taskfile.md` for complete task standards and common comman
128
128
 
129
129
  **Spec-Driven Development (SDD)** for new features/projects:
130
130
  1. Run `skills/deft-directive-setup/SKILL.md` Phase 3 — sizing gate selects Light or Full path
131
- 2. Light: Interview → scope vBRIEFs in `vbrief/proposed/` (embedded requirements) → Implement
132
- 3. Full: Interview → rich narratives in `specification.vbrief.json` (approval gate) → scope vBRIEFs → Implement
131
+ 2. Light: Interview → scope xBRIEFs in `xbrief/proposed/` (embedded requirements) → Implement
132
+ 3. Full: Interview → rich narratives in `specification.xbrief.json` (approval gate) → scope xBRIEFs → Implement
133
133
 
134
134
  See `.deft/core/coding/testing.md` for complete testing standards.
135
135
 
@@ -167,7 +167,7 @@ task project:render # Project config → xbrief/PROJECT-DEFINITION.xbrief.
167
167
  1. **First time?** If USER.md doesn't exist, run `skills/deft-directive-setup/SKILL.md` Phase 1
168
168
  2. Read `.deft/core/main.md` (general guidelines)
169
169
  3. Read `~/.config/deft/USER.md` (personal preferences - highest precedence)
170
- 4. Read `./vbrief/PROJECT-DEFINITION.vbrief.json` (project rules)
170
+ 4. Read `./xbrief/PROJECT-DEFINITION.xbrief.json` (project rules)
171
171
  5. Run `task --list` to see available tasks
172
172
 
173
173
  See `.deft/core/main.md` for complete workflow details.
package/Taskfile.yml CHANGED
@@ -370,11 +370,11 @@ includes:
370
370
  packs:
371
371
  taskfile: ./tasks/packs.yml
372
372
  optional: true
373
- # Maintainer-only Python self-test lanes (#1813 contributor path / #2022
373
+ # Maintainer-only packaging lane (#1813 contributor path / #2022
374
374
  # Phase 2). `internal: true` hides `core:*` / `ci:*` from `task -l` and
375
375
  # blocks direct CLI invocation on consumer installs; only
376
376
  # `check:framework-source` below wires them as deps. Consumer `task check`
377
- # dispatches to `check:consumer` (TS / deft verbs — no uv/python).
377
+ # dispatches to `check:consumer` (TS / deft verbs).
378
378
  core:
379
379
  taskfile: ./tasks/core.yml
380
380
  optional: true
@@ -464,8 +464,11 @@ tasks:
464
464
  - verify-eval-health-relocation-framework-check
465
465
  - verify-eval-triggers-relocation-framework-check
466
466
  - vbrief:validate
467
- - codebase:validate-structure
467
+ - task: codebase:validate-structure
468
+ vars:
469
+ CLI_ARGS: "--enforce"
468
470
  - verify:codebase-map-fresh
471
+ - verify:spec-prd-fresh
469
472
  - verify-strategy-output
470
473
  # #2980 residual: fail-closed product raw-write inventory (allowlist primitives + temporary residual).
471
474
  - verify-contained-writes-enforce
@@ -796,18 +799,16 @@ tasks:
796
799
  # `triage-bootstrap`) -- a single shared `triage:` include namespace
797
800
  # is not supported by go-task v3 (two includes cannot share a key).
798
801
  # The aliases below provide the documented `task triage:<verb>`
799
- # user-facing surface that vBRIEFs / UPGRADING.md / scripts/triage_*.py
800
- # describe. Each alias delegates to the underlying namespaced task
801
- # and forwards `{{.CLI_ARGS}}` so flags (`--repo`, `--reason`, etc.)
802
- # reach the script. The inner tasks in each fragment are
802
+ # user-facing surface that xBRIEFs / UPGRADING.md describe. Each alias
803
+ # delegates to the underlying namespaced task and forwards
804
+ # `{{.CLI_ARGS}}` so flags (`--repo`, `--reason`, etc.) reach
805
+ # engine:invoke / packages/cli/dist. The inner tasks in each fragment are
803
806
  # `internal: true` so the fragment-namespace forms
804
807
  # (`triage-cache:cache`, `triage-actions:accept`, `triage-bulk:bulk-defer`,
805
808
  # `triage-bootstrap:bootstrap`) drop out of `task -l`; only the
806
809
  # documented `triage:*` aliases below appear in the listing. The
807
- # internal tasks remain CALLABLE for legacy invocations (e.g. recap
808
- # text in `scripts/triage_bootstrap.py` still prints the namespaced
809
- # forms, which continue to dispatch correctly via the fragment
810
- # include).
810
+ # internal tasks remain CALLABLE for legacy invocations via the fragment
811
+ # include.
811
812
  #
812
813
  # Aliases are inline at the root Taskfile rather than in a separate
813
814
  # fragment because they cross include namespaces and must exist
@@ -826,10 +827,10 @@ tasks:
826
827
  # categorized verb list grouped by role (Session-start, State verbs,
827
828
  # Read verbs, Lifecycle, Subscription mutation, Archive-rotation /
828
829
  # Promote-demote, Activate-complete, Reversibility, Decomposition).
829
- # The registry + renderer live in scripts/triage_help.py so every
830
- # verb is documented in one place. Each existing `triage:X` /
831
- # `scope:X` alias forwards `--help` to the same registry via the
832
- # `intercept_help` shim called from each verb script's `main()`.
830
+ # The registry + renderer live in
831
+ # packages/core/src/triage/help/registry-data.ts (edit in place; no
832
+ # generator). Each existing `triage:X` / `scope:X` alias forwards
833
+ # `--help` to the same registry via interceptHelp (handler + dispatch).
833
834
  #
834
835
  # Defined at the root Taskfile (not in a fragment) because the bare
835
836
  # target shares the `triage:` / `scope:` prefix with the documented
package/commands.md CHANGED
@@ -413,20 +413,22 @@ After CLI/deposit upgrade, disk can show the new generation while a long-lived s
413
413
  - ! Default interactive sessions to **read-only posture** until mutation or implementation intent (questions, research, Plan Mode, ticket-shaping). Load AGENTS.md / main.md / USER.md / PROJECT-DEFINITION; confirm alignment with addressing-name; ⊗ do not write `.deft/ritual-state.json`, run install/build side effects, or emit triage welcome, branch-policy, default-branch sync, sync-skill lifecycle checks, or eval/value readback writes unless the operator asks or the task is implementation-ready.
414
414
  - ! **USER.md path (#2544):** resolve via `deft session:start` output (`USER.md resolved …`); default platform paths: Windows `%APPDATA%\deft\USER.md`, Unix `~/.config/deft/USER.md`; override `$DEFT_USER_PATH`; workspace `<project>/.deft/USER.md`. ⊗ Invent or search `~/.config/deft` on Windows — AppData Roaming is canonical.
415
415
  - ! At mutation boundaries (code-writing, scope lifecycle moves, `start_agent`, commits, pushes, PR-from-local-changes, release work): run the mutable quick tier then gated verifier below before proceeding.
416
- - ? Explicit read-only alignment only: `deft session:start -- --read-only` (no ritual-state write).
416
+ - ? Explicit read-only alignment only: `deft session:start --read-only` (no ritual-state write). Task: `task session:start -- --read-only`.
417
417
  - ! **Worktree occupancy contract (#3433 / #3604 / #3611 / #3926):** mutation `session:start` / `session:ready` claim a gitignored `.deft/occupancy.json` lease. Occupancy is cooperative host-session routing between processes that follow the protocol, not authentication against another same-user process: hook JSON and local owner IDs are forgeable. Name it for what it is (#3755): a **cooperative bearer-id boundary, not a lineage** — the lease admits whoever presents an id the record itself names, nothing observes parentage, and a dispatched child is admitted only because a grant records it. A live lease allows only a matching presented owner or member and a ritual state whose exact verified owner agrees; missing, conflicting, or mismatched identity fails closed. `--read-only` does not claim. A stored lease whose `worktree_path` is not this checkout is residue, not a holder: first mutation `session:start` claims over it. Same-tree two-session conflict still fails closed.
418
418
  - ! **Which tree the lease is read from — root admission (#3794 / #4013):** a gated write is judged against the Git working tree its **target** lands in, not always the tree the host payload names. A target in another worktree sharing `--git-common-dir` is admitted and carries occupancy, ritual and active scope with it; a proven different repository, an unreadable target identity, and a mutation spanning two worktrees are refused. A target with **no Git toplevel at all** (OS temp, a home file, anything outside every checkout) is gated against the payload root — deliberate since #3794, published with its reason and a gate-by-gate disposition in [docs/hook-root-admission.md](./docs/hook-root-admission.md), which also records the three-surface matrix (direct write consults admission; generic server-prefixed MCP and out-of-repo Shell writes do not) and the relative-target canonicalization limitation (#4023).
419
419
  - ! **Host owner namespaces (#3611):** canonical owners are `host:<provider>:v1:<base64url(raw-id)>`. Codex uses payload `session_id` for the parent and its subagents. Claude Code uses `session_id`; `agent_id` does not replace the session-family owner. Cursor uses `conversation_id` and requires a simultaneously supplied `session_id` to agree; no Cursor subagent-granularity claim is made until verified. Grok has no verified payload identity, so its owner is the hook process variable `GROK_SESSION_ID` the host publishes (#3873): the hook is a sibling the host spawns, so an agent shell export cannot reach it, and the payload `session_id` is never read. When that variable is absent the host keeps explicit `--session-id` / `DEFT_SESSION_ID` ownership; a malformed one fails closed, as does an ambient `DEFT_SESSION_ID` that contradicts a resolved host owner.
420
420
  - ! **Occupancy identity on a host with no session derivation (#3877):** the hook process environment (`GROK_SESSION_ID` on Grok, or `DEFT_SESSION_ID` inherited by the hook) or an explicit `--session-id`. ⊗ a worker-shell `export DEFT_SESSION_ID`. A shell export reaches vitest, CLI verbs, and `scope:complete`; it never reaches `deft-hook`, a sibling process. Nothing in `content/templates` or `content/skills` mentions the variable. Do not invent an envelope mandate.
421
- - ! **One actor-resolution chain, four terminals (#3954):** claim, release, heartbeat and grant/revoke resolve the acting session by the same lookup order — explicit `--session-id`, then `DEFT_SESSION_ID`, then the owner the running host published. Only the **terminal** differs, and deliberately: `session:start` / `session:ready` **mint**, because claiming establishes an identity where none exists; `occupancy:release`, `occupancy:heartbeat`, `occupancy:grant` and `--revoke` resolve to **empty** and keep the "this process presented no session identity" diagnosis, because they prove an identity rather than establish one. A shared mint would hand those surfaces a plausible id no later hook will present. The practical effect: on a host that publishes an owner, the printed recovery `occupancy:release` is a command the occupant can actually run, instead of one that resolved an empty caller and refused the owner its own lease. Disagreement is reported, not reordered: when `DEFT_SESSION_ID` and the host owner name different sessions the documented order still stands, and a refusal names both ids and the `--session-id` that would act as the host owner. Anonymous release of the occupant recorded in the lease file stays **refused** — possession of that path is not authority to delete a live lease.
421
+ - ! **One actor-resolution chain, four terminals (#3954 / #4066):** claim, release, heartbeat and grant/revoke resolve the acting session by the same lookup order — explicit `--session-id`, then `DEFT_SESSION_ID`, then the owner the running host published. **Claim** is host-authoritative when those disagree: inherited `DEFT_SESSION_ID` must not beat the host-published owner (mirrors the write-gate env drop). Release, heartbeat and grant/revoke still report disagreement without reordering, and still refuse to mint. Anonymous release of the occupant recorded in the lease file stays **refused** — possession of that path is not authority to delete a live lease.
422
422
  - ! **Where the transport still does not reach (#3873 residue):** the CLI resolves the host owner; the write gate runs in the `deft-hook` sibling process, and on a deployment where the host does not publish `GROK_SESSION_ID` into that sibling the hook presents whatever `DEFT_SESSION_ID` it inherited — possibly another host's session. Nothing in this tree can set that process's environment, and the hook writes no env or payload log, so the condition is inferred from the deny text rather than observed. Recovery meanwhile is the ambient step above: the occupant releases its own lease from its own shell. Closing it needs either host cooperation (publish the variable to the hook sibling) or a hook-process capture facility, and both are separate work.
423
423
  - ! **Lifecycle identity transport (#3611):** for every host with a resolved owner, PreToolUse rewrites only exact, simple canonical `deft` / `directive` lifecycle commands and source-repo `task <verb> [-- ...]` forms to add the host's `--session-id`. Direct CLI spellings are `session:start`, `session:ready`, `session:end`, `occupancy:steal`, `occupancy:release`, `occupancy:heartbeat`, `occupancy:grant` (#3954, its `--revoke` arm included), and `swarm-launch`; the Task spelling for the last verb is `swarm:launch`. For owner-requiring lifecycle commands, the shell execution directory must be absent or realpath-align exactly with the hook project root. Path-bearing executables (`./deft`, `/path/deft`), path/destination flags (`--project-root`, `--paths`, path-valued `--stories`, `--output`, `--worktree-map`, `--gate-clearances`), `--no-audit`, consumer-repo Task indirection, Task aliases (`task deft:<verb>`), and compound, redirected, quoted, aliased, wrapped, or otherwise ambiguous forms are not auto-rewritten. A supported-host hook rejects a recognized lifecycle form outside the narrow rewrite surface until it carries the explicit matching `--session-id`; an execution-root mismatch on an owner-requiring command always denies. With a matching ID on other excluded forms, the original command remains under normal host permission handling. Manual/integrated-terminal callers must likewise pass one matching `--session-id` (or `DEFT_SESSION_ID`) through the complete lifecycle.
424
424
  - ! **Transition, steal, and release (#3611):** an existing live UUID lease cannot silently become a host-namespaced owner. Prefer one aligned transition: `session:start --steal --confirm --occupant <reported-session-id> --session-id=<your-session-id>` (an exact host-mediated command receives the final option automatically). Bare `occupancy:steal --confirm --occupant <reported-session-id> --session-id=<your-session-id>` changes only the lease; direct writes remain denied unless ritual state already names the new owner. If they differ, align the same writer ID with `session:start --rearm --session-id=<same-session-id>` when re-arm is eligible, or cold `session:start --session-id=<same-session-id>` otherwise. The occupant drops a live lease with `occupancy:release` or `session:end`; a non-owner cannot clear it. Confirmed steal remains required for a live occupant and prints existing `claimed_at` / `heartbeat_at` / `last_write_at` when available.
425
425
  - ! **Lease refresh (#3599):** a gated write by the owner re-stamps `heartbeat_at`, so a session that keeps working keeps its lease, up to the absolute age cap below. The re-stamp is floored at a quarter of the TTL to avoid rewriting the lease per event, and it records `last_write_at` separately — `heartbeat_at` moves on any lease touch, `last_write_at` only on a gated product write, which is what tells a would-be stealer that the occupant is mid-work. When the owner's own lease is inside the staleness window (three quarters of the TTL) and the automatic re-stamp could not run, the write gate says so instead of letting the lease lapse silently; a write that did re-stamp stays quiet, because the warning would name a state that write just cleared. A re-stamp blocked by the lock leaves the lease untouched and the gate re-decides against the file on disk: contention alone keeps the rightful owner writing, while a takeover that completed during the wait denies. Long quiet stretches produce no gated write to ride on, so the owner refreshes explicitly with `deft occupancy:heartbeat` (Task: `task occupancy:heartbeat`). Refresh extends a lease the caller already holds — it never claims a free worktree, never takes a foreign lease, and never mints an owner; an unheld lease exits non-zero. Under a supported host the exact command receives the matching `--session-id` automatically; manual and Grok callers pass `--session-id <id>` or `DEFT_SESSION_ID`.
426
426
  - ! **Absolute lease age cap (#3599):** a lease is also dead 12 hours after `claimed_at`, whatever its heartbeat says, and no refresh path may extend that — `claimed_at` survives every re-stamp. Occupancy admits whoever presents the occupant's session id, so refresh alone would let any process holding that string keep a worktree forever and disable the crash-recovery reclaim the TTL exists for. The two dead states call for different responses and read differently: a stale heartbeat means refresh sooner; past the cap the tree is no longer held, so the capped holder's own gated writes are **refused** until it re-claims with `session:start --session-id=<your-session-id>` — allowing them would let the very bearer the cap bounds keep mutating a worktree a peer may claim at any moment. A lease that is both stale and capped reads as capped, because refreshing cannot revive it and the stale wording would send the holder somewhere that does not help. A different session is unaffected: taking over an aged-out tree is the reclaim the cap exists to enable. Twelve hours is sized by the stalled owner, not the busy one: refresh keys on writes, so an agent that finishes overnight and waits for its operator stops refreshing while staying legitimate, and 12 hours spans a 23:00 dispatch to a 09:00 handoff while still bounding reclaim inside a day. Reaching the cap costs one re-claim, never the work. A time cap cannot tell a stalled-but-live owner from a dead one — the only liveness signal on this path is a write; if that bites, the answer is a write-free liveness signal (explicit parked state, or refresh on non-write activity), not a larger number.
427
427
  - ! **Lease membership (#3755):** the occupant admits a dispatched child with `deft occupancy:grant --session-id=<owner> --child-session-id=<child> --role <worker-role> [--ttl-minutes N] [--worktree <path>] [--host <id>] [--address <name>] [--join-protocol none|heartbeat-file|parent-message]` (Task: `task occupancy:grant`), and withdraws it with the same command plus `--revoke`. The grant records owner id, child id, worktree, role and expiry, so a write resolves to a session rather than to whoever held the string. Admission splits: **writes** are admitted for the owner **or** a valid unexpired member; **release, steal, heartbeat and cohort close-out stay owner-only**, so a grant never escalates into the lease itself. An expired grant is refused on read, expiry is clamped to the lease's own absolute age cap, a lease carries at most 32 live grants, and a steal or a fresh claim starts with none — grants belong to the lease that issued them. The child id is checked at grant time (#3954): a value under the reserved `host:` prefix must be a well-formed canonical owner, and one that re-prefixes the owner's own host payload under a second provider is refused as the self-grant it is. Both were granted before, and the write gate then admitted them as `member`, so the lease read as membership while admitting nobody. An id outside that prefix is still accepted, because a child on a host with no identity contract presents whatever `DEFT_SESSION_ID` holds. Withdrawal skips the check, so a malformed grant written earlier stays revocable. A member's write re-stamps `heartbeat_at` and `last_write_at` on the same quarter-TTL floor as the owner's: a tree a granted child is actively writing is in use, and letting it lapse would hand the worktree to a peer mid-edit. `claimed_at` is untouched, so the absolute age cap and the grant's own expiry still bound it. The verb is inside the rewrite surface since #3954, so a supported host adds the matching `--session-id`; a `--worktree` rebind stays outside it and must carry the owner explicitly. All of it is cooperative, like the rest of this lease: it names who may write, it does not authenticate them. Ritual state stays single-owner, so a member writes under the occupant's ceremony: the composite hook write gate measures the verified ritual owner against the occupant that issued the grant rather than against the writer, and a revoked or expired member is refused there as well.
428
- - ! **Parent and child, per identity-source kind (#3954 / #3999):** there is no single answer, so do not look for one. On a **`host-env`** host (Grok) the host publishes a different id into each agent session, so a parent and its dispatched children are **different actors**: each resolves its own owner through the chain above and claims its own worktree, which is where the dispatch envelope already puts it. Membership is **not** automatic there — 32 grants at a four-hour expiry against a twenty-minute lease means granting on every dispatch exhausts a busy parent's lease inside a day — and the revocation trigger stays the owner's own `--revoke` or the grant's expiry. A dispatched child's owner lease is released when orchestration observes `phase: terminal`, using the occupancy owner and exact worktree root the parent recorded at dispatch under `.deft/child-occupancy/` (lease-gated; not `.deft-scratch/**`). Release is compare-and-release under the occupancy lock: only if that recorded child still owns that recorded tree. A successor owner is left alone. On a **`payload`** host (Codex, Claude Code, Cursor) parent and subagents share one id, so there is no foreign child lease to admit and nothing to grant; the live consequence is the inverse one, that a parent's `occupancy:release` removes a working child's lease mid-flight with no denial, because both present the same string. The terminal transition is a no-op on that arm — auto-release would drop the parent's live lease. Swarm close-out still releases only the launcher's `occupancy_session_id`. No new reap verb.
429
- - ! **Lifetime and enforcement boundaries:** expired heartbeat (20 min) is free for claim-over-expired, and the release path may clear residue; no `reap` verb. No host-to-lease map or credential file is persisted; supported hooks re-derive their owner from each payload. Gated writes renew the heartbeat (#3599), so the 20-minute window runs from the owner's last write rather than from its claim, bounded by the absolute age cap above. Missing or drifted hooks remain #3742, and spawn tools remain outside occupancy enforcement. Join negotiation is owner-issued membership (`occupancy:grant`, #3755); the parked child-initiated `occupancy:request` queue stays unimplemented and is no longer named in remediation. `swarm:launch` carries the same explicit owner and persists `occupancy_session_id` in a cohort-keyed record; close-out uses that cohort entry as authority, requires any ambient owner to corroborate it, and never substitutes the current live lease owner. Swarm close-out stays `releaseSwarmOccupancy` on complete-cohort.
428
+ - ! **Parent and child, per identity-source kind (#3954 / #3999 / #4066):** there is no single answer, so do not look for one. On a **`host-env`** host (Grok) the host publishes a different id into each agent session, so a parent and its dispatched children are **different actors**: each resolves its own owner through the chain above and claims **its own worktree**. Membership is **not** automatic there — 32 grants at a four-hour expiry against a twenty-minute lease means granting on every dispatch exhausts a busy parent's lease inside a day — and the revocation trigger stays the owner's own `--revoke` or the grant's expiry. Spawned mutating work takes a reserved linked worktree before occupancy claim; sharing the primary checkout with a live occupant is refuse, not grant-across-host. On a **`payload`** host (Codex, Claude Code, Cursor) parent and subagents share one id, so there is no foreign child lease to admit and nothing to grant on the same tree; own-tree children still record a dispatch lease. A parent's `occupancy:release` on the parent tree does not drop a child tree. No new reap verb.
429
+ - ! **Spawn occupancy seam (#4066):** implement-class spawn (`Task`, `spawn_subagent`, `start_agent`, …) inspects `tool_input.isolation=worktree` / `worktree_path` / `cwd`. Absent field fails closed (do not inherit parent cwd). Unique dispatch reservation (incarnation) is persisted before launch. Occupancy consult is on the destination tree, not a write-gate flip with `actor=null`. Explore and ephemeral spawns stay exempt. Grok PreToolUse cannot rewrite spawn input; hosts that can (`claude`, `cursor`, `codex`) re-root cwd onto the reserved tree. Primary-checkout claim is the exception (`release-cut`, `policy-restore`, `operator-default-branch`) from a trusted producer; `--read-only` never claims.
430
+ - ! **Dispatcher-owned terminal release (#4066 / #3999):** recorded-child close-out is dispatcher lifecycle on a dispatch-provenance `(owner, worktree, incarnation)` tuple. Release requires parent-id match, incarnation match, skip invalid heartbeats, and refuse a tree that is not the heartbeat tree or a dispatcher-allocated tree. Ordinary self-claim records are not close-out. Payload-kind skip remains for same-tree shared identity; a linked worktree distinct from the observer is released. Heartbeats should echo `incarnation` from the dispatch envelope.
431
+ - ! **Lifetime and enforcement boundaries:** expired heartbeat (20 min) is free for claim-over-expired, and the release path may clear residue; no `reap` verb. No host-to-lease map or credential file is persisted; supported hooks re-derive their owner from each payload. Gated writes renew the heartbeat (#3599), so the 20-minute window runs from the owner's last write rather than from its claim, bounded by the absolute age cap above. Missing or drifted hooks remain #3742. Implement-class spawn is occupancy-consulted on the destination worktree (#4066); explore/ephemeral spawn stay outside that consult. Join negotiation is owner-issued membership (`occupancy:grant`, #3755); the parked child-initiated `occupancy:request` queue stays unimplemented and is no longer named in remediation. `swarm:launch` carries the same explicit owner and persists `occupancy_session_id` in a cohort-keyed record; close-out uses that cohort entry as authority, requires any ambient owner to corroborate it, and never substitutes the current live lease owner. Swarm close-out stays `releaseSwarmOccupancy` on complete-cohort.
430
432
  - ~ Operators MAY still explicitly request full `deft session:start`, `deft triage:welcome`, sync, or doctor in read-only sessions.
431
433
 
432
434
  ### Assist / research posture (#1802)
@@ -455,17 +457,17 @@ Cross-link: spawn three postures and deny recoveries live under § Agent-host di
455
457
  ### Mutable ritual (mutation posture)
456
458
 
457
459
  - ! On **mutation** session start, run `deft session:start` (or `task session:start` in framework source) after loading AGENTS.md. Records quick-tier ritual in `.deft/ritual-state.json`: alignment confirmation, branch-policy disclosure, `deft verify:tools` guidance, default-branch sync warnings, and `deft triage:welcome` one-liner. State is worktree- and HEAD-bound; stale after `plan.policy.sessionRitualStalenessHours` hours (default 4). Mutation start also claims the worktree occupancy lease (`.deft/occupancy.json`); see Session routing (#3433).
458
- - ! **Orientation compression Now (#3286):** mutation cold `session:start` composes `doctor` + #3282 toolchain preflight (and deposit-sha fast-paths for `agents:refresh` / `verify:cache-fresh`) as inline sections with per-section status lines — composition of existing steps, not a new monolith. When the deposit fingerprint (payload + templates + engine) is unchanged, refresh surfaces print one-line `unchanged - sha match` no-ops. Opt-in compact output: `deft session:start -- --compact` or `DEFT_SESSION_COMPACT=1` (verbose remains the default). #2176 read-only default is unchanged. Dual-path Later (`deft orient`) stays open until run-summary telemetry shows ritual+gate share ≥ 25% after Now ships (#2899).
460
+ - ! **Orientation compression Now (#3286):** mutation cold `session:start` composes `doctor` + #3282 toolchain preflight (and deposit-sha fast-paths for `agents:refresh` / `verify:cache-fresh`) as inline sections with per-section status lines — composition of existing steps, not a new monolith. When the deposit fingerprint (payload + templates + engine) is unchanged, refresh surfaces print one-line `unchanged - sha match` no-ops. Opt-in compact output: `deft session:start --compact` or `DEFT_SESSION_COMPACT=1` (verbose remains the default). #2176 read-only default is unchanged. Dual-path Later (`deft orient`) stays open until run-summary telemetry shows ritual+gate share ≥ 25% after Now ships (#2899).
459
461
  - ! Cold `session:start` does **not** run the live agent-hook probe. Functional readiness belongs to the gated mutation path so cold ceremony retains the #2990/#2991 latency profile.
460
462
  - ! **Hot path latency (#2991):** by default, mutation `session:start` does **not** block ritual-state write on optional network. It skips the npm release-availability probe and triage cache empty-hydrate / self-heal (`ensureTriageCacheHydrated` / `maybeSelfHealCache`). Targets (operator-facing, not CI-hard): warm hot path typically under a few seconds once tools are on PATH; cold path dominated by local `verify:tools` and git, usually well under ~30s when optional network is off. Empty-cache GitHub fetch-all and npm `view` previously accounted for multi-minute hangs in the WWYSYDH pilot — those stay off the critical path unless opted in.
461
463
  - ! **Cold vs re-arm ceremony tiers (#2992):** default `session:start` is the **cold** (full) path. After age staleness or compact re-arm (#2113) on the **same worktree** with continuous HEAD and previously-passing quick steps, prefer `deft session:start --rearm` (alias `--tier=rearm`) to refresh the ritual clock + HEAD/worktree bind without `verify:tools`, triage welcome, release probe, or staleness tickler. Full cold remains required for missing/invalid state, worktree change, discontinuous HEAD, first install, or failed/missing quick steps. Compact marks `rearm_needed`; PreToolUse denial and inspect/verify messages prefer re-arm recovery when cold is unnecessary.
462
- - ? Opt into optional network: `deft session:start -- --with-network` or `DEFT_SESSION_START_NETWORK=1`. When enabled, the bounded release-availability probe runs against the public npm registry (skips framework source checkouts, non-release pins, and `DEFT_NO_NETWORK=1`; identical latest-version notices throttle for 24 hours in `xbrief/.triage-cache/release-availability-state.json`). Default-mode triage welcome then also hydrates/self-heals the triage cache. This is separate from `deft doctor`, whose bare and gated invocations remain offline by default (#2182). Refs #1692 / #2991. Re-arm never runs optional network.
464
+ - ? Opt into optional network: `deft session:start --with-network` or `DEFT_SESSION_START_NETWORK=1`. When enabled, the bounded release-availability probe runs against the public npm registry (skips framework source checkouts, non-release pins, and `DEFT_NO_NETWORK=1`; identical latest-version notices throttle for 24 hours in `xbrief/.triage-cache/release-availability-state.json`). Default-mode triage welcome then also hydrates/self-heals the triage cache. This is separate from `deft doctor`, whose bare and gated invocations remain offline by default (#2182). Refs #1692 / #2991. Re-arm never runs optional network.
463
465
  - ~ `session:start --json` includes `steps[]` with `name` + `duration_ms` for major phases (`alignment`, `branch_policy`, `verify_tools`, `triage_welcome`, `release_probe`, `ritual_write`), plus total `duration_ms`, `optional_network`, and `ceremony_tier` (`cold` | `rearm`). Skipped optional steps report `skipped: true` and `duration_ms: 0`. Use this for attribution when investigating ceremony wall-clock.
464
466
  - ~ **Process-cost events (#2994 / #3508):** on mutation `session:start` completion (cold or re-arm), Directive appends a local `session:start` behavioral event to `.deft-cache/events.jsonl` with `ceremony_tier`, `duration_ms`, `exit_code`, and optional `steps[]` (same labels as `--json`). Mutation `session:start` also prints one operator-visible `ceremony <tier> <ms>` line (hidden under `--compact` / `DEFT_SESSION_COMPACT`). When PreToolUse denies for `ritual-not-ready`, a local `session:ritual-blocked` event records `tool_name`, `code`, and optional `recovery_tier` / `detail`. Always-on best-effort (never blocks ceremony or deny path); not gated on `valueFeedback`; **no remote upload** (Product Insights #2603 is a separate opt-in). Pull the rollup with `task value:show` (composed reader; CLI process time, not agent-turn wall clock). See § Process-cost events below. ⊗ Do not use the printed CLI duration as #3286 Later graduation input.
465
467
  - ~ At safe idle points (clean tree, no in-flight story), mutation session start and `deft scope:complete` may also run the staleness tickler: an interactive, consent-based offer to upgrade Directive (`npm i -g @deftai/directive@latest`) and/or migrate xBRIEF (`deft migrate:xbrief`). Escalation tiers, snooze windows, and opt-out live under `plan.policy.stalenessTickler` — inspect with `deft policy:show --field=stalenessTickler`. State persists in `xbrief/.triage-cache/staleness-tickler-state.json`. Skips framework source checkouts, dirty trees, CI/headless (`DEFT_SESSION_RITUAL_SKIP=1`), and typed opt-out. Refs #2488 / #2489.
466
468
  - ! Before any code-writing tool call or `start_agent` implementation dispatch, run `deft verify:session-ritual -- --tier=gated`. Gated tier fails closed unless quick-tier state is fresh; lazily records the non-deferrable `agent_hooks` readiness gate plus `deft doctor` and `deft verify:cache-fresh` entrypoints. Agent-hook correctness is independent of doctor warnings and throttling. Step 0 of the pre-`start_agent` gate stack.
467
469
  - ! **One-shot recovery (#2993 / #3100):** when PreToolUse denies writes for a stale/missing gated ritual, run `deft session:ready` (or `task session:ready`). It composes `session:start` (only when quick-tier is not green) + `verify:session-ritual -- --tier=gated` + `cache fetch-all --force` when `cache_fresh` is the remaining blocker, then re-verifies. Even when gated inspect is already fresh, the fast path forces one live `agent_hooks` check so later drift cannot hide behind cached ritual state; it still avoids unnecessary fetch-all. Flags: `--json`, `--repo OWNER/NAME`, `--with-network` (forwarded to session:start). Prefer this over juggling the multi-step recovery sequence under hook pressure.
468
- - ? Postpone with `deft session:start -- --defer step=reason` (`alignment`, `branch_policy`, `triage_welcome`, `doctor`, `cache_fresh`). `agent_hooks` is non-deferrable.
470
+ - ? Postpone with `deft session:start --defer step=reason` (`alignment`, `branch_policy`, `triage_welcome`, `doctor`, `cache_fresh`). `agent_hooks` is non-deferrable.
469
471
  - Headless workers / CI MAY set `DEFT_SESSION_RITUAL_SKIP=1`; verifier exits 0 but warns when bypass hides failure.
470
472
  - ⊗ Self-report ritual complete without fresh `deft session:start` state; ⊗ bypass `deft verify:session-ritual` before implementation dispatch; ⊗ reorder/skip/merge ritual tiers without operator override.
471
473
 
@@ -47,6 +47,23 @@ The Stop 1 write-back records `refutation-target:` naming the triage author's hi
47
47
 
48
48
  `verify:judgment-gates --enforce` stays opt-in unused in this rollout. Advisory observe first. No marker means the gate never fires. Voluntary critiques stay legal.
49
49
 
50
+ ### Run posture (#4072)
51
+
52
+ The front door is a session-local run-posture field, not a second ingest switch and not a third occupancy concept. Occupancy mechanics stay on #4020. Cite that rule; do not clone it.
53
+
54
+ Closed tokens on the operator utterance: `direct`, `forge-only`, `github-only`, `github only`, `no worktrees` for direct; `checkout` for the mutating checkout path. `parseOperatorRunPosture` (`packages/core/src/design-critique/run-posture.ts`) matches those tokens with word boundaries. Missing token, including `arc <N> yolo`, asks before Stop 1. Yolo does not pick a mode. `ingest` is not a front-door mode; that token asks. ⊗ Substring or NLP classification. ⊗ Front-door mode `ingest`. ⊗ A yolo default-direct.
55
+
56
+ Record `arc-mode: direct` or `arc-mode: checkout` on the Stop 1 write-back. `evaluateDirectDispatch` is a fixture over parent-claimed actions, not a live occupancy observer.
57
+
58
+ - ! Record `arc-mode:` on the Stop 1 write-back before any mutation-capable session start.
59
+ - ! Direct means `session:start --read-only`, or an explicit occupancy release if a mutation lease is already held.
60
+ - ! Recognition of `direct` happens before mutation initialization. Refuse direct when mutation `session:start` has already occurred, unless the lease is released first.
61
+ - ! Direct posting path that survives a foreign lease: `gh issue comment --body-file -` (stdin). Least-authority envelope: bounded GitHub reads and one comment post.
62
+ - ! Direct N>1 process-only critics are not swarm Phase 2 and not a #4066 mutating worker. Family CLIs still spawn. ⊗ `git worktree add`. Pin reads to `git show <dispatch-sha>:` against the recorded SHA. ⊗ A moving branch ref.
63
+ - ! Direct EXIT names ingest as a later operator verb after the completed-arc record. ⊗ Auto-ingest.
64
+ - ⊗ Treat `arc-mode:` as ingest clearance or as a permanent ingest denial.
65
+ - ⊗ Record a front-door mode named `ingest`.
66
+
50
67
  ## Stop 2 — Variant selection
51
68
 
52
69
  Record one line per arc: the **charter** (`refutation` | `open critique`), the **spend** (`N=1`, or `N≥3` when the permission is used), and why.
@@ -172,7 +189,7 @@ seat: codex launcher: codex
172
189
 
173
190
  - ! For spend N≥3, the panel-deposit or a sibling-seat record names three claimed families before the first sibling spawn. Parent claims the family at dispatch. ⊗ Classify family from a model slug.
174
191
  - ! A same-family sibling set is not a panel. ⊗ Lean it. Printed recovery is re-seat (or halt), not wait for Stop 5.
175
- - ! Grok Build launcher tree: Grok seat via `spawn_subagent` (or `grok`); Claude seat via `claude` CLI; Codex seat via `codex exec`. Worktree isolation before each spawn. Probe `claude` / `codex` on PATH before offering paste-ready. Paste-ready is the fallback when a named family's CLI is absent. Close stdin on CLI spawns (Windows `cmd /c "… <nul"`; Unix `… </dev/null`). Pointer: [`docs/grok-build-subscription-setup.md`](../docs/grok-build-subscription-setup.md).
192
+ - ! Grok Build launcher tree: Grok seat via `spawn_subagent` (or `grok`); Claude seat via `claude` CLI; Codex seat via `codex exec`. Worktree isolation before each spawn unless `arc-mode: direct`. Probe `claude` / `codex` on PATH before offering paste-ready. Paste-ready is the fallback when a named family's CLI is absent. Close stdin on CLI spawns (Windows `cmd /c "… <nul"`; Unix `… </dev/null`). Pointer: [`docs/grok-build-subscription-setup.md`](../docs/grok-build-subscription-setup.md).
176
193
  - ! `evaluatePanelSeatComposition` (`packages/core/src/design-critique/panel-seat-families.ts`) refuses a same-family N≥3 set and refuses paste-ready-first when `claude` / `codex` resolve. It takes claimed families and PATH probe results. It does not observe live comments and does not count siblings.
177
194
  - ! After a dispatch-composition miss, offer a prevention issue. On yolo, file it. ⊗ Only re-seat.
178
195
 
@@ -467,7 +484,7 @@ Closed catalog (last chip wins): `design-critique:mechanism-shaped` (in-flight,
467
484
  - ⊗ `gh api POST .../labels` or additive `scm:issue:edit --add-label` for this facet.
468
485
  - ⊗ Intercept mixed `scm issue edit` adds/removes for this facet.
469
486
  - ⊗ General-purpose labels CLI.
470
- - ! After the completed-arc record is present, `triage:accept` / `scope:promote` / `issue:ingest` / build may proceed unless `evaluateCompletedArcRecord` returns `cancelled` or `unrecut-body` (#4057). Any identity may run those verbs. Same-session parent continuation is not required. GitHub Triage on the implementer is not required. They read the accepted verified synthesis (latest successor lean plus the verified-claims table).
487
+ - ! After the completed-arc record is present, `triage:accept` / `scope:promote` / `issue:ingest` / build may proceed unless `evaluateCompletedArcRecord` returns `cancelled` or `unrecut-body` (#4057). Any identity may run those verbs. Same-session parent continuation is not required. ⊗ Treat `arc-mode:` as ingest clearance or as a permanent ingest denial. Ingest stays `issue:ingest` after the completed-arc record. Direct EXIT names it as a later operator verb. GitHub Triage on the implementer is not required. They read the accepted verified synthesis (latest successor lean plus the verified-claims table).
471
488
  - ! Per-thread body ingest stays the mapper after a set-level bind. Stories the bind wants are recut bodies or newly filed issues. Derived AC stays on that body.
472
489
  - ! Un-recut portfolio members fail closed on `cancelled`. Parent posts `design-critique: cancelled, because ...` on that number. Parent `role: parent` dominate prose is not that record. Critic, quoted, or fenced cancel-shaped prose is not that record. Leftover `mechanism-shaped` without cancel stays `missing-record` and is not this control.
473
490
  - ! A later successor lean after cancel starts a recut arc. Completing a superseded thread without recut would mint the harvest.
@@ -576,4 +593,4 @@ This motion ingests untrusted issue threads by design.
576
593
 
577
594
  ## Test surface
578
595
 
579
- `packages/core/src/content-contracts/standards/design_critique_contract.test.ts` locks required pointer strings, the scaffolds framing, the comment-lead field as model then role from the closed set (not an issue label), the operator-gated loop (successor lean, operator verbs including walk / walk all, dual stop, halt line, exclusive remaining-set replace of the two catalog chips, #3640 auto-stamp on a non-empty all-accept map and no-stamp on stubs, first-lean recording obligation after this round's siblings are posted), the parent-side substantiation token and independence rules, the Stop 1 exclusion (pre-critic premises outside the trigger) and `refutation-target:` field tokens rather than full body sentences, the composed auto-bind conjunct (all-accept map AND zero unresolved audit markers) at Operator verbs and Bind path 1, the variant-table evaluation rule (charter selection and spend permission evaluated independently), the critic-method heading and distinctive obligation tokens (exact class tokens, citations-are-claims, existing mechanisms, injection / swarm trigger nouns, failed-reviewer phrase, finding anatomy) rather than full body sentences, the brief-template forbidden-inputs list, and the thin router skill (existence, line cap, pointer resolution, no-normative-content). `evaluateParentAudit` locks the omission failure modes. This suite locks the SoT MUST and the thin skill pointer for the first-lean recording obligation, including the auto-stamp operator-confirm conjunct and the no-bind-while-unposted-same-round-siblings rule. `evaluateCompletedArcRecord` locks ingest on the completed-arc record rather than a catalog chip. It does not fail-close live parent turns. `packages/core/src/design-critique/citation-grammar.test.ts` locks the `## Citation grammar` closed set, the refused positions, and the diagnostics surface; `packages/core/src/design-critique/completed-arc-record.test.ts` locks one parser for both questions, set membership against the latest lean, and the observation-echoing block details (#3831). Runtime parent-turn detection only if `evaluateParentAudit` is extended; that extension is not required to ship the recording obligation. Panel completeness is locked as contract text only. No predicate observes it on a live arc (#3850). `evaluatePanelSeatComposition` locks claimed-family composition and PATH paste-ready-first; it is a fixture over claimed families, not a live sibling-count gate. `### The arc` and its derived boundaries, the `### Target shape` axis with its twice-run caveat, and the two bind-path-2 non-empty refusals are locked as contract text (#3797). `## Plain-language summary` is locked the same way: the contract test pins the heading token, the MUST-not-SHOULD reasoning, the ADR-006 exemption and its limit, the non-normative marking, and the per-artifact reserved line-start matrix, and `packages/core/src/design-critique/reserved-line-starts.test.ts` exercises each of the three families on each artifact kind against the exported shape predicates and `evaluateCompletedArcRecord`. No predicate observes a summary on a live arc (#3929). `### Verified-claims table heading`, the closed reason vocabulary, and the re-measured line-start matrix are locked as contract text, and `completed-arc-record.test.ts` exercises the typed refusal partition: the two states, details that differ by more than the id, the untyped null table id, and the seven recorded live arc table ids (#3942).
596
+ `packages/core/src/content-contracts/standards/design_critique_contract.test.ts` locks required pointer strings, the scaffolds framing, the comment-lead field as model then role from the closed set (not an issue label), the operator-gated loop (successor lean, operator verbs including walk / walk all, dual stop, halt line, exclusive remaining-set replace of the two catalog chips, #3640 auto-stamp on a non-empty all-accept map and no-stamp on stubs, first-lean recording obligation after this round's siblings are posted), the parent-side substantiation token and independence rules, the Stop 1 exclusion (pre-critic premises outside the trigger) and `refutation-target:` field tokens rather than full body sentences, the composed auto-bind conjunct (all-accept map AND zero unresolved audit markers) at Operator verbs and Bind path 1, the variant-table evaluation rule (charter selection and spend permission evaluated independently), the critic-method heading and distinctive obligation tokens (exact class tokens, citations-are-claims, existing mechanisms, injection / swarm trigger nouns, failed-reviewer phrase, finding anatomy) rather than full body sentences, the brief-template forbidden-inputs list, and the thin router skill (existence, line cap, pointer resolution, no-normative-content). `evaluateParentAudit` locks the omission failure modes. This suite locks the SoT MUST and the thin skill pointer for the first-lean recording obligation, including the auto-stamp operator-confirm conjunct and the no-bind-while-unposted-same-round-siblings rule. `evaluateCompletedArcRecord` locks ingest on the completed-arc record rather than a catalog chip. It does not fail-close live parent turns. `packages/core/src/design-critique/citation-grammar.test.ts` locks the `## Citation grammar` closed set, the refused positions, and the diagnostics surface; `packages/core/src/design-critique/completed-arc-record.test.ts` locks one parser for both questions, set membership against the latest lean, and the observation-echoing block details (#3831). Runtime parent-turn detection only if `evaluateParentAudit` is extended; that extension is not required to ship the recording obligation. Panel completeness is locked as contract text only. No predicate observes it on a live arc (#3850). `evaluatePanelSeatComposition` locks claimed-family composition and PATH paste-ready-first; it is a fixture over claimed families, not a live sibling-count gate. `### The arc` and its derived boundaries, the `### Target shape` axis with its twice-run caveat, and the two bind-path-2 non-empty refusals are locked as contract text (#3797). `## Plain-language summary` is locked the same way: the contract test pins the heading token, the MUST-not-SHOULD reasoning, the ADR-006 exemption and its limit, the non-normative marking, and the per-artifact reserved line-start matrix, and `packages/core/src/design-critique/reserved-line-starts.test.ts` exercises each of the three families on each artifact kind against the exported shape predicates and `evaluateCompletedArcRecord`. No predicate observes a summary on a live arc (#3929). `### Verified-claims table heading`, the closed reason vocabulary, and the re-measured line-start matrix are locked as contract text, and `completed-arc-record.test.ts` exercises the typed refusal partition: the two states, details that differ by more than the id, the untyped null table id, and the seven recorded live arc table ids (#3942). `### Run posture` and `parseOperatorRunPosture` / `evaluateDirectDispatch` lock the closed-token front door, the missing-token ask including yolo, the `session:start --read-only` start verb, stdin posting, SHA-pinned reads, and the no-worktree direct panel; `run-posture.test.ts` exercises those fixtures. `evaluateCompletedArcRecord` ignores `arc-mode:` (#4072).
@@ -10,7 +10,7 @@ Legend (from RFC2119): !=MUST, ~=SHOULD, ≉=SHOULD NOT, ⊗=MUST NOT, ?=MAY.
10
10
  ## Why
11
11
 
12
12
  Before this contract, deft had four machine-managed file writers
13
- (`task migrate:vbrief` deprecation redirects, `task spec:render`,
13
+ (frozen `task migrate:vbrief` deprecation redirects (v0.59.0; historical), `task spec:render`,
14
14
  `task prd:render`, `task roadmap:render`) and each used a different
15
15
  (or no) banner convention. Downstream heuristics that distinguish
16
16
  "is this file user-customized" from "is this machine-managed" were
@@ -34,7 +34,7 @@ of the file:
34
34
  - `{purpose}` — one of the enumerated per-writer purposes below; fixed
35
35
  string values so downstream detectors can match on a stable token.
36
36
  - `{source}` — the source-of-truth path the writer consumed
37
- (typically `vbrief/specification.vbrief.json`), or `n/a` when the
37
+ (typically `xbrief/specification.xbrief.json`), or `n/a` when the
38
38
  writer has no single source-of-truth file (e.g. the migrator
39
39
  deprecation redirect, which is driven by the migration flow).
40
40
  - `{command}` — the canonical `task *` invocation that regenerates
@@ -49,10 +49,10 @@ of the file:
49
49
  The `Purpose:` value is a small fixed enum so detectors can match on a
50
50
  stable token. Writers MUST use exactly one of these values:
51
51
 
52
- - `rendered specification` -- `scripts/spec_render.py` -> `SPECIFICATION.md`
53
- - `rendered PRD` -- `scripts/prd_render.py` -> `PRD.md`
54
- - `rendered roadmap` -- `scripts/roadmap_render.py` -> `ROADMAP.md`
55
- - `deprecation redirect` -- `scripts/migrate_vbrief.py::_deprecation_redirect()`
52
+ - `rendered specification` -- `task spec:render` -> `SPECIFICATION.md`
53
+ - `rendered PRD` -- `task prd:render` -> `PRD.md`
54
+ - `rendered roadmap` -- `task roadmap:render` -> `ROADMAP.md`
55
+ - `deprecation redirect` -- frozen `task migrate:vbrief` (v0.59.0; historical)
56
56
  -> replaced `SPECIFICATION.md` / `PROJECT.md`
57
57
 
58
58
  ? Future render tasks added under `tasks/` MUST extend this list before
@@ -61,7 +61,7 @@ contract violation.
61
61
 
62
62
  ## Detection heuristic (for user-customization guards)
63
63
 
64
- ! `scripts/migrate_vbrief.py::_is_user_customized()` consults the
64
+ ! Frozen `task migrate:vbrief` (v0.59.0) `_is_user_customized()` consults the
65
65
  `_SPEC_AUTO_MARKERS` and `_PROJECT_AUTO_MARKERS` tuples. Both MUST
66
66
  include `"AUTO-GENERATED by"` and the FULL HTML-comment prefix
67
67
  `"<!-- Purpose:"` so any file carrying this banner is recognised as
@@ -83,13 +83,13 @@ incorrectly re-flagged as pre-cutover on rc.3.
83
83
  ```
84
84
  <!-- AUTO-GENERATED by task spec:render -- DO NOT EDIT MANUALLY -->
85
85
  <!-- Purpose: rendered specification -->
86
- <!-- Source of truth: vbrief/specification.vbrief.json -->
86
+ <!-- Source of truth: xbrief/specification.xbrief.json -->
87
87
  <!-- Regenerate with: task spec:render -->
88
88
  # My Project
89
89
  ...
90
90
  ```
91
91
 
92
- ## Example (migrator deprecation redirect)
92
+ ## Example (frozen migrator deprecation redirect, v0.59.0; historical)
93
93
 
94
94
  ```
95
95
  <!-- AUTO-GENERATED by task migrate:vbrief -- DO NOT EDIT MANUALLY -->
@@ -252,11 +252,11 @@
252
252
  },
253
253
  {
254
254
  "id": "main-vbrief-persistence",
255
- "text": "All vBRIEF files MUST be stored in `./vbrief/` or its lifecycle subfolders",
255
+ "text": "All xBRIEF files MUST be stored in `./xbrief/` or its lifecycle subfolders",
256
256
  "owner_file": "main.md",
257
- "owner_section": "## vBRIEF Persistence",
257
+ "owner_section": "## xBRIEF Persistence",
258
258
  "authority": "MUST",
259
- "last_verified": "2026-04-28"
259
+ "last_verified": "2026-09-02"
260
260
  },
261
261
  {
262
262
  "id": "agents-deft-alignment-confirmation",
@@ -90,6 +90,8 @@ Flags:
90
90
  | `--xbrief-rel-path` | no | override path binding; default maps `pending/` → `active/` |
91
91
  | `--repo` | no | `owner/name` seed for preimage `approvedRepos` (same source as `issue:emit`) |
92
92
 
93
+ Those two record kinds are **tracked provenance**, not local cache. Canonical `deft init` / `deft update` gitignore must not ignore the `.deft/approved-scope/` directory. Crash-journal, lock, and `.next` sidecars in that directory stay ignored. `git add` of the two record files must work without `-f`. Leftover directory ignore lines (both slash spellings) are healed off on update.
94
+
93
95
  Commit **both** `.deft/approved-scope/<plan-id>.json` and `<plan-id>.intent.json` on the **merge base** (or a prior PR) before the implementation PR activates or expands the scoped xBRIEF. Read the preimage before you commit — that file is the approved intent.
94
96
 
95
97
  ## Three layers (do not mix)
package/main.md CHANGED
@@ -10,7 +10,7 @@ Foundational guidelines for AI agent behavior in the Deft framework.
10
10
 
11
11
  Legend (from RFC2119): !=MUST, ~=SHOULD, ≉=SHOULD NOT, ⊗=MUST NOT, ?=MAY.
12
12
 
13
- **⚠️ Rule Precedence**: USER.md has two sections: `Personal` (always wins — name, custom rules) and `Defaults` (fallback — strategy, coverage, languages; PROJECT-DEFINITION.vbrief.json overrides these). (Override path via `DEFT_USER_PATH` env var; )
13
+ **⚠️ Rule Precedence**: USER.md has two sections: `Personal` (always wins — name, custom rules) and `Defaults` (fallback — strategy, coverage, languages; PROJECT-DEFINITION.xbrief.json overrides these). (Override path via `DEFT_USER_PATH` env var; )
14
14
 
15
15
  **📋 Lazy Loading**: See `npx deft packs:slice skills list` (Skills Index; `REFERENCES.md` is maintainer-only and does not ship) for guidance on when to load which files.
16
16
 
@@ -26,7 +26,7 @@ Legend (from RFC2119): !=MUST, ~=SHOULD, ≉=SHOULD NOT, ⊗=MUST NOT, ?=MAY.
26
26
  - `main.md` - General AI behavior (this document)
27
27
  - [coding/coding.md](./coding/coding.md) - Software development guidelines
28
28
  - `~/.config/deft/USER.md` - Personal preferences (highest precedence)
29
- - `./vbrief/PROJECT-DEFINITION.vbrief.json` - Project identity gestalt and scope registry
29
+ - `./xbrief/PROJECT-DEFINITION.xbrief.json` - Project identity gestalt and scope registry
30
30
 
31
31
  **Coding-Specific:**
32
32
  - Languages: [languages/cpp.md](./languages/cpp.md), [languages/go.md](./languages/go.md), [languages/officejs.md](./languages/officejs.md), [languages/python.md](./languages/python.md), [languages/typescript.md](./languages/typescript.md), [languages/vba.md](./languages/vba.md)
@@ -191,21 +191,21 @@ Source material: AI Agent Traps paper (`docs/ssrn-6372438.pdf`, Franklin et al.,
191
191
 
192
192
  Propagation: the canonical orchestrator preamble at [templates/agent-prompt-preamble.md](./templates/agent-prompt-preamble.md) carries the same rule so dispatched workers inherit the behavior. This is the same class as the approval-fatigue defense above (`## Agent Trap Defenses`) applied to a different surface -- "you cancelled" is a buried mis-attribution that the rule corrects with the same fail-loud / surface-the-anomaly discipline.
193
193
 
194
- ## vBRIEF Persistence
194
+ ## xBRIEF Persistence
195
195
 
196
- - ! All vBRIEF files MUST be stored in `./vbrief/` or its lifecycle subfolders — never in workspace root
197
- - ! Use `PROJECT-DEFINITION.vbrief.json` (singular) as the project identity gestalt — narratives for identity, items as scope registry
198
- - ! Use `plan.vbrief.json` (singular) for session-level tactical plans and progress tracking
199
- - ! Use `continue.vbrief.json` (singular) for interruption recovery checkpoints
200
- - ! Specifications are written as `specification.vbrief.json`, then rendered to `.md`
201
- - ! Scope vBRIEFs live in lifecycle folders: `proposed/`, `pending/`, `active/`, `completed/`, `cancelled/`
202
- - ! Scope vBRIEF filenames MUST follow: `YYYY-MM-DD-descriptive-slug.vbrief.json` (slug rules: [`conventions/vbrief-filenames.md`](./conventions/vbrief-filenames.md))
203
- - ! Playbooks use `playbook-{name}.vbrief.json` (named, not ULID-suffixed)
196
+ - ! All xBRIEF files MUST be stored in `./xbrief/` or its lifecycle subfolders — never in workspace root
197
+ - ! Use `PROJECT-DEFINITION.xbrief.json` (singular) as the project identity gestalt — narratives for identity, items as scope registry
198
+ - ! Use `plan.xbrief.json` (singular) for session-level tactical plans and progress tracking
199
+ - ! Use `continue.xbrief.json` (singular) for interruption recovery checkpoints
200
+ - ! Specifications are written as `specification.xbrief.json`, then rendered to `.md`
201
+ - ! Scope xBRIEFs live in lifecycle folders: `proposed/`, `pending/`, `active/`, `completed/`, `cancelled/`
202
+ - ! Scope xBRIEF filenames MUST follow: `YYYY-MM-DD-descriptive-slug.xbrief.json` (slug rules: [`conventions/vbrief-filenames.md`](./conventions/vbrief-filenames.md))
203
+ - ! Playbooks use `playbook-{name}.xbrief.json` (named, not ULID-suffixed)
204
204
  - ! Completed xBRIEFs are evidence of what was built — full standing as a record of *what is*, zero authority over *what to build next* (#3383). The current contract is the active xBRIEF plus the human operator's live instruction. Both halves are required.
205
205
  - ⊗ Use ULID-suffixed filenames for plan, todo, or continue files
206
- - ⊗ Place vBRIEF files at workspace root
207
- - ⊗ Write `SPECIFICATION.md` directly — it MUST be generated from `specification.vbrief.json`
208
- - ⊗ Move scope vBRIEFs between lifecycle folders without updating `plan.status`
206
+ - ⊗ Place xBRIEF files at workspace root
207
+ - ⊗ Write `SPECIFICATION.md` directly — it MUST be generated from `specification.xbrief.json`
208
+ - ⊗ Move scope xBRIEFs between lifecycle folders without updating `plan.status`
209
209
  - ⊗ Treat a completed xBRIEF as the next-build contract, or let it override the active story or the live human instruction
210
210
 
211
211
  ### Schema version: v0.8 (canonical write)
@@ -230,10 +230,10 @@ Projects that pre-date v0.20 (pre-vBRIEF-centric model) must migrate on a **pinn
230
230
 
231
231
  A consumer project is **pre-cutover** if ANY of these hold:
232
232
 
233
- - `SPECIFICATION.md` exists at the project root 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.
233
+ - `SPECIFICATION.md` exists at the project root and is neither a deprecation redirect nor a current generated spec export. A current generated spec export contains `<!-- Purpose: rendered specification -->` and a layout-resolved `<!-- Source of truth: ... -->` line for the specification artifact (`xbrief/specification.xbrief.json` on a migrated tree), and that artifact plus all five lifecycle folders exist.
234
234
  - `PROJECT.md` exists at the project root and is not a deprecation redirect (`<!-- deft:deprecated-redirect -->` or `<!-- Purpose: deprecation redirect -->`)
235
- - `vbrief/` exists but one or more of the five lifecycle subfolders (`proposed/`, `pending/`, `active/`, `completed/`, `cancelled/`) is missing
236
- - `vbrief/PROJECT-DEFINITION.vbrief.json` is absent on a project that otherwise looks set up
235
+ - `xbrief/` exists but one or more of the five lifecycle subfolders (`proposed/`, `pending/`, `active/`, `completed/`, `cancelled/`) is missing
236
+ - `xbrief/PROJECT-DEFINITION.xbrief.json` is absent on a project that otherwise looks set up
237
237
 
238
238
  The executable detection helper is `task migrate:preflight`. The full agent-facing flow lives in [QUICK-START.md](./QUICK-START.md) Step 2 and in [skills/deft-directive-setup/SKILL.md](./skills/deft-directive-setup/SKILL.md) (Pre-Cutover Detection Guard).
239
239
 
@@ -275,7 +275,7 @@ After migration completes, upgrade to current npm per [UPGRADING.md](./UPGRADING
275
275
 
276
276
  ### What migration produces
277
277
 
278
- The migrator replaces `SPECIFICATION.md` and `PROJECT.md` with deprecation-redirect stubs (both carry the `<!-- deft:deprecated-redirect -->` sentinel) and writes:
278
+ **Legacy (frozen v0.59.0 `task migrate:vbrief` only — not a current write path; do not reverse #2907).** The migrator replaces `SPECIFICATION.md` and `PROJECT.md` with deprecation-redirect stubs (both carry the `<!-- deft:deprecated-redirect -->` sentinel) and writes:
279
279
 
280
280
  - `vbrief/PROJECT-DEFINITION.vbrief.json` — project identity gestalt (narratives + items registry)
281
281
  - `vbrief/specification.vbrief.json` — design narratives and requirements
@@ -366,18 +366,18 @@ See [commands.md](./commands.md) for full workflow details.
366
366
  ### Session
367
367
 
368
368
  - `/deft:continue` — Resume from continue checkpoint ([resilience/continue-here.md](./resilience/continue-here.md))
369
- - `/deft:checkpoint` — Save session state to `./vbrief/continue.vbrief.json`
369
+ - `/deft:checkpoint` — Save session state to `./xbrief/continue.xbrief.json`
370
370
 
371
371
  ## Context Awareness
372
372
 
373
373
  **Project Context:**
374
- - ! Check `./vbrief/PROJECT-DEFINITION.vbrief.json` (in your consumer project) for project-specific rules and scope registry
374
+ - ! Check `./xbrief/PROJECT-DEFINITION.xbrief.json` (in your consumer project) for project-specific rules and scope registry
375
375
  - ! Follow project-specific patterns and conventions
376
376
  - ~ Note which rules/patterns are being applied
377
377
 
378
378
  **User Context:**
379
379
  - ! Respect `~/.config/deft/USER.md` Personal section (highest precedence)
380
- - ! For project-scoped settings, PROJECT-DEFINITION.vbrief.json overrides USER.md Defaults
380
+ - ! For project-scoped settings, PROJECT-DEFINITION.xbrief.json overrides USER.md Defaults
381
381
  - ! Remember user's maintained projects and their purposes
382
382
  - ~ Adapt communication style to user's expertise level
383
383
 
@@ -389,4 +389,4 @@ See [commands.md](./commands.md) for full workflow details.
389
389
 
390
390
  **Context Engineering:**
391
391
  - ~ See [context/context.md](./context/context.md) for strategies on managing context budget
392
- - ~ Use vBRIEF ([vbrief.org](https://vbrief.org)) for structured task plans, scratchpads, and checkpoints
392
+ - ~ Use xBRIEF for structured task plans, scratchpads, and checkpoints
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@deftai/directive-content",
3
- "version": "0.110.0",
3
+ "version": "0.111.0",
4
4
  "deftConsumerDeposit": true,
5
5
  "description": "Shippable Directive framework content in the consumer .deft/core/ layout (C1 flatten), plus the engine surfaces (.githooks/, Taskfile.yml, tasks/) the deposit wires. Python-free per #2022 Phase 3. Refs #11, #1669, #1967.",
6
6
  "license": "MIT",
@@ -3839,7 +3839,7 @@
3839
3839
  "id": "agents-029",
3840
3840
  "tier": "MUST",
3841
3841
  "domain": "agents",
3842
- "text": "**Worker-owns-lifecycle (Gap C):** When dispatching an implementation worker, the envelope MUST declare `stop-at: pr-open` OR `drive-to: merge-ready` (default for story work). Workers scoped `drive-to: merge-ready` own PR + review cycle + fix batches through merge-ready as ONE unit of work \u2014 they spawn their own review poller per review-cycle monitoring tiers; the orchestrator MUST NOT hand back at PR-open and re-dispatch separate leaf agents for review/fixes.",
3842
+ "text": "**Worker-owns-lifecycle (Gap C):** When dispatching an implementation worker, the envelope MUST declare `stop-at: pr-open` OR `drive-to: merge-ready` (default for story work). Workers scoped `drive-to: merge-ready` own PR + review cycle + fix batches through merge-ready as ONE unit of work \u2014 following review-cycle monitoring tiers (Grok Build / Cursor / Claude Code leaves that cannot nest block on `pr:watch` in-process and MUST NOT spawn a child poller) (#4130); the orchestrator MUST NOT hand back at PR-open and re-dispatch separate leaf agents for review/fixes.",
3843
3843
  "path": "AGENTS.md",
3844
3844
  "body": null
3845
3845
  },