@pennixrv/trellis 0.7.1-beta.9 → 0.7.2-beta.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 (231) hide show
  1. package/dist/cli/index.js +4 -4
  2. package/dist/cli/index.js.map +1 -1
  3. package/dist/commands/init.d.ts.map +1 -1
  4. package/dist/commands/init.js +39 -26
  5. package/dist/commands/init.js.map +1 -1
  6. package/dist/commands/teamwork/adapters/acp.d.ts +20 -0
  7. package/dist/commands/teamwork/adapters/acp.d.ts.map +1 -0
  8. package/dist/commands/teamwork/adapters/acp.js +268 -0
  9. package/dist/commands/teamwork/adapters/acp.js.map +1 -0
  10. package/dist/commands/teamwork/adapters/claude.d.ts +1 -0
  11. package/dist/commands/teamwork/adapters/claude.d.ts.map +1 -1
  12. package/dist/commands/teamwork/adapters/claude.js +5 -0
  13. package/dist/commands/teamwork/adapters/claude.js.map +1 -1
  14. package/dist/commands/teamwork/adapters/codex.d.ts +3 -2
  15. package/dist/commands/teamwork/adapters/codex.d.ts.map +1 -1
  16. package/dist/commands/teamwork/adapters/codex.js +14 -15
  17. package/dist/commands/teamwork/adapters/codex.js.map +1 -1
  18. package/dist/commands/teamwork/adapters/index.d.ts +23 -1
  19. package/dist/commands/teamwork/adapters/index.d.ts.map +1 -1
  20. package/dist/commands/teamwork/adapters/index.js +163 -24
  21. package/dist/commands/teamwork/adapters/index.js.map +1 -1
  22. package/dist/commands/teamwork/agent-loader.d.ts +2 -1
  23. package/dist/commands/teamwork/agent-loader.d.ts.map +1 -1
  24. package/dist/commands/teamwork/agent-loader.js +2 -1
  25. package/dist/commands/teamwork/agent-loader.js.map +1 -1
  26. package/dist/commands/teamwork/artifact.d.ts +33 -10
  27. package/dist/commands/teamwork/artifact.d.ts.map +1 -1
  28. package/dist/commands/teamwork/artifact.js +182 -50
  29. package/dist/commands/teamwork/artifact.js.map +1 -1
  30. package/dist/commands/teamwork/batch-reservation.d.ts +16 -0
  31. package/dist/commands/teamwork/batch-reservation.d.ts.map +1 -0
  32. package/dist/commands/teamwork/batch-reservation.js +43 -0
  33. package/dist/commands/teamwork/batch-reservation.js.map +1 -0
  34. package/dist/commands/teamwork/batch.d.ts +22 -0
  35. package/dist/commands/teamwork/batch.d.ts.map +1 -0
  36. package/dist/commands/teamwork/batch.js +394 -0
  37. package/dist/commands/teamwork/batch.js.map +1 -0
  38. package/dist/commands/teamwork/context-loader.d.ts +1 -1
  39. package/dist/commands/teamwork/context-loader.d.ts.map +1 -1
  40. package/dist/commands/teamwork/context-loader.js +19 -6
  41. package/dist/commands/teamwork/context-loader.js.map +1 -1
  42. package/dist/commands/teamwork/coordination.d.ts +88 -0
  43. package/dist/commands/teamwork/coordination.d.ts.map +1 -0
  44. package/dist/commands/teamwork/coordination.js +153 -0
  45. package/dist/commands/teamwork/coordination.js.map +1 -0
  46. package/dist/commands/teamwork/coordinator.d.ts +17 -3
  47. package/dist/commands/teamwork/coordinator.d.ts.map +1 -1
  48. package/dist/commands/teamwork/coordinator.js +772 -289
  49. package/dist/commands/teamwork/coordinator.js.map +1 -1
  50. package/dist/commands/teamwork/create.d.ts +1 -0
  51. package/dist/commands/teamwork/create.d.ts.map +1 -1
  52. package/dist/commands/teamwork/create.js +2 -1
  53. package/dist/commands/teamwork/create.js.map +1 -1
  54. package/dist/commands/teamwork/dev-parse-trace.d.ts +2 -1
  55. package/dist/commands/teamwork/dev-parse-trace.d.ts.map +1 -1
  56. package/dist/commands/teamwork/dev-parse-trace.js +2 -0
  57. package/dist/commands/teamwork/dev-parse-trace.js.map +1 -1
  58. package/dist/commands/teamwork/foreground-wait.d.ts +6 -0
  59. package/dist/commands/teamwork/foreground-wait.d.ts.map +1 -0
  60. package/dist/commands/teamwork/foreground-wait.js +65 -0
  61. package/dist/commands/teamwork/foreground-wait.js.map +1 -0
  62. package/dist/commands/teamwork/guard.d.ts +2 -2
  63. package/dist/commands/teamwork/guard.d.ts.map +1 -1
  64. package/dist/commands/teamwork/guard.js +23 -5
  65. package/dist/commands/teamwork/guard.js.map +1 -1
  66. package/dist/commands/teamwork/index.d.ts.map +1 -1
  67. package/dist/commands/teamwork/index.js +139 -10
  68. package/dist/commands/teamwork/index.js.map +1 -1
  69. package/dist/commands/teamwork/kill.d.ts +2 -0
  70. package/dist/commands/teamwork/kill.d.ts.map +1 -1
  71. package/dist/commands/teamwork/kill.js +79 -38
  72. package/dist/commands/teamwork/kill.js.map +1 -1
  73. package/dist/commands/teamwork/messages.d.ts.map +1 -1
  74. package/dist/commands/teamwork/messages.js +3 -0
  75. package/dist/commands/teamwork/messages.js.map +1 -1
  76. package/dist/commands/teamwork/plan.d.ts +22 -0
  77. package/dist/commands/teamwork/plan.d.ts.map +1 -0
  78. package/dist/commands/teamwork/plan.js +288 -0
  79. package/dist/commands/teamwork/plan.js.map +1 -0
  80. package/dist/commands/teamwork/process-identity.d.ts +3 -0
  81. package/dist/commands/teamwork/process-identity.d.ts.map +1 -0
  82. package/dist/commands/teamwork/process-identity.js +24 -0
  83. package/dist/commands/teamwork/process-identity.js.map +1 -0
  84. package/dist/commands/teamwork/profiles.d.ts +43 -6
  85. package/dist/commands/teamwork/profiles.d.ts.map +1 -1
  86. package/dist/commands/teamwork/profiles.js +138 -110
  87. package/dist/commands/teamwork/profiles.js.map +1 -1
  88. package/dist/commands/teamwork/prompt.d.ts +4 -0
  89. package/dist/commands/teamwork/prompt.d.ts.map +1 -0
  90. package/dist/commands/teamwork/prompt.js +33 -0
  91. package/dist/commands/teamwork/prompt.js.map +1 -0
  92. package/dist/commands/teamwork/result.d.ts +54 -0
  93. package/dist/commands/teamwork/result.d.ts.map +1 -0
  94. package/dist/commands/teamwork/result.js +94 -0
  95. package/dist/commands/teamwork/result.js.map +1 -0
  96. package/dist/commands/teamwork/rm.d.ts.map +1 -1
  97. package/dist/commands/teamwork/rm.js +64 -64
  98. package/dist/commands/teamwork/rm.js.map +1 -1
  99. package/dist/commands/teamwork/run.d.ts +5 -0
  100. package/dist/commands/teamwork/run.d.ts.map +1 -1
  101. package/dist/commands/teamwork/run.js +120 -24
  102. package/dist/commands/teamwork/run.js.map +1 -1
  103. package/dist/commands/teamwork/runtime.d.ts +9 -0
  104. package/dist/commands/teamwork/runtime.d.ts.map +1 -0
  105. package/dist/commands/teamwork/runtime.js +372 -0
  106. package/dist/commands/teamwork/runtime.js.map +1 -0
  107. package/dist/commands/teamwork/send.d.ts +1 -0
  108. package/dist/commands/teamwork/send.d.ts.map +1 -1
  109. package/dist/commands/teamwork/send.js +2 -1
  110. package/dist/commands/teamwork/send.js.map +1 -1
  111. package/dist/commands/teamwork/spawn.d.ts +10 -3
  112. package/dist/commands/teamwork/spawn.d.ts.map +1 -1
  113. package/dist/commands/teamwork/spawn.js +41 -29
  114. package/dist/commands/teamwork/spawn.js.map +1 -1
  115. package/dist/commands/teamwork/store/lock.js +28 -4
  116. package/dist/commands/teamwork/store/lock.js.map +1 -1
  117. package/dist/commands/teamwork/supervisor/inbox.d.ts +1 -0
  118. package/dist/commands/teamwork/supervisor/inbox.d.ts.map +1 -1
  119. package/dist/commands/teamwork/supervisor/inbox.js +28 -9
  120. package/dist/commands/teamwork/supervisor/inbox.js.map +1 -1
  121. package/dist/commands/teamwork/supervisor/stdout.d.ts.map +1 -1
  122. package/dist/commands/teamwork/supervisor/stdout.js +2 -3
  123. package/dist/commands/teamwork/supervisor/stdout.js.map +1 -1
  124. package/dist/commands/teamwork/supervisor/warning.d.ts.map +1 -1
  125. package/dist/commands/teamwork/supervisor/warning.js +2 -3
  126. package/dist/commands/teamwork/supervisor/warning.js.map +1 -1
  127. package/dist/commands/teamwork/supervisor.d.ts +5 -0
  128. package/dist/commands/teamwork/supervisor.d.ts.map +1 -1
  129. package/dist/commands/teamwork/supervisor.js +21 -12
  130. package/dist/commands/teamwork/supervisor.js.map +1 -1
  131. package/dist/commands/teamwork/teammate-adapters.d.ts +0 -3
  132. package/dist/commands/teamwork/teammate-adapters.d.ts.map +1 -1
  133. package/dist/commands/teamwork/teammate-adapters.js +9 -54
  134. package/dist/commands/teamwork/teammate-adapters.js.map +1 -1
  135. package/dist/commands/teamwork/teammate-config.d.ts +5 -1
  136. package/dist/commands/teamwork/teammate-config.d.ts.map +1 -1
  137. package/dist/commands/teamwork/teammate-config.js +62 -19
  138. package/dist/commands/teamwork/teammate-config.js.map +1 -1
  139. package/dist/commands/teamwork/teammate-launch.d.ts +14 -4
  140. package/dist/commands/teamwork/teammate-launch.d.ts.map +1 -1
  141. package/dist/commands/teamwork/teammate-launch.js +129 -20
  142. package/dist/commands/teamwork/teammate-launch.js.map +1 -1
  143. package/dist/commands/teamwork/wait.d.ts +2 -0
  144. package/dist/commands/teamwork/wait.d.ts.map +1 -1
  145. package/dist/commands/teamwork/wait.js +44 -3
  146. package/dist/commands/teamwork/wait.js.map +1 -1
  147. package/dist/commands/update.d.ts.map +1 -1
  148. package/dist/commands/update.js +4 -3
  149. package/dist/commands/update.js.map +1 -1
  150. package/dist/configurators/workflow.d.ts.map +1 -1
  151. package/dist/configurators/workflow.js +14 -32
  152. package/dist/configurators/workflow.js.map +1 -1
  153. package/dist/migrations/manifests/0.7.1-beta.10.json +9 -0
  154. package/dist/migrations/manifests/0.7.1-beta.11.json +9 -0
  155. package/dist/migrations/manifests/0.7.1-beta.12.json +9 -0
  156. package/dist/migrations/manifests/0.7.1-beta.13.json +9 -0
  157. package/dist/migrations/manifests/0.7.1-beta.14.json +11 -0
  158. package/dist/migrations/manifests/0.7.1-beta.15.json +9 -0
  159. package/dist/migrations/manifests/0.7.1-beta.16.json +9 -0
  160. package/dist/migrations/manifests/0.7.1-beta.17.json +9 -0
  161. package/dist/migrations/manifests/0.7.1-beta.18.json +9 -0
  162. package/dist/migrations/manifests/0.7.1-beta.19.json +9 -0
  163. package/dist/migrations/manifests/0.7.1-beta.6.json +1 -1
  164. package/dist/migrations/manifests/0.7.2-beta.0.json +11 -0
  165. package/dist/templates/codex/hooks/session-start.py +14 -11
  166. package/dist/templates/codex/hooks.json +10 -0
  167. package/dist/templates/common/bundled-skills/trellis-meta/references/local-architecture/multi-agent-teamwork.md +14 -2
  168. package/dist/templates/common/bundled-skills/trellis-meta/references/local-architecture/task-system.md +1 -1
  169. package/dist/templates/common/bundled-skills/trellis-solution-design-and-convergence/workflow.md +4 -0
  170. package/dist/templates/common/bundled-skills/trellis-task-implementation/workflow.md +6 -0
  171. package/dist/templates/common/bundled-skills/trellis-teamwork/SKILL.md +14 -4
  172. package/dist/templates/common/bundled-skills/trellis-teamwork/references/coordination-modes.md +31 -2
  173. package/dist/templates/common/bundled-skills/trellis-teamwork/references/teammate-configuration-matrix.md +37 -31
  174. package/dist/templates/common/bundled-skills/trellis-teamwork/references/teammate-processes.md +94 -24
  175. package/dist/templates/common/bundled-skills/trellis-teamwork/references/teamwork-plan-construction.md +112 -20
  176. package/dist/templates/copilot/hooks/session-start.py +14 -11
  177. package/dist/templates/copilot/index.d.ts +1 -6
  178. package/dist/templates/copilot/index.d.ts.map +1 -1
  179. package/dist/templates/copilot/index.js +1 -14
  180. package/dist/templates/copilot/index.js.map +1 -1
  181. package/dist/templates/markdown/spec/backend/index.md.txt +4 -35
  182. package/dist/templates/markdown/spec/frontend/index.md.txt +4 -36
  183. package/dist/templates/omp/extensions/trellis/index.ts.txt +1 -1
  184. package/dist/templates/pi/extensions/trellis/index.ts.txt +17 -1
  185. package/dist/templates/shared-hooks/guard-teamwork-wait.py +53 -0
  186. package/dist/templates/shared-hooks/index.d.ts +1 -1
  187. package/dist/templates/shared-hooks/index.d.ts.map +1 -1
  188. package/dist/templates/shared-hooks/index.js +1 -0
  189. package/dist/templates/shared-hooks/index.js.map +1 -1
  190. package/dist/templates/shared-hooks/inject-workflow-state.py +8 -3
  191. package/dist/templates/shared-hooks/session-start.py +16 -12
  192. package/dist/templates/trellis/agents/delegated-worktree-primary-agent.md +9 -0
  193. package/dist/templates/trellis/agents/profiles/architecture.md +9 -0
  194. package/dist/templates/trellis/agents/profiles/diagnosis.md +9 -0
  195. package/dist/templates/trellis/agents/profiles/exploration.md +9 -0
  196. package/dist/templates/trellis/agents/profiles/research.md +9 -0
  197. package/dist/templates/trellis/agents/profiles/review.md +9 -0
  198. package/dist/templates/trellis/agents/profiles/verification.md +9 -0
  199. package/dist/templates/trellis/agents/teammate-profiles.json +56 -4
  200. package/dist/templates/trellis/agents/teammate.md +4 -63
  201. package/dist/templates/trellis/config.yaml +2 -5
  202. package/dist/templates/trellis/index.d.ts +1 -0
  203. package/dist/templates/trellis/index.d.ts.map +1 -1
  204. package/dist/templates/trellis/index.js +16 -4
  205. package/dist/templates/trellis/index.js.map +1 -1
  206. package/dist/templates/trellis/scripts/common/task_continuity.py +54 -28
  207. package/dist/templates/trellis/scripts/common/task_store.py +7 -2
  208. package/dist/templates/trellis/scripts/common/task_workflow.py +270 -18
  209. package/dist/templates/trellis/scripts/task.py +27 -3
  210. package/dist/templates/trellis/teamwork.json +10 -0
  211. package/dist/templates/trellis/workflow.md +7 -0
  212. package/dist/utils/asset-backup.d.ts.map +1 -1
  213. package/dist/utils/asset-backup.js +10 -4
  214. package/dist/utils/asset-backup.js.map +1 -1
  215. package/dist/utils/template-fetcher.d.ts +4 -19
  216. package/dist/utils/template-fetcher.d.ts.map +1 -1
  217. package/dist/utils/template-fetcher.js +9 -45
  218. package/dist/utils/template-fetcher.js.map +1 -1
  219. package/package.json +3 -2
  220. package/dist/templates/copilot/prompts/before-dev.prompt.md +0 -39
  221. package/dist/templates/copilot/prompts/brainstorm.prompt.md +0 -13
  222. package/dist/templates/copilot/prompts/break-loop.prompt.md +0 -129
  223. package/dist/templates/copilot/prompts/check-cross-layer.prompt.md +0 -170
  224. package/dist/templates/copilot/prompts/check.prompt.md +0 -110
  225. package/dist/templates/copilot/prompts/create-command.prompt.md +0 -116
  226. package/dist/templates/copilot/prompts/finish-work.prompt.md +0 -22
  227. package/dist/templates/copilot/prompts/integrate-skill.prompt.md +0 -223
  228. package/dist/templates/copilot/prompts/onboard.prompt.md +0 -362
  229. package/dist/templates/copilot/prompts/record-session.prompt.md +0 -58
  230. package/dist/templates/copilot/prompts/start.prompt.md +0 -65
  231. package/dist/templates/copilot/prompts/update-spec.prompt.md +0 -358
@@ -14,10 +14,14 @@ coordination_mode
14
14
  ```
15
15
 
16
16
  The plan also freezes the Teamwork Session, batch, deadline, protected targets,
17
- and ordered `assignments`. Each assignment has an `assignment_id`, brief path,
18
- role, provider, optional profile and model, scope, lens, source digest,
19
- acceptance criteria, and an explicit retry budget. The CLI validates the plan
20
- and the immutable brief before dispatch.
17
+ and ordered `assignments`. Each assignment has an `assignment_id`, selected
18
+ profile/configuration, selection reason, task input, scope, optional lens,
19
+ source digest, acceptance criteria, and an explicit retry budget. The native
20
+ constructor resolves the effective provider/model/effort/options and common
21
+ plus professional instructions, then publishes schema-2 plan and briefs.
22
+ Claims also use schema 2; new launches freeze `reportVersion: 2`. Historical
23
+ frozen launches without it continue to read schema-1 reports. Do not hand-author frozen
24
+ execution objects, role or capability digests, claims, or plan hashes.
21
25
 
22
26
  Use the native task lifecycle for task status and acceptance. Teamwork records
23
27
  coordination facts and teammate reports; it does not write `current_phase_id`,
@@ -39,19 +43,78 @@ specs, and the generic teammate role card. Freeze the input revision and route
39
43
  revision after the coordinator has selected the scope. If those values change,
40
44
  construct a new plan rather than mixing results from different task inputs.
41
45
 
42
- The reserved managed-batch entry point is:
46
+ Construct and run through the native entry points:
43
47
 
44
48
  ```bash
45
- trellis teamwork batch <plan-path>
49
+ trellis teamwork config --profile review --mode advisor
50
+ trellis teamwork plan <draft.json> --task <task-dir> --output <task-dir>/plan.json --dry-run
51
+ trellis teamwork plan <draft.json> --task <task-dir> --output <task-dir>/plan.json
52
+ trellis teamwork batch <task-dir>/plan.json --task <task-dir> --preflight
53
+ trellis teamwork batch <task-dir>/plan.json --task <task-dir> --json
46
54
  ```
47
55
 
48
- The current CLI unconditionally refuses this command before writing
49
- coordination state: a verified runtime adapter has not been connected to the
50
- coordinator. It does not discover an adapter or start the batch. The shared
51
- coordinator and its plan/report contracts exist and are tested separately.
52
- Do not present `run` or `spawn` as a substitute for managed batch execution.
53
- When connected, the coordinator owns dispatch, waiting, report acceptance,
54
- and the terminal receipt; the coordinating agent must not add a second retry loop.
56
+ The draft is a JSON object with `schema_version: 2`, the binding fields above,
57
+ safe `batch_id` and `session_id`, `deadline`, optional `requested_capacity`
58
+ and `protected_targets`, and explicit `assignments`. A minimal member is:
59
+
60
+ ```json
61
+ {
62
+ "assignment_id": "review-a",
63
+ "profile": "review",
64
+ "configuration": "codex-sol",
65
+ "selection_reason": "Use the configured source reviewer",
66
+ "summary": "Review the selected change",
67
+ "scope": "src/example.ts",
68
+ "input": "Inspect the assigned source and return evidence in the requested report.",
69
+ "source_digest": "<SHA-256 of the selected source evidence>",
70
+ "acceptance": ["Cite precise source locations and explain observable impact"],
71
+ "max_retries": 0
72
+ }
73
+ ```
74
+
75
+ Optional member overrides are `provider`, `model`, `reasoning_effort`, and
76
+ adapter-supported `options`; context comes from `context_files` and
77
+ `context_manifests`. Committee members additionally need distinct `lens`
78
+ values and otherwise share the same task/evidence/acceptance contract. The
79
+ constructor creates their evaluation group. Read the configuration matrix
80
+ before choosing candidates. Output must be inside the selected task under
81
+ this project's `.trellis/tasks/`; existing immutable artifacts are preserved.
82
+
83
+ `--dry-run` validates all prepared briefs and paths without writing artifacts.
84
+ `--preflight` validates frozen inputs, current native task revisions and
85
+ capacity without launching a provider; `processProbe: not_run` means accounts,
86
+ models and transport have not been tested by that command. Actual dispatch
87
+ negotiates provider model and effort and fails explicitly if unsupported.
88
+
89
+ Invoke one foreground `trellis teamwork batch` command and wait for its
90
+ receipt. The CLI owns FIFO admission, capacity, provider waits, retries,
91
+ cancellation, report acceptance, and settlement. The main agent does not
92
+ schedule per-assignment waits or retries. A timeout continuation waits on the
93
+ same provider process under the frozen batch deadline; it does not send another
94
+ provider prompt or consume a full-attempt retry. At the batch deadline, the CLI
95
+ closes admission, marks undispatched FIFO work `FINAL_FAILED`, then cancels and
96
+ drains active attempts. Confirmed outcomes settle as `SETTLED_WITH_FAILURE`;
97
+ unconfirmed process exit requires reconciliation.
98
+
99
+ A valid `blocked` report with evidence ends only that assignment as
100
+ `FINAL_FAILED`; the CLI continues with the remaining FIFO work and preserves
101
+ the blocker report. Missing reports may use the assignment's declared retry
102
+ budget. A truncated report or report storage error is uncertain and requires
103
+ reconciliation. Other incomplete or rejected reports may retry only within the
104
+ declared attempt budget.
105
+
106
+ `run` and `spawn` operate interactive sessions and do not bypass batch
107
+ reconciliation. A restart returns a durable terminal receipt or
108
+ `RECONCILIATION_REQUIRED`; it never silently replays an uncertain attempt.
109
+ Before returning a recovered terminal receipt, the CLI checks the frozen plan,
110
+ all assignment dispositions, terminal attempt and teammate facts, capacity
111
+ leases, projection issues, and the exact receipt event. It may reconstruct a
112
+ missing receipt only from consistent terminal facts. Capacity reservations
113
+ survive a coordinator crash because a dead coordinator does not prove its
114
+ provider processes exited. Do not delete an unresolved reservation to make
115
+ another batch fit; inspect ownership and terminal evidence. An unreadable or
116
+ conflicting recovery state retains the reservation and original evidence; it
117
+ does not authorize a replacement dispatch.
55
118
 
56
119
  ## Teamwork Session and forum commands
57
120
 
@@ -59,10 +122,10 @@ Create and inspect the durable runtime object with the native CLI:
59
122
 
60
123
  ```bash
61
124
  trellis teamwork create <name> --type chat|forum \
62
- --task .trellis/tasks/<task-dir> --description "bounded discussion"
125
+ --task .trellis/tasks/in_progress/<task-dir> --description "bounded discussion"
63
126
  trellis teamwork list [--scope project|global] [--all]
64
127
  trellis teamwork messages <name> [--raw]
65
- trellis teamwork wait <name> --as <agent> --kind done,turn_finished
128
+ trellis teamwork wait <name> --as <agent> --from <worker> --json
66
129
  trellis teamwork forum <name>
67
130
  trellis teamwork thread <name> <thread-key>
68
131
  trellis teamwork context list <name> [--thread <thread-key>]
@@ -110,9 +173,38 @@ archive operation.
110
173
 
111
174
  ## Result handling
112
175
 
176
+ Agent callers always request the machine view: `run --json`, `batch --json`,
177
+ or interactive `wait --json --from <one-worker>`. The common envelope has
178
+ `schemaVersion: 1`, `kind: trellis_result`, `mode`, `association`, `execution`,
179
+ `reports`, `semanticValidation: not_run`, and `disposition`. Execution facts
180
+ are distinct from report validation, model content status, and task acceptance.
181
+ `execution.stopped` describes confirmed process cleanup; a persistent wait
182
+ leaves its worker running. Parse stdout as one JSON object; diagnostics use
183
+ stderr. CLI argument-parser errors may precede this result contract.
184
+
185
+ Each new content report has `schema_version: 2`, `status` (complete, blocked,
186
+ incomplete, error), nonempty `answer`, nonempty `evidence` entries with
187
+ `id`, `locator`, `summary`, and arrays `limitations`, `unresolved`, `deviations`.
188
+ Interactive replies return this JSON directly, with no report file or invented
189
+ batch identity. Batch reports additionally copy the assigned task, batch,
190
+ assignment, attempt, teammate, plan, phase, route, input and source identities
191
+ into the exact report path. `done` is emitted by the adapter, not by the model.
192
+
193
+ Batch machine results expose validated report content, association, report path
194
+ and SHA-256. Missing or invalid accepted artifacts fail validation; historical
195
+ schema-1 content is explicitly `legacy`, never synthesized as a valid new
196
+ answer. Retention may remove failed-attempt artifacts. Main-agent semantic
197
+ review checks the answer and evidence against the acceptance criteria; shape
198
+ validation does not perform that review or change native task acceptance.
199
+
113
200
  The coordinator returns `ALL_ACCEPTED`, `SETTLED_WITH_FAILURE`, or
114
- `RECONCILIATION_REQUIRED`. A terminal receipt is a runtime fact. The main task
115
- then reviews reports against the phase contract, records durable evidence in
116
- the task-owned artifact, and uses the task's native acceptance gate before
117
- advancing. A formal session handoff is an independent, lower-priority
118
- continuity artifact and does not represent a phase transition.
201
+ `RECONCILIATION_REQUIRED`. For `ALL_ACCEPTED`, review every accepted report
202
+ against the phase contract, record the evidence in the task-owned artifact, and
203
+ use the native task acceptance gate before advancing. For
204
+ `SETTLED_WITH_FAILURE`, review the failure reports and blockers, do not accept
205
+ or advance the phase, and decide the next task-level action through the native
206
+ workflow. For `RECONCILIATION_REQUIRED`, stop dispatch, retry, and cleanup;
207
+ preserve the reported runtime evidence and reservation for explicit
208
+ reconciliation. A receipt is a runtime fact, not phase acceptance. A formal
209
+ session handoff is an independent, lower-priority continuity artifact and does
210
+ not represent a phase transition.
@@ -231,8 +231,7 @@ def _get_task_status(trellis_dir: Path, hook_input: dict) -> str:
231
231
  if not active.task_path:
232
232
  return (
233
233
  "Status: NO ACTIVE TASK\n"
234
- "Next: Classify the current turn and ask for task-creation consent "
235
- "before creating any Trellis task."
234
+ "Next: Route through trellis-request-intake using the existing authorization and taskless contract."
236
235
  )
237
236
 
238
237
  task_ref = active.task_path
@@ -244,12 +243,10 @@ def _get_task_status(trellis_dir: Path, hook_input: dict) -> str:
244
243
  )
245
244
 
246
245
  task_json_path = task_dir / "task.json"
247
- task_data: dict = {}
248
- if task_json_path.is_file():
249
- try:
250
- task_data = json.loads(task_json_path.read_text(encoding="utf-8"))
251
- except (json.JSONDecodeError, PermissionError):
252
- pass # Optional task metadata; fall back to generic status.
246
+ from common.io import read_json_checked # type: ignore[import-not-found]
247
+ task_data, _reason = read_json_checked(task_json_path)
248
+ if task_data is None or task_data.get("status") not in ("planning", "in_progress", "completed", "cancelled"):
249
+ return f"Status: TASK_ERROR\nTask: {task_ref}\nNext: Repair the existing task record through its owner before continuing; do not create a replacement task."
253
250
 
254
251
  task_title = task_data.get("title", task_ref)
255
252
  task_status = task_data.get("status", "unknown")
@@ -379,13 +376,15 @@ def _build_compact_current_state(
379
376
  active = _resolve_active_task(trellis_dir, hook_input)
380
377
  if active.task_path:
381
378
  task_dir = _resolve_task_dir(trellis_dir, active.task_path)
382
- status = "unknown"
379
+ status = "task_error"
383
380
  task_json = task_dir / "task.json"
384
381
  if task_json.is_file():
385
382
  try:
386
383
  data = json.loads(task_json.read_text(encoding="utf-8"))
387
384
  if isinstance(data, dict):
388
- status = str(data.get("status") or "unknown")
385
+ value = data.get("status")
386
+ if value in ("planning", "in_progress", "completed", "cancelled"):
387
+ status = value
389
388
  except (json.JSONDecodeError, OSError):
390
389
  pass # Optional task metadata; fall back to generic status.
391
390
  lines.append(f"Current task: {_repo_relative(repo_root, task_dir)}; status={status}.")
@@ -503,11 +502,15 @@ def main() -> None:
503
502
  hook_input = json.loads(sys.stdin.read())
504
503
  if not isinstance(hook_input, dict):
505
504
  hook_input = {}
506
- project_dir = Path(_normalize_windows_shell_path(hook_input.get("cwd", "."))).resolve()
505
+ raw_cwd = hook_input.get("cwd")
506
+ project_dir = Path(_normalize_windows_shell_path(raw_cwd if isinstance(raw_cwd, str) and raw_cwd else ".")).resolve()
507
507
  except (json.JSONDecodeError, KeyError):
508
508
  hook_input = {}
509
509
  project_dir = Path(".").resolve()
510
510
 
511
+ project_dir = next((candidate for candidate in (project_dir, *project_dir.parents) if (candidate / ".trellis").is_dir()), None)
512
+ if project_dir is None or not (project_dir / ".trellis" / "scripts" / "common" / "active_task.py").is_file():
513
+ return
511
514
  configure_project_encoding(project_dir)
512
515
 
513
516
  trellis_dir = project_dir / ".trellis"
@@ -5,7 +5,7 @@
5
5
  *
6
6
  * Directory structure:
7
7
  * copilot/
8
- * ├── prompts/ # Slash-command prompts → .github/prompts/*.prompt.md
8
+ * Slash-command prompts come from common/commands via the configurator.
9
9
  * ├── hooks/ # Hook scripts → .github/copilot/hooks/
10
10
  * ├── hooks.json # Hooks config → .github/hooks/trellis.json
11
11
  * └── copilot-instructions.md → .github/copilot-instructions.md
@@ -17,12 +17,7 @@ export interface HookTemplate {
17
17
  name: string;
18
18
  content: string;
19
19
  }
20
- export interface PromptTemplate {
21
- name: string;
22
- content: string;
23
- }
24
20
  export declare function getAllHooks(): HookTemplate[];
25
21
  export declare function getHooksConfig(): string;
26
22
  export declare function getCopilotInstructions(): string;
27
- export declare function getAllPrompts(): PromptTemplate[];
28
23
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/templates/copilot/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AASH,eAAO,MAAM,yBAAyB,oCAAoC,CAAC;AAC3E,eAAO,MAAM,gCAAgC,4CACF,CAAC;AAC5C,eAAO,MAAM,8BAA8B,0CACF,CAAC;AAc1C,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,wBAAgB,WAAW,IAAI,YAAY,EAAE,CAW5C;AAED,wBAAgB,cAAc,IAAI,MAAM,CAEvC;AAED,wBAAgB,sBAAsB,IAAI,MAAM,CAE/C;AAED,wBAAgB,aAAa,IAAI,cAAc,EAAE,CAchD"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/templates/copilot/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AASH,eAAO,MAAM,yBAAyB,oCAAoC,CAAC;AAC3E,eAAO,MAAM,gCAAgC,4CACF,CAAC;AAC5C,eAAO,MAAM,8BAA8B,0CACF,CAAC;AAc1C,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,wBAAgB,WAAW,IAAI,YAAY,EAAE,CAW5C;AAED,wBAAgB,cAAc,IAAI,MAAM,CAEvC;AAED,wBAAgB,sBAAsB,IAAI,MAAM,CAE/C"}
@@ -5,7 +5,7 @@
5
5
  *
6
6
  * Directory structure:
7
7
  * copilot/
8
- * ├── prompts/ # Slash-command prompts → .github/prompts/*.prompt.md
8
+ * Slash-command prompts come from common/commands via the configurator.
9
9
  * ├── hooks/ # Hook scripts → .github/copilot/hooks/
10
10
  * ├── hooks.json # Hooks config → .github/hooks/trellis.json
11
11
  * └── copilot-instructions.md → .github/copilot-instructions.md
@@ -45,17 +45,4 @@ export function getHooksConfig() {
45
45
  export function getCopilotInstructions() {
46
46
  return readTemplate("copilot-instructions.md");
47
47
  }
48
- export function getAllPrompts() {
49
- const prompts = [];
50
- for (const file of listFiles("prompts")) {
51
- if (!file.endsWith(".prompt.md")) {
52
- continue;
53
- }
54
- prompts.push({
55
- name: file.slice(0, -".prompt.md".length),
56
- content: readTemplate(`prompts/${file}`),
57
- });
58
- }
59
- return prompts;
60
- }
61
48
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/templates/copilot/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACpD,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAClD,MAAM,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;AAEtC,MAAM,CAAC,MAAM,yBAAyB,GAAG,iCAAiC,CAAC;AAC3E,MAAM,CAAC,MAAM,gCAAgC,GAC3C,yCAAyC,CAAC;AAC5C,MAAM,CAAC,MAAM,8BAA8B,GACzC,uCAAuC,CAAC;AAE1C,SAAS,YAAY,CAAC,YAAoB;IACxC,OAAO,YAAY,CAAC,IAAI,CAAC,SAAS,EAAE,YAAY,CAAC,EAAE,OAAO,CAAC,CAAC;AAC9D,CAAC;AAED,SAAS,SAAS,CAAC,GAAW;IAC5B,IAAI,CAAC;QACH,OAAO,WAAW,CAAC,IAAI,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IAClD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAYD,MAAM,UAAU,WAAW;IACzB,MAAM,KAAK,GAAmB,EAAE,CAAC;IAEjC,KAAK,MAAM,IAAI,IAAI,SAAS,CAAC,OAAO,CAAC,EAAE,CAAC;QACtC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;YAC1B,SAAS;QACX,CAAC;QACD,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,YAAY,CAAC,SAAS,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC;IACrE,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,UAAU,cAAc;IAC5B,OAAO,YAAY,CAAC,YAAY,CAAC,CAAC;AACpC,CAAC;AAED,MAAM,UAAU,sBAAsB;IACpC,OAAO,YAAY,CAAC,yBAAyB,CAAC,CAAC;AACjD,CAAC;AAED,MAAM,UAAU,aAAa;IAC3B,MAAM,OAAO,GAAqB,EAAE,CAAC;IAErC,KAAK,MAAM,IAAI,IAAI,SAAS,CAAC,SAAS,CAAC,EAAE,CAAC;QACxC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC;YACjC,SAAS;QACX,CAAC;QACD,OAAO,CAAC,IAAI,CAAC;YACX,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,YAAY,CAAC,MAAM,CAAC;YACzC,OAAO,EAAE,YAAY,CAAC,WAAW,IAAI,EAAE,CAAC;SACzC,CAAC,CAAC;IACL,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/templates/copilot/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACpD,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAClD,MAAM,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;AAEtC,MAAM,CAAC,MAAM,yBAAyB,GAAG,iCAAiC,CAAC;AAC3E,MAAM,CAAC,MAAM,gCAAgC,GAC3C,yCAAyC,CAAC;AAC5C,MAAM,CAAC,MAAM,8BAA8B,GACzC,uCAAuC,CAAC;AAE1C,SAAS,YAAY,CAAC,YAAoB;IACxC,OAAO,YAAY,CAAC,IAAI,CAAC,SAAS,EAAE,YAAY,CAAC,EAAE,OAAO,CAAC,CAAC;AAC9D,CAAC;AAED,SAAS,SAAS,CAAC,GAAW;IAC5B,IAAI,CAAC;QACH,OAAO,WAAW,CAAC,IAAI,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IAClD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAOD,MAAM,UAAU,WAAW;IACzB,MAAM,KAAK,GAAmB,EAAE,CAAC;IAEjC,KAAK,MAAM,IAAI,IAAI,SAAS,CAAC,OAAO,CAAC,EAAE,CAAC;QACtC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;YAC1B,SAAS;QACX,CAAC;QACD,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,YAAY,CAAC,SAAS,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC;IACrE,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,UAAU,cAAc;IAC5B,OAAO,YAAY,CAAC,YAAY,CAAC,CAAC;AACpC,CAAC;AAED,MAAM,UAAU,sBAAsB;IACpC,OAAO,YAAY,CAAC,yBAAyB,CAAC,CAAC;AACjD,CAAC"}
@@ -1,38 +1,7 @@
1
- # Backend Development Guidelines
1
+ # 后端开发规范索引
2
2
 
3
- > Best practices for backend development in this project.
3
+ 此文件是项目规范的入口,尚未建立源码约定。
4
4
 
5
- ---
5
+ 在首次实施前使用 `trellis-spec-bootstrap`,核对本项目实际源码、包边界和验证入口,只建立适用且有证据的规范,并在这里添加链接。不要把通用建议、未核实的技术栈或占位内容当作项目合同;没有数据库时不创建数据库规范。
6
6
 
7
- ## Overview
8
-
9
- This directory contains guidelines for backend development. Fill in each file with your project's specific conventions.
10
-
11
- ---
12
-
13
- ## Guidelines Index
14
-
15
- | Guide | Description | Status |
16
- |-------|-------------|--------|
17
- | [Directory Structure](./directory-structure.md) | Module organization and file layout | To fill |
18
- | [Database Guidelines](./database-guidelines.md) | ORM patterns, queries, migrations | To fill |
19
- | [Error Handling](./error-handling.md) | Error types, handling strategies | To fill |
20
- | [Quality Guidelines](./quality-guidelines.md) | Code standards, forbidden patterns | To fill |
21
- | [Logging Guidelines](./logging-guidelines.md) | Structured logging, log levels | To fill |
22
-
23
- ---
24
-
25
- ## How to Fill These Guidelines
26
-
27
- For each guideline file:
28
-
29
- 1. Document your project's **actual conventions** (not ideals)
30
- 2. Include **code examples** from your codebase
31
- 3. List **forbidden patterns** and why
32
- 4. Add **common mistakes** your team has made
33
-
34
- The goal is to help AI assistants and new team members understand how YOUR project works.
35
-
36
- ---
37
-
38
- **Language**: All documentation should be written in **English**.
7
+ `trellis-before-dev` 按当前修改读取相关规范;`trellis-update-spec` 将已验证、可复用的约定增量写回。保留项目已有的自定义内容和语言要求,不为初始化重写规范。
@@ -1,39 +1,7 @@
1
- # Frontend Development Guidelines
1
+ # 前端开发规范索引
2
2
 
3
- > Best practices for frontend development in this project.
3
+ 此文件是项目规范的入口,尚未建立源码约定。
4
4
 
5
- ---
5
+ 在首次实施前使用 `trellis-spec-bootstrap`,核对本项目实际源码、包边界和验证入口,只建立适用且有证据的规范,并在这里添加链接。不要预设框架、状态库、Hook 或组件模式,也不要生成没有源码依据的占位规范。
6
6
 
7
- ## Overview
8
-
9
- This directory contains guidelines for frontend development. Fill in each file with your project's specific conventions.
10
-
11
- ---
12
-
13
- ## Guidelines Index
14
-
15
- | Guide | Description | Status |
16
- |-------|-------------|--------|
17
- | [Directory Structure](./directory-structure.md) | Module organization and file layout | To fill |
18
- | [Component Guidelines](./component-guidelines.md) | Component patterns, props, composition | To fill |
19
- | [Hook Guidelines](./hook-guidelines.md) | Custom hooks, data fetching patterns | To fill |
20
- | [State Management](./state-management.md) | Local state, global state, server state | To fill |
21
- | [Quality Guidelines](./quality-guidelines.md) | Code standards, forbidden patterns | To fill |
22
- | [Type Safety](./type-safety.md) | Type patterns, validation | To fill |
23
-
24
- ---
25
-
26
- ## How to Fill These Guidelines
27
-
28
- For each guideline file:
29
-
30
- 1. Document your project's **actual conventions** (not ideals)
31
- 2. Include **code examples** from your codebase
32
- 3. List **forbidden patterns** and why
33
- 4. Add **common mistakes** your team has made
34
-
35
- The goal is to help AI assistants and new team members understand how YOUR project works.
36
-
37
- ---
38
-
39
- **Language**: All documentation should be written in **English**.
7
+ `trellis-before-dev` 按当前修改读取相关规范;`trellis-update-spec` 将已验证、可复用的约定增量写回。保留项目已有的自定义内容和语言要求,不为初始化重写规范。
@@ -81,7 +81,7 @@ function parseTeamworkTrustSection(content: string): { trustedDirs: string[]; au
81
81
  const trimmed = line.trimEnd();
82
82
  if (trimmed.trim().startsWith("#")) continue;
83
83
 
84
- if (/^channel:\s*$/.test(trimmed)) {
84
+ if (/^teamwork:\s*$/.test(trimmed)) {
85
85
  inChannel = true;
86
86
  inList = false;
87
87
  continue;
@@ -1202,7 +1202,23 @@ function workflowBreadcrumb(root: string, key: string | null): string {
1202
1202
  header = `Task: ${id} (${status})`;
1203
1203
  lookup = status;
1204
1204
  }
1205
- } catch {}
1205
+ const meta = d.meta as JsonObject | undefined;
1206
+ if (isObj(meta) && "task_workflow" in meta) {
1207
+ const state = meta.task_workflow;
1208
+ const routed = isObj(state) && Array.isArray(state.phase_ids) ? state.phase_ids : [];
1209
+ const phase = isObj(state) && str(state.current_phase_id === null ? routed.at(-1) : state.current_phase_id);
1210
+ const phases = isObj(state) && isObj(state.phases) ? state.phases : null;
1211
+ const record = phase && phases?.[phase];
1212
+ if (phase && isObj(record) && str(record.status)) {
1213
+ lookup = phase;
1214
+ header += `; phase=${phase}; state=${str(record.status) ?? "unknown"}`;
1215
+ } else {
1216
+ lookup = "task_error";
1217
+ }
1218
+ }
1219
+ } catch {
1220
+ lookup = "task_error";
1221
+ }
1206
1222
  }
1207
1223
  const body = templates[lookup] ?? "Refer to workflow.md for current step.";
1208
1224
  return `<workflow-state>\n${header}\n${body}\n</workflow-state>`;
@@ -0,0 +1,53 @@
1
+ #!/usr/bin/env python3
2
+ """Codex PreToolUse guard for CLI-owned foreground batches.
3
+
4
+ Only supported host tool hooks are guarded. Ordinary model messages and tools
5
+ that the host does not expose to PreToolUse remain Skill obligations.
6
+ """
7
+ from __future__ import annotations
8
+
9
+ import hashlib
10
+ import json
11
+ import os
12
+ import shlex
13
+ import sys
14
+ from pathlib import Path
15
+
16
+
17
+ def decision(payload: dict) -> dict | None:
18
+ if not isinstance(payload, dict):
19
+ return None
20
+ if os.environ.get("TRELLIS_HOOKS") == "0":
21
+ return None
22
+ session = payload.get("session_id") or os.environ.get("CODEX_THREAD_ID")
23
+ if not isinstance(session, str) or not session:
24
+ return None
25
+ root = Path(payload.get("cwd") or os.getcwd()).resolve()
26
+ while not (root / ".trellis").is_dir() and root != root.parent:
27
+ root = root.parent
28
+ directory = root / ".trellis/.runtime/teamwork-waits" / hashlib.sha256(session.encode()).hexdigest()
29
+ if not directory.exists():
30
+ return None
31
+ records = list(directory.glob("*.json"))
32
+ if not records:
33
+ return None
34
+ tool = str(payload.get("tool_name", "")).rsplit(".", 1)[-1]
35
+ if tool in {"write_stdin", "wait"}:
36
+ return None
37
+ tool_input = payload.get("tool_input")
38
+ tool_input = tool_input if isinstance(tool_input, dict) else {}
39
+ command = tool_input.get("command", tool_input.get("cmd"))
40
+ if isinstance(command, str) and not any(character in command for character in "$`;\n&|<>"):
41
+ try:
42
+ argv = shlex.split(command)
43
+ except ValueError:
44
+ argv = []
45
+ if argv[:3] == ["trellis", "teamwork", "reconcile"]:
46
+ return None
47
+ return {"hookSpecificOutput": {"hookEventName": "PreToolUse", "permissionDecision": "deny", "permissionDecisionReason": "Trellis owns an outstanding foreground batch. Silently continue the original host wait handle, or interrupt that same handle. A dead coordinator still requires native teamwork reconcile; do not start another batch or take over FIFO scheduling."}}
48
+
49
+
50
+ if __name__ == "__main__":
51
+ result = decision(json.load(sys.stdin))
52
+ if result:
53
+ print(json.dumps(result))
@@ -11,7 +11,7 @@ export interface HookScript {
11
11
  /** Script content — no placeholders, ready to write directly */
12
12
  content: string;
13
13
  }
14
- export type SharedHookName = "session-start.py" | "inject-shell-session-context.py" | "inject-workflow-state.py" | "inject-subagent-context.py" | "inject-spec-context.py";
14
+ export type SharedHookName = "guard-teamwork-wait.py" | "session-start.py" | "inject-shell-session-context.py" | "inject-workflow-state.py" | "inject-subagent-context.py" | "inject-spec-context.py";
15
15
  export type SharedHookPlatform = "claude" | "cursor" | "codex" | "opencode" | "gemini" | "qoder" | "copilot" | "codebuddy" | "droid" | "kiro" | "trae" | "zcode";
16
16
  /**
17
17
  * Which shared hooks each platform actually invokes. Single source of truth
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/templates/shared-hooks/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAaH,MAAM,WAAW,UAAU;IACzB,0CAA0C;IAC1C,IAAI,EAAE,MAAM,CAAC;IACb,gEAAgE;IAChE,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,MAAM,cAAc,GACtB,kBAAkB,GAClB,iCAAiC,GACjC,0BAA0B,GAC1B,4BAA4B,GAC5B,wBAAwB,CAAC;AAE7B,MAAM,MAAM,kBAAkB,GAC1B,QAAQ,GACR,QAAQ,GACR,OAAO,GACP,UAAU,GACV,QAAQ,GACR,OAAO,GACP,SAAS,GACT,WAAW,GACX,OAAO,GACP,MAAM,GACN,MAAM,GACN,OAAO,CAAC;AAEZ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsDG;AACH,eAAO,MAAM,wBAAwB,EAAE,MAAM,CAC3C,kBAAkB,EAClB,SAAS,cAAc,EAAE,CA0D1B,CAAC;AAEF;;;GAGG;AACH,wBAAgB,oBAAoB,IAAI,UAAU,EAAE,CAWnD;AAED;;;;GAIG;AACH,wBAAgB,+BAA+B,CAC7C,QAAQ,EAAE,kBAAkB,GAC3B,UAAU,EAAE,CAGd"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/templates/shared-hooks/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAaH,MAAM,WAAW,UAAU;IACzB,0CAA0C;IAC1C,IAAI,EAAE,MAAM,CAAC;IACb,gEAAgE;IAChE,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,MAAM,cAAc,GACtB,wBAAwB,GACxB,kBAAkB,GAClB,iCAAiC,GACjC,0BAA0B,GAC1B,4BAA4B,GAC5B,wBAAwB,CAAC;AAE7B,MAAM,MAAM,kBAAkB,GAC1B,QAAQ,GACR,QAAQ,GACR,OAAO,GACP,UAAU,GACV,QAAQ,GACR,OAAO,GACP,SAAS,GACT,WAAW,GACX,OAAO,GACP,MAAM,GACN,MAAM,GACN,OAAO,CAAC;AAEZ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsDG;AACH,eAAO,MAAM,wBAAwB,EAAE,MAAM,CAC3C,kBAAkB,EAClB,SAAS,cAAc,EAAE,CA2D1B,CAAC;AAEF;;;GAGG;AACH,wBAAgB,oBAAoB,IAAI,UAAU,EAAE,CAWnD;AAED;;;;GAIG;AACH,wBAAgB,+BAA+B,CAC7C,QAAQ,EAAE,kBAAkB,GAC3B,UAAU,EAAE,CAGd"}
@@ -81,6 +81,7 @@ export const SHARED_HOOKS_BY_PLATFORM = {
81
81
  "inject-subagent-context.py",
82
82
  ],
83
83
  codex: [
84
+ "guard-teamwork-wait.py",
84
85
  "inject-workflow-state.py",
85
86
  "inject-subagent-context.py",
86
87
  "inject-spec-context.py",
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/templates/shared-hooks/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACpD,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAClD,MAAM,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;AAEtC,SAAS,YAAY,CAAC,YAAoB;IACxC,OAAO,YAAY,CAAC,IAAI,CAAC,SAAS,EAAE,YAAY,CAAC,EAAE,OAAO,CAAC,CAAC;AAC9D,CAAC;AA8BD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsDG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAGjC;IACF,MAAM,EAAE;QACN,kBAAkB;QAClB,0BAA0B;QAC1B,4BAA4B;QAC5B,wBAAwB;KACzB;IACD,MAAM,EAAE;QACN,kBAAkB;QAClB,iCAAiC;QACjC,4BAA4B;KAC7B;IACD,KAAK,EAAE;QACL,0BAA0B;QAC1B,4BAA4B;QAC5B,wBAAwB;KACzB;IACD,QAAQ,EAAE,CAAC,wBAAwB,CAAC;IACpC,MAAM,EAAE;QACN,kBAAkB;QAClB,iCAAiC;QACjC,0BAA0B;KAC3B;IACD,KAAK,EAAE;QACL,kBAAkB;QAClB,iCAAiC;QACjC,0BAA0B;KAC3B;IACD,OAAO,EAAE,CAAC,0BAA0B,CAAC;IACrC,SAAS,EAAE;QACT,kBAAkB;QAClB,iCAAiC;QACjC,0BAA0B;QAC1B,4BAA4B;KAC7B;IACD,KAAK,EAAE;QACL,kBAAkB;QAClB,iCAAiC;QACjC,0BAA0B;QAC1B,4BAA4B;KAC7B;IACD,IAAI,EAAE;QACJ,kBAAkB;QAClB,0BAA0B;QAC1B,4BAA4B;KAC7B;IACD,IAAI,EAAE;QACJ,kBAAkB;QAClB,iCAAiC;QACjC,0BAA0B;KAC3B;IACD,KAAK,EAAE;QACL,kBAAkB;QAClB,iCAAiC;QACjC,0BAA0B;QAC1B,4BAA4B;KAC7B;CACF,CAAC;AAEF;;;GAGG;AACH,MAAM,UAAU,oBAAoB;IAClC,MAAM,OAAO,GAAiB,EAAE,CAAC;IACjC,MAAM,KAAK,GAAG,WAAW,CAAC,SAAS,CAAC;SACjC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;SAChC,IAAI,EAAE,CAAC;IAEV,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC5D,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,+BAA+B,CAC7C,QAA4B;IAE5B,MAAM,OAAO,GAAG,IAAI,GAAG,CAAS,wBAAwB,CAAC,QAAQ,CAAC,CAAC,CAAC;IACpE,OAAO,oBAAoB,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;AACnE,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/templates/shared-hooks/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACpD,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAClD,MAAM,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;AAEtC,SAAS,YAAY,CAAC,YAAoB;IACxC,OAAO,YAAY,CAAC,IAAI,CAAC,SAAS,EAAE,YAAY,CAAC,EAAE,OAAO,CAAC,CAAC;AAC9D,CAAC;AA+BD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsDG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAGjC;IACF,MAAM,EAAE;QACN,kBAAkB;QAClB,0BAA0B;QAC1B,4BAA4B;QAC5B,wBAAwB;KACzB;IACD,MAAM,EAAE;QACN,kBAAkB;QAClB,iCAAiC;QACjC,4BAA4B;KAC7B;IACD,KAAK,EAAE;QACL,wBAAwB;QACxB,0BAA0B;QAC1B,4BAA4B;QAC5B,wBAAwB;KACzB;IACD,QAAQ,EAAE,CAAC,wBAAwB,CAAC;IACpC,MAAM,EAAE;QACN,kBAAkB;QAClB,iCAAiC;QACjC,0BAA0B;KAC3B;IACD,KAAK,EAAE;QACL,kBAAkB;QAClB,iCAAiC;QACjC,0BAA0B;KAC3B;IACD,OAAO,EAAE,CAAC,0BAA0B,CAAC;IACrC,SAAS,EAAE;QACT,kBAAkB;QAClB,iCAAiC;QACjC,0BAA0B;QAC1B,4BAA4B;KAC7B;IACD,KAAK,EAAE;QACL,kBAAkB;QAClB,iCAAiC;QACjC,0BAA0B;QAC1B,4BAA4B;KAC7B;IACD,IAAI,EAAE;QACJ,kBAAkB;QAClB,0BAA0B;QAC1B,4BAA4B;KAC7B;IACD,IAAI,EAAE;QACJ,kBAAkB;QAClB,iCAAiC;QACjC,0BAA0B;KAC3B;IACD,KAAK,EAAE;QACL,kBAAkB;QAClB,iCAAiC;QACjC,0BAA0B;QAC1B,4BAA4B;KAC7B;CACF,CAAC;AAEF;;;GAGG;AACH,MAAM,UAAU,oBAAoB;IAClC,MAAM,OAAO,GAAiB,EAAE,CAAC;IACjC,MAAM,KAAK,GAAG,WAAW,CAAC,SAAS,CAAC;SACjC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;SAChC,IAAI,EAAE,CAAC;IAEV,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC5D,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,+BAA+B,CAC7C,QAA4B;IAE5B,MAAM,OAAO,GAAG,IAAI,GAAG,CAAS,wBAAwB,CAAC,QAAQ,CAAC,CAAC,CAAC;IACpE,OAAO,oBAAoB,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;AACnE,CAAC"}
@@ -194,8 +194,11 @@ def get_active_task(
194
194
  status = data.get("status", "")
195
195
  if not isinstance(status, str) or not status:
196
196
  return task_dir.name, "task_error", active.source, None
197
- phase_workflow = data.get("meta", {}).get("task_workflow") if isinstance(data.get("meta"), dict) else None
198
- if isinstance(phase_workflow, dict):
197
+ meta = data.get("meta")
198
+ if isinstance(meta, dict) and "task_workflow" in meta:
199
+ phase_workflow = meta["task_workflow"]
200
+ if not isinstance(phase_workflow, dict):
201
+ return task_id, "task_error", active.source, None
199
202
  phase_id = phase_workflow.get("current_phase_id")
200
203
  phases = phase_workflow.get("phases")
201
204
  if phase_id is None:
@@ -204,7 +207,9 @@ def get_active_task(
204
207
  phase = phases.get(phase_id) if isinstance(phases, dict) and isinstance(phase_id, str) else None
205
208
  if isinstance(phase_id, str) and isinstance(phase, dict):
206
209
  phase_status = phase.get("status")
207
- return task_id, phase_id, active.source, phase_status if isinstance(phase_status, str) else None
210
+ if isinstance(phase_status, str) and phase_status:
211
+ return task_id, phase_id, active.source, phase_status
212
+ return task_id, "task_error", active.source, None
208
213
  return task_id, status, active.source, None
209
214
 
210
215
 
@@ -429,8 +429,7 @@ def _get_task_status(trellis_dir: Path, input_data: dict) -> str:
429
429
  return (
430
430
  "Status: NO ACTIVE TASK\n"
431
431
  "Next-Action: Classify the current turn before creating any Trellis task. "
432
- "Simple conversation / small task asks only whether this turn should create a Trellis task. "
433
- "Complex task asks whether task creation and planning are allowed."
432
+ "Route through trellis-request-intake using the existing authorization and taskless contract."
434
433
  )
435
434
 
436
435
  task_ref = active.task_path
@@ -443,12 +442,10 @@ def _get_task_status(trellis_dir: Path, input_data: dict) -> str:
443
442
  )
444
443
 
445
444
  task_json_path = task_dir / "task.json"
446
- task_data = {}
447
- if task_json_path.is_file():
448
- try:
449
- task_data = json.loads(task_json_path.read_text(encoding="utf-8"))
450
- except (json.JSONDecodeError, PermissionError):
451
- pass # Optional task metadata; fall back to generic status.
445
+ from common.io import read_json_checked # type: ignore[import-not-found]
446
+ task_data, _reason = read_json_checked(task_json_path)
447
+ if task_data is None or task_data.get("status") not in ("planning", "in_progress", "completed", "cancelled"):
448
+ return f"Status: TASK_ERROR\nTask: {task_ref}\nNext-Action: Repair the existing task record through its owner before continuing; do not create a replacement task."
452
449
 
453
450
  task_title = task_data.get("title", task_ref)
454
451
  task_status = task_data.get("status", "unknown")
@@ -475,7 +472,7 @@ def _get_task_status(trellis_dir: Path, input_data: dict) -> str:
475
472
  if task_status == "planning":
476
473
  next_bits = [
477
474
  "Follow the current per-turn workflow-state; task lifecycle status and artifact presence do not identify the business phase",
478
- "If no phase route is initialized, load `trellis-goal-exploration-and-requirements` and confirm the requirements baseline before initializing the route",
475
+ "If no phase route is initialized, initialize it through Trellis CLI, load `trellis-goal-exploration-and-requirements`, and obtain user confirmation for the recorded requirements artifact before advancing",
479
476
  ]
480
477
  if not jsonl_ready:
481
478
  next_bits.append("curate task context manifests only when a dispatched agent needs them")
@@ -698,13 +695,15 @@ def _build_compact_current_state(
698
695
  active = _resolve_active_task(trellis_dir, input_data)
699
696
  if active.task_path:
700
697
  task_dir = _resolve_task_dir(trellis_dir, active.task_path)
701
- status = "unknown"
698
+ status = "task_error"
702
699
  task_json = task_dir / "task.json"
703
700
  if task_json.is_file():
704
701
  try:
705
702
  data = json.loads(task_json.read_text(encoding="utf-8"))
706
703
  if isinstance(data, dict):
707
- status = str(data.get("status") or "unknown")
704
+ value = data.get("status")
705
+ if value in ("planning", "in_progress", "completed", "cancelled"):
706
+ status = value
708
707
  except (json.JSONDecodeError, OSError):
709
708
  pass # Optional task metadata; fall back to generic status.
710
709
  lines.append(f"Current task: {_repo_relative(repo_root, task_dir)}; status={status}.")
@@ -859,7 +858,12 @@ def main():
859
858
  project_dir = Path(_normalize_windows_shell_path(val)).resolve()
860
859
  break
861
860
  if project_dir is None:
862
- project_dir = Path(_normalize_windows_shell_path(hook_input.get("cwd", "."))).resolve()
861
+ raw_cwd = hook_input.get("cwd")
862
+ project_dir = Path(_normalize_windows_shell_path(raw_cwd if isinstance(raw_cwd, str) and raw_cwd else ".")).resolve()
863
+
864
+ project_dir = next((candidate for candidate in (project_dir, *project_dir.parents) if (candidate / ".trellis").is_dir()), None)
865
+ if project_dir is None or not (project_dir / ".trellis" / "scripts" / "common" / "active_task.py").is_file():
866
+ return
863
867
 
864
868
  trellis_dir = project_dir / ".trellis"
865
869
  context_key = _resolve_context_key(trellis_dir, hook_input)
@@ -16,3 +16,12 @@ start another delegated run. Verify the changes with relevant project checks
16
16
  and report the files changed, evidence, and any remaining limitation. Stop and
17
17
  report if the contract conflicts with repository instructions or requires a
18
18
  materially different scope.
19
+
20
+ Treat `.trellis/tasks/`, task ownership, session pointers, runtime state, and
21
+ workflow acceptance as read-only control-plane facts. Do not invoke task CLI
22
+ write commands, including create, start, finish, set-meta, phase, transfer,
23
+ link/unlink, rename, delegate, or lifecycle commands. Write the assigned result
24
+ artifact only at its supplied path; do not create a second task contract.
25
+ One level of bounded read-only Teamwork research or review is allowed when the
26
+ parent contract permits it. Those teammates must not implement code or delegate
27
+ again. These are role obligations, not a sandbox guarantee.
@@ -0,0 +1,9 @@
1
+ # 架构与方案评估(architecture)
2
+
3
+ 你负责评估 brief 指定的架构问题和实质候选。共同角色卡规定的范围、结果写入和停止条件始终适用。
4
+
5
+ 输入应包含目标与约束、当前结构、受影响边界、候选或待决问题和接受条件。先核对现有职责与接口,再比较满足当前需求的候选,包括数据与控制流、失败恢复、兼容与迁移、可验证性及维护成本。必要的源码探索或外部补证必须服务于当前决定。
6
+
7
+ 结果应包含推荐及依据、排除候选与理由、接口和边界、关键情景、风险、实施与验证建议,以及仍须用户决定的取舍。证据足以评估候选后停止;不要为假设的未来增加框架,不自行扩充规划权限或实施授权。最终结论由协调者归并。
8
+
9
+ 必要输入缺失、角色与 brief 冲突或需要越界操作时,报告阻断。不编写产品源码、测试或修复,不替协调者接受结果,不继续委派。