@deftai/directive-content 0.55.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 (250) hide show
  1. package/.agents/skills/deft/SKILL.md +6 -0
  2. package/.agents/skills/deft-directive-article-review/SKILL.md +11 -0
  3. package/.agents/skills/deft-directive-build/SKILL.md +10 -0
  4. package/.agents/skills/deft-directive-cost/SKILL.md +12 -0
  5. package/.agents/skills/deft-directive-debug/SKILL.md +13 -0
  6. package/.agents/skills/deft-directive-gh-arch/SKILL.md +11 -0
  7. package/.agents/skills/deft-directive-gh-slice/SKILL.md +10 -0
  8. package/.agents/skills/deft-directive-glossary/SKILL.md +10 -0
  9. package/.agents/skills/deft-directive-interview/SKILL.md +9 -0
  10. package/.agents/skills/deft-directive-pre-pr/SKILL.md +9 -0
  11. package/.agents/skills/deft-directive-refinement/SKILL.md +10 -0
  12. package/.agents/skills/deft-directive-release/SKILL.md +12 -0
  13. package/.agents/skills/deft-directive-review-cycle/SKILL.md +10 -0
  14. package/.agents/skills/deft-directive-setup/SKILL.md +10 -0
  15. package/.agents/skills/deft-directive-swarm/SKILL.md +10 -0
  16. package/.agents/skills/deft-directive-sync/SKILL.md +9 -0
  17. package/.agents/skills/deft-directive-triage/SKILL.md +9 -0
  18. package/.agents/skills/deft-directive-write-skill/SKILL.md +9 -0
  19. package/LICENSE.md +22 -0
  20. package/QUICK-START.md +167 -0
  21. package/UPGRADING.md +517 -0
  22. package/coding/build-output.md +28 -0
  23. package/coding/coding.md +235 -0
  24. package/coding/debugging.md +110 -0
  25. package/coding/holzmann.md +96 -0
  26. package/coding/hygiene.md +127 -0
  27. package/coding/security.md +158 -0
  28. package/coding/testing.md +162 -0
  29. package/coding/toolchain.md +44 -0
  30. package/commands.md +300 -0
  31. package/context/context.md +57 -0
  32. package/context/deterministic-split.md +67 -0
  33. package/context/examples.md +26 -0
  34. package/context/fractal-summaries.md +69 -0
  35. package/context/long-horizon.md +46 -0
  36. package/context/spec-deltas.md +177 -0
  37. package/context/tool-design.md +34 -0
  38. package/context/working-memory.md +62 -0
  39. package/contracts/boundary-maps.md +65 -0
  40. package/contracts/deterministic-questions.md +59 -0
  41. package/contracts/hierarchy.md +77 -0
  42. package/conventions/content-manifest.json +399 -0
  43. package/conventions/machine-generated-banner.md +130 -0
  44. package/conventions/references.md +120 -0
  45. package/conventions/rule-ownership.json +382 -0
  46. package/conventions/task-caching.md +43 -0
  47. package/conventions/vbrief-filenames.md +70 -0
  48. package/deployments/README.md +37 -0
  49. package/deployments/agentuity/README.md +138 -0
  50. package/deployments/agentuity/via-cli.md +380 -0
  51. package/deployments/agentuity/via-cloud.md +425 -0
  52. package/deployments/agentuity/via-github-actions.md +664 -0
  53. package/deployments/agentuity/via-gravity-network.md +606 -0
  54. package/deployments/agentuity/via-vpc.md +607 -0
  55. package/deployments/aws/README.md +38 -0
  56. package/deployments/aws/via-app-runner.md +612 -0
  57. package/deployments/aws/via-ecs-fargate.md +561 -0
  58. package/deployments/aws/via-elastic-beanstalk.md +628 -0
  59. package/deployments/aws/via-lambda.md +649 -0
  60. package/deployments/azure/README.md +37 -0
  61. package/deployments/azure/via-aks.md +390 -0
  62. package/deployments/azure/via-app-service.md +564 -0
  63. package/deployments/azure/via-container-apps.md +599 -0
  64. package/deployments/azure/via-functions.md +552 -0
  65. package/deployments/cloud-gov/README.md +63 -0
  66. package/deployments/cloud-gov/agents/compliance-docs.md +154 -0
  67. package/deployments/cloud-gov/agents.md +39 -0
  68. package/deployments/cloud-gov/cicd.md +64 -0
  69. package/deployments/cloud-gov/deployment.md +150 -0
  70. package/deployments/cloud-gov/logging.md +43 -0
  71. package/deployments/cloud-gov/manifest.md +121 -0
  72. package/deployments/cloud-gov/overview.md +58 -0
  73. package/deployments/cloud-gov/security.md +46 -0
  74. package/deployments/cloud-gov/services.md +72 -0
  75. package/deployments/cloud-gov/upstream/README.md +18 -0
  76. package/deployments/cloudflare/README.md +33 -0
  77. package/deployments/cloudflare/via-dashboard.md +83 -0
  78. package/deployments/cloudflare/via-git.md +90 -0
  79. package/deployments/cloudflare/via-github-actions.md +185 -0
  80. package/deployments/cloudflare/via-terraform.md +157 -0
  81. package/deployments/cloudflare/via-wrangler.md +165 -0
  82. package/deployments/fly-io/README.md +37 -0
  83. package/deployments/fly-io/via-dockerfile.md +648 -0
  84. package/deployments/fly-io/via-flyctl.md +653 -0
  85. package/deployments/fly-io/via-github-actions.md +695 -0
  86. package/deployments/fly-io/via-multi-region.md +598 -0
  87. package/deployments/google/README.md +34 -0
  88. package/deployments/google/via-app-engine.md +42 -0
  89. package/deployments/google/via-cloud-functions.md +23 -0
  90. package/deployments/google/via-cloud-run.md +330 -0
  91. package/deployments/google/via-gke.md +23 -0
  92. package/deployments/netlify/README.md +99 -0
  93. package/deployments/netlify/via-cli.md +17 -0
  94. package/deployments/netlify/via-functions.md +19 -0
  95. package/deployments/netlify/via-git.md +25 -0
  96. package/deployments/vercel/README.md +90 -0
  97. package/deployments/vercel/via-api.md +16 -0
  98. package/deployments/vercel/via-cli.md +17 -0
  99. package/deployments/vercel/via-git.md +24 -0
  100. package/docs/BROWNFIELD.md +179 -0
  101. package/docs/getting-started.md +137 -0
  102. package/docs/good-agents-md.md +137 -0
  103. package/events/README.md +89 -0
  104. package/events/event-record.schema.json +26 -0
  105. package/events/registry.json +166 -0
  106. package/events/registry.schema.json +71 -0
  107. package/glossary.md +145 -0
  108. package/incidents/README.md +81 -0
  109. package/incidents/_template.md +38 -0
  110. package/interfaces/cli.md +104 -0
  111. package/interfaces/rest.md +212 -0
  112. package/interfaces/tui.md +242 -0
  113. package/interfaces/web.md +123 -0
  114. package/languages/6502-DASM.md +132 -0
  115. package/languages/c.md +235 -0
  116. package/languages/commands.md +23 -0
  117. package/languages/cpp.md +132 -0
  118. package/languages/csharp.md +259 -0
  119. package/languages/dart.md +183 -0
  120. package/languages/delphi.md +218 -0
  121. package/languages/elixir.md +208 -0
  122. package/languages/go.md +78 -0
  123. package/languages/java.md +278 -0
  124. package/languages/javascript.md +163 -0
  125. package/languages/julia.md +175 -0
  126. package/languages/kotlin.md +193 -0
  127. package/languages/markdown.md +168 -0
  128. package/languages/mermaid.md +146 -0
  129. package/languages/officejs.md +392 -0
  130. package/languages/python.md +209 -0
  131. package/languages/r.md +163 -0
  132. package/languages/rust.md +216 -0
  133. package/languages/sql.md +216 -0
  134. package/languages/swift.md +153 -0
  135. package/languages/typescript.md +132 -0
  136. package/languages/vba.md +279 -0
  137. package/languages/vhdl.md +180 -0
  138. package/languages/visual-basic.md +151 -0
  139. package/languages/zig.md +196 -0
  140. package/meta/SOUL.md +27 -0
  141. package/meta/code-field.md +44 -0
  142. package/meta/morals.md +40 -0
  143. package/meta/philosophy.md +39 -0
  144. package/meta/project.md +49 -0
  145. package/meta/ralph.md +223 -0
  146. package/meta/security.md +80 -0
  147. package/meta/versioning.md +326 -0
  148. package/package.json +22 -0
  149. package/packs/lessons/lessons-pack-0.1.json +553 -0
  150. package/packs/patterns/patterns-pack-0.1.json +57 -0
  151. package/packs/rules/rules-pack-0.1.json +4767 -0
  152. package/packs/skills/skills-pack-0.1.json +262 -0
  153. package/packs/strategies/strategies-pack-0.1.json +167 -0
  154. package/packs/swarm-spec/swarm-spec-pack-0.1.json +17 -0
  155. package/patterns/executor-layer-credentials.md +227 -0
  156. package/patterns/llm-app.md +156 -0
  157. package/patterns/multi-agent.md +278 -0
  158. package/patterns/prompt-assembly-layer-ordering.md +154 -0
  159. package/patterns/role-as-overlay.md +179 -0
  160. package/platforms/2600.md +137 -0
  161. package/platforms/unity.md +329 -0
  162. package/references/composer-skill-porting.md +152 -0
  163. package/references/cost-models.md +163 -0
  164. package/references/ip-risk.md +246 -0
  165. package/references/plain-english-ux.md +275 -0
  166. package/resilience/context-pruning.md +67 -0
  167. package/resilience/continue-here.md +62 -0
  168. package/scm/changelog.md +276 -0
  169. package/scm/git.md +139 -0
  170. package/scm/github.md +265 -0
  171. package/secrets/.gitkeep +0 -0
  172. package/skills/deft-build/SKILL.md +20 -0
  173. package/skills/deft-directive-article-review/SKILL.md +156 -0
  174. package/skills/deft-directive-build/SKILL.md +302 -0
  175. package/skills/deft-directive-cost/SKILL.md +201 -0
  176. package/skills/deft-directive-debug/SKILL.md +140 -0
  177. package/skills/deft-directive-decompose/SKILL.md +96 -0
  178. package/skills/deft-directive-gh-arch/SKILL.md +160 -0
  179. package/skills/deft-directive-gh-slice/SKILL.md +199 -0
  180. package/skills/deft-directive-glossary/SKILL.md +118 -0
  181. package/skills/deft-directive-interview/SKILL.md +528 -0
  182. package/skills/deft-directive-pre-pr/SKILL.md +131 -0
  183. package/skills/deft-directive-probe/SKILL.md +127 -0
  184. package/skills/deft-directive-refinement/SKILL.md +403 -0
  185. package/skills/deft-directive-release/SKILL.md +266 -0
  186. package/skills/deft-directive-review-cycle/SKILL.md +401 -0
  187. package/skills/deft-directive-setup/SKILL.md +717 -0
  188. package/skills/deft-directive-swarm/SKILL.md +989 -0
  189. package/skills/deft-directive-sync/SKILL.md +288 -0
  190. package/skills/deft-directive-triage/SKILL.md +137 -0
  191. package/skills/deft-directive-write-skill/SKILL.md +169 -0
  192. package/skills/deft-interview/SKILL.md +16 -0
  193. package/skills/deft-pre-pr/SKILL.md +16 -0
  194. package/skills/deft-review-cycle/SKILL.md +16 -0
  195. package/skills/deft-roadmap-refresh/SKILL.md +16 -0
  196. package/skills/deft-setup/SKILL.md +20 -0
  197. package/skills/deft-swarm/SKILL.md +16 -0
  198. package/skills/deft-sync/SKILL.md +16 -0
  199. package/strategies/README.md +83 -0
  200. package/strategies/artifact-guards.md +85 -0
  201. package/strategies/bdd.md +115 -0
  202. package/strategies/brownfield.md +7 -0
  203. package/strategies/discuss.md +129 -0
  204. package/strategies/emit-hints.md +69 -0
  205. package/strategies/enterprise.md +193 -0
  206. package/strategies/interview.md +551 -0
  207. package/strategies/map.md +179 -0
  208. package/strategies/probe.md +151 -0
  209. package/strategies/rapid.md +155 -0
  210. package/strategies/research.md +155 -0
  211. package/strategies/roadmap.md +9 -0
  212. package/strategies/speckit.md +437 -0
  213. package/strategies/v0-20-contract.md +134 -0
  214. package/strategies/yolo.md +169 -0
  215. package/swarm/swarm.md +300 -0
  216. package/templates/COST-ESTIMATE.md +114 -0
  217. package/templates/PULL_REQUEST_TEMPLATE.md +35 -0
  218. package/templates/agent-prompt-preamble.md +409 -0
  219. package/templates/agents-entry.md +211 -0
  220. package/templates/agents-entry.placeholders.md +75 -0
  221. package/templates/embed.go +20 -0
  222. package/templates/embed_test.go +36 -0
  223. package/templates/make-spec-example.md +9 -0
  224. package/templates/make-spec.md +246 -0
  225. package/templates/project.md.template +52 -0
  226. package/templates/specification.md +1 -0
  227. package/templates/swarm-greptile-poller-prompt.md +556 -0
  228. package/templates/user.md.template +31 -0
  229. package/tools/RWLDL.md +80 -0
  230. package/tools/greptile.md +141 -0
  231. package/tools/installer.md +23 -0
  232. package/tools/taskfile-migration.md +32 -0
  233. package/tools/taskfile.md +185 -0
  234. package/tools/telemetry.md +285 -0
  235. package/vbrief/schemas/cache-meta.schema.json +137 -0
  236. package/vbrief/schemas/candidates.schema.json +130 -0
  237. package/vbrief/schemas/codebase-map.schema.json +213 -0
  238. package/vbrief/schemas/lessons-pack.schema.json +134 -0
  239. package/vbrief/schemas/patterns-pack.schema.json +84 -0
  240. package/vbrief/schemas/rules-pack.schema.json +105 -0
  241. package/vbrief/schemas/skills-pack.schema.json +94 -0
  242. package/vbrief/schemas/slices.schema.json +87 -0
  243. package/vbrief/schemas/strategies-pack.schema.json +89 -0
  244. package/vbrief/schemas/swarm-spec-pack.schema.json +84 -0
  245. package/vbrief/schemas/vbrief-core.schema.json +1022 -0
  246. package/vbrief/vbrief.md +684 -0
  247. package/verification/integration.md +76 -0
  248. package/verification/plan-checking.md +85 -0
  249. package/verification/uat.md +60 -0
  250. package/verification/verification.md +117 -0
@@ -0,0 +1,409 @@
1
+ # Canonical orchestrator preamble (#954)
2
+
3
+ This is the canonical preamble that orchestrators (this conversation, swarm-skill dispatchers, monitor agents, scheduled / cloud agents) MUST include verbatim or by reference in any implementation sub-agent's dispatch envelope. It encodes the rules learned from prior recurrence patterns so each fresh dispatch starts with the institutional memory already loaded.
4
+
5
+ The orchestrator copies the section bodies into the worker prompt; the worker reads them as binding rules. Orchestrators MAY trim sections that are demonstrably out of scope (e.g. a docs-only worker may skip the rate-limit-throttle section), but MUST NOT silently drop the AGENTS.md read mandate, the #810 vBRIEF gate, the #1378 allocation-context token, the #1531 worker-metadata section when backend routing applies, or the PowerShell 5.1 non-ASCII rule.
6
+
7
+ ## 1. Read AGENTS.md before any other tool call
8
+
9
+ The first action in your tool loop MUST be reading `AGENTS.md` at the project root. Confirm the read in your first status message ("Deft Directive active -- AGENTS.md loaded."). The rules below override or extend the AGENTS.md content where they are stricter; AGENTS.md takes precedence where they are silent.
10
+
11
+ Anti-pattern: skimming AGENTS.md via `head` or `wc -l` and proceeding. Read the full file.
12
+
13
+ ## 2. #810 vBRIEF Implementation Intent Gate
14
+
15
+ Before any code-writing tool call (or before dispatching a sub-agent that will write code), satisfy the gate:
16
+
17
+ 1. Locate (or create) a scope vBRIEF for the work. If none exists in `vbrief/proposed/`, `vbrief/pending/`, or `vbrief/active/`, create one in `vbrief/proposed/` first.
18
+ 2. Promote the vBRIEF to `vbrief/pending/` via `task scope:promote -- <path>` (idempotent; lifecycle requires proposed -> pending -> active).
19
+ 3. Activate it: `task vbrief:activate -- <path>`. This moves the file to `vbrief/active/` and flips `plan.status` to `running`.
20
+ 4. Run the gate: `task vbrief:preflight -- vbrief/active/<file>.vbrief.json`. Exit 0 means you are clear to write code.
21
+
22
+ Anti-pattern: editing files before activating the vBRIEF, then activating "to make the gate pass" retroactively. The gate is the contract; satisfy it first.
23
+
24
+ The gate also requires an explicit action-verb directive from the user (`build`, `implement`, `ship`, `swarm`, `run agents`, `start agent`). Affirmative continuation phrases ("yes", "go", "proceed") are NOT authorisation unless the prior turn explicitly proposed implementation.
25
+
26
+ ## 2.5 Allocation context -- swarm-cohort consent token (#1378)
27
+
28
+ Every dispatch envelope MUST carry a `## Allocation context` section so any downstream skill (the build SKILL Story Start Gate, the `task vbrief:preflight` gate) or deterministic gate can decide whether batched work was operator-approved by reading structured fields instead of pattern-matching free-form prose. The section has exactly five fields, in this order:
29
+
30
+ - `dispatch_kind`: `solo` | `swarm-cohort` -- whether this worker is a lone dispatch or one member of an operator-approved swarm cohort.
31
+ - `allocation_plan_id`: <swarm-monitor session id, or path to the Phase 5 allocation-plan snapshot> | null -- the stable handle for the allocation plan that authorized this dispatch.
32
+ - `batching_rationale`: <one-line rationale from the Phase 5 allocation plan> | null -- the one-line reason the cohort was batched together.
33
+ - `cohort_vbriefs`: [<vbrief-path>, ...] -- the full cohort vBRIEF list; a `solo` dispatch lists just its one vBRIEF.
34
+ - `operator_approval_evidence`: <Phase 5 approval timestamp or session reference> -- the audit handle proving the operator approved the allocation plan (advisory / audit-only -- it is NOT part of the recognition-contract gate below).
35
+
36
+ **Recognition contract:** a section reporting `dispatch_kind: swarm-cohort` with a NON-NULL `allocation_plan_id` AND a NON-NULL `batching_rationale` satisfies the Story Start Gate consent-token requirement (the #1371 carve-out) -- the worker does NOT re-prompt the operator 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 in the Story Start Gate.
37
+
38
+ Worked example (a swarm-cohort member):
39
+
40
+ ```markdown
41
+ ## Allocation context
42
+
43
+ - dispatch_kind: swarm-cohort
44
+ - allocation_plan_id: orchestrator-run-019e80bd-7328-7636-b283-a2f818243dd9
45
+ - batching_rationale: Three disjoint-file-scope stories from #1378; Story A freezes the schema, Stories B and C build against it in parallel.
46
+ - cohort_vbriefs: [vbrief/active/2026-06-01-1378a-allocation-context-schema.vbrief.json, vbrief/active/2026-06-01-1378b-skill-allocation-context-recognition.vbrief.json, vbrief/active/2026-06-01-1378c-preflight-story-start-gate.vbrief.json]
47
+ - operator_approval_evidence: user directive "swarm 1378 per option a" 2026-06-01T02:26Z
48
+ ```
49
+
50
+ A `solo` dispatch sets `dispatch_kind: solo`, MAY leave `allocation_plan_id` / `batching_rationale` null, and lists only its own vBRIEF in `cohort_vbriefs`; such a section does NOT by itself satisfy the consent token, so the Story Start Gate falls through to the #1371 prose carve-out for a lone interactive dispatch.
51
+
52
+ ## 2.6 Provider-neutral worker metadata (#1531)
53
+
54
+ Heterogeneous swarm dispatch (#1531) assigns each worker a **dispatch provider** (the runtime primitive that launched the agent), a **worker role** (what the agent is allowed to do), and a **selected backend** or **routing policy** (how the harness maps that role to a concrete agent). These fields are provider-neutral: Composer-class coding agents, Grok Build (`spawn_subagent`), Cursor/cloud agents, and future adapters share the same contract.
55
+
56
+ ! Every intentional backend-routed dispatch MUST carry a separate `## Worker metadata` section in the dispatch envelope, placed AFTER `## Allocation context` and BEFORE the task body. This section is advisory metadata for the worker and for audit; it does NOT replace, extend, or reorder the five-field #1378 `## Allocation context` recognition contract above.
57
+
58
+ When present, the section documents these fields in order:
59
+
60
+ - `dispatch_provider`: the runtime primitive that launched this worker -- e.g. `spawn_subagent`, `start_agent`, `cursor-composer`, `cursor-cloud-agent`, or a future adapter id. Names the harness surface, not the model.
61
+ - `worker_role`: the role boundary for this dispatch -- one of `leaf-implementation`, `orchestrator`, `review-monitor`, or `merge-release` (stable ids from `scripts/policy.py` `SWARM_WORKER_ROLES`). Tells the worker which preamble rules and skill surfaces apply.
62
+ - `selected_backend`: the stable backend id from `plan.policy.swarmSubagentBackend` / `task policy:subagent-backends` (e.g. `composer`, `grok-build`, `cursor-cloud`) | null -- which catalogued coding backend the operator selected for this role.
63
+ - `routing_policy`: <path or reference to the operator's routing file / tiering policy> | null -- when backend selection is delegated to harness routing instead of a typed policy field, cite the policy handle here so postmortems can reconstruct the route. The canonical handle is the gitignored, per-machine `.deft/routing.local.json` (#1739), keyed by `(dispatch_provider, worker_role)`; set decisions with `task swarm:routing-set -- --role <role> (--model <slug> | --harness-default)`.
64
+ - `resolved_model` (#1739): the concrete model slug the operator pinned for this `(provider, role)` | null for an explicit harness default. Resolved from `.deft/routing.local.json` and stamped into the `task swarm:launch` manifest. **This is the field the dispatch primitive must actually honor** -- see the threading rule below.
65
+ - `model_source` (#1739): provenance of `resolved_model` -- e.g. `cursor-route`, `harness-default explicit`. Lets a postmortem tell a pinned model from a harness default.
66
+
67
+ ! THREADING RULE (#1739): when `resolved_model` is non-null, the orchestrator MUST pass it as the model argument of the actual dispatch primitive (e.g. the Task tool's `model` parameter for a Cursor sub-agent). Stamping the manifest is PREP; the dispatch is agent-driven, so a recorded model that is never passed into the spawn call is the exact bug #1739 closes. For harness-bound providers (e.g. `grok`) the model is chosen by the harness; only `mode: harness-default` is recordable and `resolved_model` stays null.
68
+
69
+ Populate `selected_backend` OR `routing_policy` (or both when the operator sets a default backend and also maintains a routing file). Nullability by role:
70
+
71
+ - `leaf-implementation` + intentionally tiered dispatch: at least one MUST be non-null.
72
+ - `orchestrator`, `review-monitor`, or `merge-release` + explicit backend routing: at least one MUST be non-null so strong-tier audit traces stay reconstructable.
73
+ - Any role on the harness-default agent with no tiering decision: both MAY be null; `dispatch_provider` and `worker_role` remain required.
74
+
75
+ **Role-boundary expectations (all providers):** the same boundaries apply whether the worker runs on Composer, Grok Build, Cursor/cloud, or a future adapter:
76
+
77
+ - ! `leaf-implementation` workers implement scoped vBRIEF work in their assigned worktree only -- gates (`task check`, file-scope audit, Greptile review cycle) are model-agnostic and MUST still pass.
78
+ - ! `orchestrator`, `review-monitor`, and `merge-release` roles MUST run on strong or review-capable agents; dispatchers MUST NOT route these roles to cheap leaf backends.
79
+ - ⊗ Route a cheap leaf backend onto the merge cascade, Phase 5->6 release gate, conflict-resolution rebase, or review-cycle merge-ready decision -- these are irreversible-damage surfaces that stay on the strong tier regardless of provider.
80
+
81
+ **Audit visibility:** review cycles and postmortems MUST be able to reconstruct which backend and role produced a change without inferring it from harness-specific prose.
82
+
83
+ - ! Dispatchers MUST populate `## Worker metadata` in the dispatch envelope whenever backend routing is intentional (headless `task swarm:launch`, monitor dispatch, or manual orchestrator spawn).
84
+ - ! Workers MUST echo `dispatch_provider`, `worker_role`, and `selected_backend` or `routing_policy` (plus `resolved_model` when set, #1739) in the final status message per §11 (e.g. `DONE: ... (commit <sha>, PR #N, role leaf-implementation, model composer-2.5-fast via cursor-route)`). Omitting backend/role/model from the terminal message when metadata was present in the envelope is a hard `⊗`.
85
+
86
+ Worked example (a tiered leaf worker on Composer):
87
+
88
+ ```markdown
89
+ ## Worker metadata
90
+
91
+ - dispatch_provider: cursor-cloud
92
+ - worker_role: leaf-implementation
93
+ - selected_backend: null
94
+ - routing_policy: .deft/routing.local.json
95
+ - resolved_model: composer-2.5-fast
96
+ - model_source: cursor-route
97
+ ```
98
+
99
+ ! Pre-dispatch gate (#1739): run `task verify:routing` before spawning a cohort -- it fails when a dispatched worker role has no decision (pinned model or explicit harness default) for the active provider. Session start runs `task verify:routing -- --advise` (non-blocking disclosure).
100
+
101
+ Reference: `.deft/routing.local.json` + `task swarm:routing-set` + `task verify:routing` (#1739, supersedes the `plan.policy.swarmSubagentBackend` enum of #1531a / #1735), `scripts/policy.py` `SWARM_WORKER_ROLES`, issue #1531 scope update (dispatch provider / worker role / model selection are three separate concerns).
102
+
103
+ ## 2.7 Runtime and GitHub auth mode (#1557)
104
+
105
+ Swarm launch manifests and worker dispatch envelopes MUST carry **runtime** and **GitHub auth mode** labels so each worker knows whether host `gh` credential store access is permitted. These fields are policy labels only -- they MUST NOT contain `GH_TOKEN`, `GITHUB_TOKEN`, `GH_ENTERPRISE_TOKEN`, or any secret token value.
106
+
107
+ When present, document the fields in a separate `## Runtime and GitHub auth mode` section placed AFTER `## Worker metadata` (when present) and BEFORE the task body:
108
+
109
+ - `runtime_mode`: one of `local-unsandboxed`, `cursor-native-sandbox`, or `cloud-headless` -- the execution envelope the worker runs in (from the read-only runtime probe, #1557a).
110
+ - `github_auth_mode`: one of `host-gh` or `injected-token` -- which GitHub credential rule applies to this worker (#1557b).
111
+
112
+ Launch-manifest entries (#1387 C2 contract) carry the same two fields at the top level alongside `allocation_context`. Workers MUST read the dispatch envelope (or launch manifest) and apply the identity-separation rules in §8 according to `github_auth_mode`, not the historical one-size-fits-all injected-token default.
113
+
114
+ Worked example (local interactive worker with validated host gh):
115
+
116
+ ```markdown
117
+ ## Runtime and GitHub auth mode
118
+
119
+ - runtime_mode: local-unsandboxed
120
+ - github_auth_mode: host-gh
121
+ ```
122
+
123
+ Worked example (cloud / headless worker):
124
+
125
+ ```markdown
126
+ ## Runtime and GitHub auth mode
127
+
128
+ - runtime_mode: cloud-headless
129
+ - github_auth_mode: injected-token
130
+ ```
131
+
132
+ Reference: `scripts/platform_capabilities.py` (#1557a), `scripts/github_auth_modes.py` (#1557b), issue #1557.
133
+
134
+ ## 3. PowerShell 5.1 non-ASCII rule (#798)
135
+
136
+ If your shell is `pwsh 5.x` on Windows AND you are editing a file containing any non-ASCII glyph (em dashes, en dashes, arrows, smart quotes, ⊗, ✓, ellipses, emoji, ...), you MUST route the read AND write through Python `pathlib`:
137
+
138
+ ```pwsh path=null start=null
139
+ python -c "import pathlib; p = pathlib.Path('path/to/file.md'); s = p.read_text(encoding='utf-8'); s = s.replace('old', 'new'); p.write_text(s, encoding='utf-8')"
140
+ ```
141
+
142
+ The corruption happens on the READ side (`Get-Content -Raw` decodes via cp1252 / cp437 BEFORE any safe write can preserve the bytes), so a UTF-8 write of already-corrupted text just persists the mojibake. PS 7+ (`pwsh`), bash, and zsh handle UTF-8 correctly and are exempt. The deterministic gate `task verify:encoding` will catch violations in `task check`, but a tooling failure here costs a full review-cycle iteration.
143
+
144
+ This is the recurrence with four prior occurrences (#236 / #240 / #283 / PR #795); do not be the fifth.
145
+
146
+ ## 3.5 Windows Grok Build harness capture limitations (observed 2026-05, #1353)
147
+
148
+ When running under the Grok Build runtime on Windows + pwsh 7+, `run_terminal_command` leaks internal wrapper text (Get-Content and redirection fragments) whenever the command string contains `|`, `2>&1`, `| cat`, `>`, or similar metacharacters. Non-piped commands execute cleanly.
149
+
150
+ **Directive rule:** Never emit commands containing pipes or redirections through the agent shell tool on this platform. For anything requiring a pipe, use one of:
151
+ - Python one-liners with `pathlib` / `subprocess.run(capture_output=True)` (preferred -- bypasses the wrapper at the OS level)
152
+ - Run the operation in the user's native terminal and paste the result back
153
+ - Isolate the work in a dedicated worktree and mark the step as "user shell required"
154
+
155
+ This rule applies to the Grok Build runtime (pwsh 7+); Warp + Claude (PTY-based) is not affected by this wrapper leakage.
156
+
157
+ ## 3.6 Safe subprocess on Windows -- UTF-8 capture helper (#1366)
158
+
159
+ Windows hosts running deft tooling (Grok Build, native PowerShell, scheduled / cloud agents) inherit the locale codepage (cp1252 / cp437) as the default `text=True` decode encoding for `subprocess.run`. When the child process (most commonly `gh api` returning a Greptile rolling-summary body) emits bytes that are not valid in that codepage, Python's internal `Thread-3 (_readerthread)` crashes with `UnicodeDecodeError`. The calling script then returns empty / malformed stdout, and any monitor parsing the JSON sees `head: None` -- the exact failure mode behind the #1166 swarm `Still waiting... (last reviewed: none, head: None)` symptom.
160
+
161
+ **Directive rule:** Any deft script that captures `gh` output or another Python subprocess for parsing MUST route its capture through `scripts/_safe_subprocess.py::run_text` (or pass `encoding="utf-8", errors="replace"` to `subprocess.run` directly). The helper FORCES `capture_output=True`, `text=True`, `encoding="utf-8"`, `errors="replace"`, and `shell=False`; callers cannot regress the safety contract via kwargs.
162
+
163
+ ```python path=null start=null
164
+ # WRONG -- crashes Thread-3 (_readerthread) on Windows when output contains non-cp1252 bytes
165
+ result = subprocess.run(cmd, capture_output=True, text=True, timeout=60)
166
+
167
+ # RIGHT -- bytes that don't decode under utf-8 become U+FFFD; the reader thread never crashes
168
+ from _safe_subprocess import run_text
169
+ result = run_text(cmd, timeout=60)
170
+ ```
171
+
172
+ This rule applies on every platform but BITES on Windows + Grok Build / cmd / PowerShell hosts where the locale codepage is not UTF-8. Linux / macOS hosts generally default to UTF-8 already and so do not reproduce the crash, but routing through `run_text` keeps the behavior identical across platforms.
173
+
174
+ Reference: AGENTS.md `## Safe subprocess capture (#1366)`. Recurrence record: the #1166 swarm session repeatedly observed `Thread-3 (_readerthread) UnicodeDecodeError` across multiple gh-shelling tools; #1366 is the structural fix.
175
+
176
+ ## 3.7 Per-run unique pytest basetemp under concurrent swarm dispatch (#1681)
177
+
178
+ Parallel swarm workers run as the same OS user and, by default, share pytest's `/tmp/pytest-of-<user>/` basetemp root. With `tmp_path_retention_count = 0` (pyproject.toml, #281), one worker's session-startup temp cleanup deletes another worker's in-use `tmp_path`, and `tmp_path_factory.mktemp` then fails with `FileNotFoundError` -- the #1681 cascade observed across three concurrent `task check` runs (~3.3k errors). This is a concurrency-only amplifier: a single run on a clean checkout passes.
179
+
180
+ **Directive rule:** When you run `task check` (or any pytest invocation) inside a swarm cohort -- i.e. concurrently with sibling workers under the same user -- you MUST give pytest a per-run unique basetemp so no two runs share a root. Either prefix a unique `TMPDIR` or set `PYTEST_ADDOPTS=--basetemp=<unique>`:
181
+
182
+ ```bash path=null start=null
183
+ # Preferred: a fresh private temp root per run (also isolates non-pytest tmp use)
184
+ TMPDIR=$(mktemp -d) task check
185
+
186
+ # Equivalent: pin pytest's basetemp explicitly to a unique per-run path
187
+ PYTEST_ADDOPTS="--basetemp=$(mktemp -d)/pt" task check
188
+ ```
189
+
190
+ A clean result under an isolated basetemp is attributable to your change, not to the ambient shared-`/tmp` race. Do NOT point `--basetemp` at a static path shared across workers -- that re-introduces the collision. Solo / single-run invocations on a private worktree do not require this, but it is harmless to apply unconditionally.
191
+
192
+ ## 4. pre-pr and review-cycle skills
193
+
194
+ Before pushing any branch:
195
+
196
+ - Run `skills/deft-directive-pre-pr/SKILL.md` end-to-end. The skill's RWLD loop (read, write, lint, doc) catches the easy stuff before Greptile sees it.
197
+ - After opening the PR, run `skills/deft-directive-review-cycle/SKILL.md` end-to-end on bot findings. Cap iterations at 3 unless the user explicitly extends.
198
+
199
+ Anti-pattern: pushing without pre-pr and relying on Greptile to find issues. That burns review-cycle iterations on issues you could have caught locally; each iteration costs GraphQL budget under your shared identity.
200
+
201
+ ## 5. REST-by-default for read-only gh calls
202
+
203
+ The GraphQL bucket (5000 pts/hr) is the operational bottleneck under shared-identity workflows, not the REST `core` bucket. Every read-only GitHub API call MUST prefer REST:
204
+
205
+ ```pwsh path=null start=null
206
+ # REST -- preferred
207
+ gh api repos/<owner>/<repo>/issues/<N> -q '.title,.state'
208
+ gh api repos/<owner>/<repo>/pulls/<N> -q '.draft,.mergeable_state'
209
+ ghx api repos/<owner>/<repo>/issues/<N> # cached REST via ghx; even better
210
+
211
+ # GraphQL -- forbidden in steady-state polling
212
+ gh issue view <N> --json title,state # GraphQL
213
+ gh pr view <N> --json draft,mergeable # GraphQL
214
+ gh pr ready <N> # GraphQL mutation (mutation, not poll)
215
+ gh pr update-branch <N> # GraphQL mutation
216
+ ```
217
+
218
+ The forbidden surfaces are convenient and well-documented but route through GraphQL; under N concurrent workers they exhaust the bucket within minutes. Use the explicit REST forms above. Mutations to REST endpoints (`gh api -X POST/PATCH/PUT/DELETE /repos/...`) do not consume GraphQL budget and are fine; mutations to the `/graphql` endpoint (`gh api -X POST /graphql -f query=...`) DO consume GraphQL budget and are subject to the same throttle.
219
+
220
+ ## 5.5 Safe Markdown body posting (#1555)
221
+
222
+ Markdown-rich GitHub bodies MUST NOT be embedded inside double-quoted shell commands. In Bash and zsh, backticks perform command substitution before `gh` receives the text, so a phrase like ``"include `ghx`"`` can be posted as the output of running `ghx` instead of the literal Markdown.
223
+
224
+ Use the canonical safe wrapper for issue bodies, PR bodies, and issue/PR comments:
225
+
226
+ ```bash path=null start=null
227
+ task scm:body:comment:create -- --repo OWNER/REPO --issue 1555 --body-file "$bodyFile"
228
+ task scm:body:comment:edit -- --repo OWNER/REPO --comment 123456789 --body-file "$bodyFile"
229
+ task scm:body:issue:create -- --repo OWNER/REPO --title "Title" --body-file "$bodyFile"
230
+ task scm:body:issue:edit -- --repo OWNER/REPO --issue 1555 --body-file "$bodyFile"
231
+ task scm:body:pr:edit -- --repo OWNER/REPO --pr 42 --body-file "$bodyFile"
232
+ ```
233
+
234
+ The wrapper reads UTF-8 body text from a file or stdin, sends JSON to `gh api --input -` via `_safe_subprocess.run_text` with `shell=False`, and prints the live post-mutation read-back object. Use live `gh` for immediate verification after mutations; do not use `ghx` for the first read-back because it may serve a cached stale GET.
235
+
236
+ ## 6. No Draft re-toggling within a single review cycle
237
+
238
+ Once a PR transitions Draft -> Ready, keep it Ready unless a P0 finding requires re-Draft. Repeated Draft<->Ready toggles cost GraphQL mutations and trigger stale CheckRun states downstream (Greptile re-runs, branch-protection re-evaluations).
239
+
240
+ The PR #652 merge-cascade incident traced back to a Draft re-toggle that hid a stale Greptile verdict from `gh pr view --json`'s cache. The mitigation: at most one toggle per cycle.
241
+
242
+ Anti-pattern: re-Drafting a PR to "indicate work in progress" between review iterations. Use commit-status messages or PR comments instead.
243
+
244
+ ## 7. Rate-limit-aware throttle
245
+
246
+ Before any GraphQL-heavy operation (PR readiness check loop, batch issue ingest, review-cycle Greptile polling, mass `gh pr list`), probe the rate limit:
247
+
248
+ ```pwsh path=null start=null
249
+ gh api rate_limit -q '{core: .resources.core.remaining, graphql: .resources.graphql.remaining}'
250
+ # {
251
+ # "core": 4998,
252
+ # "graphql": 3989
253
+ # }
254
+ ```
255
+
256
+ Decision tree:
257
+
258
+ - `graphql.remaining >= 1500` -- GraphQL paths are fine
259
+ - `500 <= graphql.remaining < 1500` -- prefer REST equivalents; defer non-essential GraphQL polling
260
+ - `graphql.remaining < 500` -- HALT GraphQL paths; switch to REST or batch+wait until reset (`reset` field is a unix timestamp)
261
+ - `core.remaining < 500` -- you have bigger problems; stop and escalate
262
+
263
+ The probe itself is a `core`-bucket call, so polling it cheaply does not consume GraphQL.
264
+
265
+ ## 8. Identity separation -- mode-aware GitHub credential rules (#983 / #1557)
266
+
267
+ Workers MUST follow the GitHub credential rule recorded in the dispatch envelope's `github_auth_mode` field (§2.7) or launch manifest. The rule prevents maintainer/worker bucket coupling and audit conflation when modes are mixed across a cohort.
268
+
269
+ Why: maintainer and workers sharing a single PAT couples the human review/merge workflow and N concurrent workers onto one 5,000-req/hr GraphQL bucket per identity. The architectural fix is bucket partitioning by identity -- the maintainer keeps their PAT for review/merge/release, workers consume a dedicated bot account or GitHub App installation token (injected-token mode) or an explicitly approved host `gh` session (host-gh mode). The full pattern lives at `patterns/multi-agent.md`.
270
+
271
+ ### injected-token mode (required for `github_auth_mode: injected-token` and always for `runtime_mode: cloud-headless`)
272
+
273
+ - ! Consume the GitHub credential injected by the dispatcher (typically `GH_TOKEN` / `GITHUB_TOKEN` / `GH_ENTERPRISE_TOKEN` in the prompt-supplied env). If unset and no other dispatcher-supplied credential is present, FAIL LOUD -- do not silently run under the host's `gh auth status` token.
274
+ - ~ Confirm the credential's identity matches expectation: `gh api user --jq .login` should return the bot/App login, not the maintainer login. Mismatch is `BLOCKED: identity mismatch` to the parent.
275
+ - ⊗ Inherit the maintainer's `gh auth status` token implicitly. Host `gh` fallback is forbidden in injected-token and cloud-headless modes.
276
+
277
+ ### host-gh mode (permitted only when `github_auth_mode: host-gh`)
278
+
279
+ Applies to local interactive workers (`runtime_mode: local-unsandboxed` or, after validation, `cursor-native-sandbox`) where swarm launch preflight confirmed `gh auth status` and repo access from the worker environment.
280
+
281
+ - ! Use the worker environment's `gh` credential store -- the dispatch envelope explicitly authorises host `gh` for this worker. Do NOT require an injected `GH_TOKEN` when host gh auth is already valid in the worker shell.
282
+ - ! Still verify identity before GitHub operations: `gh auth status` must pass and `gh api user --jq .login` must return the expected account.
283
+ - ⊗ Fall back to host `gh` when `github_auth_mode` is `injected-token` or `runtime_mode` is `cloud-headless` -- those modes forbid host credential store use regardless of what is available on the host.
284
+ - ~ When `runtime_mode: cursor-native-sandbox`, host `gh` may fail inside the sandbox even when the parent session is authenticated. Fail loud with remediation (full-access execution, trusted-path allowlist, or switch to injected-token handoff) rather than assuming parent auth is visible to the worker.
285
+
286
+ Dispatchers MUST inject worker credentials for injected-token / cloud-headless dispatches and MUST record the selected `github_auth_mode` in the launch manifest and dispatch envelope. v1 deliberately keeps token injection operator-implemented; mode labels make the contract explicit without placing token values in prompts or transcripts.
287
+
288
+ This rule is complementary to §5 (REST-by-default) and §7 (rate-limit-aware throttle): REST-by-default reduces GraphQL demand on whichever bucket the worker is using; rate-limit throttle keeps the worker from exhausting its own bucket; mode-aware identity separation prevents the worker bucket from being the maintainer's bucket when injected-token mode applies. All three are required for stable swarm operation.
289
+
290
+ ## 9. Sub-agent spawn rules per #727
291
+
292
+ If you (the worker) need to spawn a sub-agent yourself:
293
+
294
+ - Sub-agents MUST have non-overlapping file scopes. Use the parent vBRIEF's `files_owned` / `files_must_not_touch` to partition.
295
+ - Destructive operations (worktree removal, branch deletion, force-push) run alone, never in parallel.
296
+ - Each sub-agent receives its own dispatch envelope including this preamble (or a reference to it).
297
+ - Each child dispatch MUST carry its own `## Worker metadata` section per §2.6 when backend routing applies: set `dispatch_provider` and `worker_role` for the child's actual harness and role; propagate or override `selected_backend` / `routing_policy` so audit trails remain reconstructable at every tree depth (#1531).
298
+ - Coordinate shared append-only files (CHANGELOG, lessons.md) with explicit ownership at dispatch time.
299
+ - Sub-agents inherit the parent worker's credential policy: when the parent dispatch is `github_auth_mode: injected-token`, children MUST use the injected token; when `host-gh`, children inherit the same host-gh authorisation. They MUST NOT mint or fall back to a different credential mode than the parent envelope specifies. Identity separation per §8 cascades through the spawn tree.
300
+
301
+ ### Orchestrator dispatch doctrine (#1880)
302
+
303
+ These rules bind **orchestrators** dispatching implementation, fix, or review-cycle workers (not only workers spawning their own children). Root cause: the 2026-06-22 #1878 session split implementation and review across separate leaf dispatches and blocked the parent conversation on long-running workers.
304
+
305
+ **Worker-owns-lifecycle (Gap C):**
306
+
307
+ - ! When dispatching an implementation worker, the dispatch envelope MUST declare the unit-of-work boundary explicitly: `stop-at: pr-open` (worker opens PR and exits) OR `drive-to: merge-ready` (worker owns PR + Greptile review cycle + fix batches through merge-ready as ONE unit of work, spawning its own review poller per `skills/deft-directive-review-cycle/SKILL.md` monitoring tiers). Default for story implementation dispatches is `drive-to: merge-ready`.
308
+ - ! Workers scoped `drive-to: merge-ready` MUST drive to merge-ready in their own tool loop — pre-PR, push, PR open, review-cycle poll/fix loop, and the #1259 Step 6 fail-closed exit — without handing back at PR-open for the orchestrator to re-dispatch separate leaf agents for review or fixes.
309
+ - ⊗ Re-dispatch a separate review-monitor or fix agent after an implementation worker exits at PR-open when the original envelope scoped `drive-to: merge-ready` — that split recreates cross-agent state-handoff hazards and terminal lifecycle gaps (#1878 / Gap C).
310
+
311
+ **Background / independent dispatch (Gap D):**
312
+
313
+ - ! Long-running workers (expected >~3 min: implementation, fix batches, review-cycle owners, pollers) MUST be dispatched independently / in the background so the parent conversation channel stays interactive and the orchestrator is notified on completion (`DONE` / `BLOCKED` / `FAILED` per §11).
314
+ - ! On Cursor, background dispatch means the Task tool's background path (`run_in_background: true` on the Task invocation) — NOT blocking the orchestrator's turn for the worker's full wall-clock.
315
+ - ⊗ Foreground/blocking dispatch for long-running implementation, fix, or review-cycle workers when a background/independent dispatch primitive is available — blocking locks the conversation and prevents user steerability (#1878 / Gap D).
316
+ - ~ Foreground dispatch is reserved for short tasks (<~3 min): quick probes, single-command checks, terse status reads.
317
+
318
+ **Deliberate model routing before ANY dispatch (doctrine; enforcement #1877):**
319
+
320
+ - ! Before dispatching ANY sub-agent (cohort OR single), the orchestrator MUST make a deliberate per-`worker_role` model-routing decision — consult `task verify:routing` / `task swarm:routing-set`, populate `## Worker metadata` per §2.6, and pass `resolved_model` into the actual dispatch primitive when non-null. Never silently inherit the parent orchestrator's model.
321
+ - ⊗ Dispatch a worker without a recorded routing decision for its `(dispatch_provider, worker_role)` pair when backend routing applies — silent inheritance of the parent model is forbidden.
322
+ - ~ Deterministic gate enforcement for undecided routes is tracked in #1877; this subsection is the behavioral rule only.
323
+
324
+ Reference: issue #1880 (doctrine), #1877 (gate enforcement), #954 (multi-agent discipline). Cross-references: `skills/deft-directive-swarm/SKILL.md` Phase 3 dispatch + Phase 5→6, `skills/deft-directive-review-cycle/SKILL.md` Review Monitoring.
325
+
326
+ ## 10. Dispatcher lifecycle hygiene -- workers are all-or-nothing
327
+
328
+ If your dispatch envelope contains a "pause for user approval" step in the middle of the worker's scope, REWRITE IT into two dispatches:
329
+
330
+ - WRONG: `Implement deliverables 1-3, then pause and wait for user confirmation before opening the PR.`
331
+ - Worker implements 1-3, sends "paused, awaiting confirmation" message, exits its tool loop, lifecycle goes `succeeded` (terminal). User approval message hits a dead `agent_id`. Dispatcher must spawn a successor anyway -- the gate accomplished nothing except adding a context-handoff cost.
332
+ - CORRECT: two dispatches
333
+ - Dispatch A: `Implement deliverables 1-3, push, report DONE.` Worker completes, lifecycle goes `succeeded`.
334
+ - User reviews diff.
335
+ - Dispatch B: `Open PR via REST, apply label, run review-cycle skill.`
336
+
337
+ Lifecycle events (`succeeded`, `failed`, `blocked`, `in_progress`, `cancelled`, `errored`) are emitted by the platform observing the worker's process state -- the worker does not choose them directly. A worker that finishes its tool loop with a "paused" message will be observed as `succeeded` (terminal); the agent_id becomes unreachable. The only ways for a worker to remain reachable mid-flight are: keep the tool loop alive (long-lived poll / sleep) or be observed by the platform as `blocked` via a sanctioned blocked_action. Neither is a natural fit for "I finished sub-task A and want approval before sub-task B."
338
+
339
+ Workers must therefore be all-or-nothing on their dispatch envelope. Approval gates split scope at the dispatcher layer.
340
+
341
+ Reference: scope-expansion comment 4399553752 on issue #954.
342
+
343
+ ## 10.5 Heartbeat contract (#1365)
344
+
345
+ Long-running `spawn_subagent` review-cycle agents on the Grok Build hybrid swarm path can go completely dark from the monitor's perspective -- no commits, no PR comments, no completion notifications. The #1166 swarm session demonstrated the failure mode: two of three dispatched pollers produced zero observable signals; the monitor could not distinguish stalled from healthy.
346
+
347
+ The heartbeat contract closes that gap. Any sub-agent whose tool loop is expected to run for more than ~3 minutes (review-cycle pollers, watchdogs, long-running implementation agents) MUST emit a small JSON heartbeat at `<project-root>/.deft-scratch/subagent-status/<agent-id>.json` per `docs/subagent-heartbeat.md`.
348
+
349
+ The contract in one paragraph:
350
+
351
+ - Write a heartbeat IMMEDIATELY on startup (`phase: "starting"`).
352
+ - Re-write the heartbeat at minimum every 2-3 minutes during normal operation. The canonical poller template's 90s poll cadence satisfies this for free -- one heartbeat per poll iteration.
353
+ - Write a FINAL heartbeat right before exiting with `phase: "terminal"` and `terminal_state` populated with the canonical exit name (`CLEAN` / `ERRORED` / `TIMEOUT` / `STALL` / `FAILED` / `BLOCKED`). The terminal heartbeat is what tells the monitor "finished cleanly" vs "went silent".
354
+ - The record is JSON with at least `agent_id` (matches filename), `parent_id`, `last_heartbeat_at` (ISO-8601 UTC, `Z`-suffix), `last_message` (one human-readable line), `phase` (one of `starting | implementing | validating | committing | pushing | polling | fixing | terminal`), and optional `terminal_state`.
355
+ - Writes MUST be atomic (write-to-temp + rename) so the monitor never reads a half-written file.
356
+
357
+ The parent monitor watches via `scripts/subagent_monitor.py` (three-state exit 0 ok / 1 stale-or-malformed / 2 config error). Skipping the heartbeat is a hard `⊗` for any long-running sub-agent: a stalled agent with no heartbeat surface is the exact #1166 failure mode this contract closes.
358
+
359
+ ## 11. Mandatory DONE message even on early exit
360
+
361
+ Every worker MUST send a final status message before exiting its tool loop, regardless of outcome:
362
+
363
+ - Success: `DONE: <one-line summary> (commit <sha>, PR #N)` -- when the dispatch envelope carried `## Worker metadata` per §2.6, extend the parenthetical with `role <worker_role>` and `backend <selected_backend|routing_policy>` (e.g. `DONE: ... (commit <sha>, PR #N, role leaf-implementation, backend composer)`).
364
+ - Halted at cap: `BLOCKED: <reason> (review-cycle iter <i>/3, wall-clock <t>m/<cap>m)`
365
+ - Failure: `FAILED: <reason> + recovery hint`
366
+ - Stand-down: `STOOD-DOWN: <reason>` (e.g. user said "wait" with no follow-up dispatch)
367
+
368
+ Per-step acks during the run are noise. ONE start message, ONE final message; intermediate messages only on `BLOCKED` / `FAILED`. The final message lets the dispatcher distinguish a clean exit from a silent timeout when the lifecycle event arrives.
369
+
370
+ ## 12. Session ritual + `task verify:cache-fresh` gates before `start_agent` (#1348 / #1127)
371
+
372
+ Dispatchers (this orchestrator, swarm Phase 4 dispatch, monitor agents, scheduled / cloud runs) run in a headless worker context and MUST set `DEFT_SESSION_RITUAL_SKIP=1` for dispatched implementation workers. The interactive parent session remains responsible for `task session:start`; worker processes bypass the local `.deft/ritual-state.json` gate explicitly so they do not need per-clone interactive ritual state. When the bypass would hide a stale/missing ritual state, `task verify:session-ritual` prints a warning to stderr; preserve that warning in the dispatch log.
373
+
374
+ Dispatchers MUST run `task verify:cache-fresh --for-issue <N>` immediately before any `start_agent` invocation that will dispatch an implementation sub-agent for upstream issue N, and MUST refuse dispatch on any non-zero exit. The cache gate follows the session ritual gate in the canonical pre-`start_agent` gate stack documented in `AGENTS.md` (`verify:session-ritual` -> Story Start Gate -> Implementation Intent Gate -> `verify:cache-fresh` -> branch-policy gate -> `start_agent`).
375
+
376
+ The gate is detection-bound and has three exit states (mirrors the #747 branch gate):
377
+
378
+ - `0` -- cache fresh, target issue's latest decision is `accept`, and the issue is inside the active `plan.policy.triageScope[]` subscription (D12 / #1131). Proceed to `start_agent`.
379
+ - `1` -- cache is stale OR a blocking condition was found (issue's latest decision is `defer` / `reject` / `needs-ac` / `mark-duplicate` / absent, OR the issue is outside the active subscription, OR no cached entry exists for the issue under the resolved subscription). The dispatcher MUST refuse `start_agent` and surface the printed remediation (cite `task triage:bootstrap` / `task cache:fetch-all` for staleness, `task triage:accept` / `task triage:scope --list` for the gating decision).
380
+ - `2` -- config error: `.deft-cache/` is absent or `vbrief/.eval/candidates.jsonl` is missing. The dispatcher MUST refuse `start_agent` and surface the bootstrap recovery line (`task triage:bootstrap`). This is the never-bootstrapped case and is distinct from the stale-cache case so the operator sees the right action.
381
+
382
+ The `--allow-stale` override is per-shell and audited: the dispatcher MAY pass it after operator approval when the upstream issue body is known to be stable across the freshness window, but the override is logged to stderr and SHOULD be cited in the dispatch envelope so a downstream reviewer can audit the decision. Never silently strip the `--for-issue` arg to clear a failing gate; that defeats the contract.
383
+
384
+ The `--allow-missing-bootstrap` flag exists for the framework's own `task check` wiring (so a fresh framework checkout doesn't fail its own `verify:cache-fresh` aggregate run) and MUST NOT be passed by dispatchers. Consumer dispatchers leave it OFF; a missing cache is a real failure for them.
385
+
386
+ Reference: the gate is implemented at `scripts/preflight_cache.py` and exposed via `task verify:cache-fresh`; the subscription scope is read via the D12 surface `scripts/triage_scope.py` so a consumer that has tightened `plan.policy.triageScope[]` is not gated by stale entries outside their subscription.
387
+
388
+ ## 13. Cancellation Attribution (#1300)
389
+
390
+ When a tool result reports `cancelled` / `aborted` / `killed`, default to **runtime glitch, not user intent.** Tool-runtime signals (parallel-batch limits, network glitches, server 5xx, timeouts, scheduler interruptions, IPC drops) look identical to a real user-issued cancel and MUST NOT be attributed to the user without direct user-side evidence. The canonical rule body lives at `main.md` `## Cancellation Attribution (#1300)`; this section is the worker-side propagation so dispatched sub-agents inherit the behavior.
391
+
392
+ Required flow on any `cancelled` / `aborted` / `killed` tool result:
393
+
394
+ 1. Retry the affected operation SEQUENTIALLY (one at a time) before drawing any conclusion about user intent.
395
+ 2. If the retry succeeds, treat the original event as a runtime glitch -- do NOT tell the user they cancelled.
396
+ 3. If the retry also fails the same way, surface the actual error to the user and ASK whether they intended to cancel -- do not assert it.
397
+ 4. Reserve "you cancelled" / "you stopped" / "you declined" phrasing for cases where the user explicitly performed a cancellation gesture (terminal Ctrl-C, an explicit "stop" / "cancel" / "abort" instruction in chat, an explicit decline of a confirmation prompt).
398
+
399
+ Dispatchers reading lifecycle events: the platform-emitted `cancelled` lifecycle state (see §10) is also subject to this rule -- a worker that the platform reports as `cancelled` is NOT necessarily a worker the user cancelled. Probe before attributing; the live incident motivating this rule was a parallel `gh issue edit` batch where three of four calls returned `{"cancelled":true}` from the runtime, the orchestrator told the operator "you cancelled the other three", and a sequential retry rescued all three immediately.
400
+
401
+ Anti-pattern: a parallel batch returns `{"cancelled":true}` on N-1 of N calls, the agent reports "you cancelled the other N-1", and the operator has to correct the agent before a sequential retry rescues the work. The sequential retry is the rule; reaching for user-intent attribution before retrying is the failure mode.
402
+
403
+ Forbidden phrasing without direct user-side evidence: `you cancelled`, `you stopped`, `you declined`. SHOULD phrasing when reporting a probable runtime cancellation: "N parallel calls returned cancelled -- likely a runtime hiccup; retrying sequentially."
404
+
405
+ ## Footer
406
+
407
+ If any rule above conflicts with the user's explicit in-conversation directive, ASK rather than improvise. Rules represent the project's institutional memory; the user can override on a case-by-case basis but the dispatcher should surface the conflict, not silently bypass.
408
+
409
+ This template is owned by `vbrief/active/2026-05-07-954-orchestrator-agents-md-preamble-template.vbrief.json` (lifecycle-moves to `vbrief/completed/` on PR merge) and may be revised via a #954-tagged PR.