@mindfoldhq/trellis 0.6.0-beta.8 → 0.6.0-rc.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 (337) hide show
  1. package/README.md +49 -49
  2. package/dist/cli/index.d.ts +1 -1
  3. package/dist/cli/index.d.ts.map +1 -1
  4. package/dist/cli/index.js +59 -2
  5. package/dist/cli/index.js.map +1 -1
  6. package/dist/commands/channel/adapters/claude.d.ts +29 -0
  7. package/dist/commands/channel/adapters/claude.d.ts.map +1 -0
  8. package/dist/commands/channel/adapters/claude.js +203 -0
  9. package/dist/commands/channel/adapters/claude.js.map +1 -0
  10. package/dist/commands/channel/adapters/codex.d.ts +85 -0
  11. package/dist/commands/channel/adapters/codex.d.ts.map +1 -0
  12. package/dist/commands/channel/adapters/codex.js +505 -0
  13. package/dist/commands/channel/adapters/codex.js.map +1 -0
  14. package/dist/commands/channel/adapters/index.d.ts +84 -0
  15. package/dist/commands/channel/adapters/index.d.ts.map +1 -0
  16. package/dist/commands/channel/adapters/index.js +115 -0
  17. package/dist/commands/channel/adapters/index.js.map +1 -0
  18. package/dist/commands/channel/adapters/types.d.ts +33 -0
  19. package/dist/commands/channel/adapters/types.d.ts.map +1 -0
  20. package/dist/commands/channel/adapters/types.js +2 -0
  21. package/dist/commands/channel/adapters/types.js.map +1 -0
  22. package/dist/commands/channel/agent-loader.d.ts +32 -0
  23. package/dist/commands/channel/agent-loader.d.ts.map +1 -0
  24. package/dist/commands/channel/agent-loader.js +154 -0
  25. package/dist/commands/channel/agent-loader.js.map +1 -0
  26. package/dist/commands/channel/context-loader.d.ts +26 -0
  27. package/dist/commands/channel/context-loader.d.ts.map +1 -0
  28. package/dist/commands/channel/context-loader.js +290 -0
  29. package/dist/commands/channel/context-loader.js.map +1 -0
  30. package/dist/commands/channel/context.d.ts +16 -0
  31. package/dist/commands/channel/context.d.ts.map +1 -0
  32. package/dist/commands/channel/context.js +83 -0
  33. package/dist/commands/channel/context.js.map +1 -0
  34. package/dist/commands/channel/create.d.ts +27 -0
  35. package/dist/commands/channel/create.d.ts.map +1 -0
  36. package/dist/commands/channel/create.js +39 -0
  37. package/dist/commands/channel/create.js.map +1 -0
  38. package/dist/commands/channel/dev-parse-trace.d.ts +14 -0
  39. package/dist/commands/channel/dev-parse-trace.d.ts.map +1 -0
  40. package/dist/commands/channel/dev-parse-trace.js +70 -0
  41. package/dist/commands/channel/dev-parse-trace.js.map +1 -0
  42. package/dist/commands/channel/guard.d.ts +150 -0
  43. package/dist/commands/channel/guard.d.ts.map +1 -0
  44. package/dist/commands/channel/guard.js +474 -0
  45. package/dist/commands/channel/guard.js.map +1 -0
  46. package/dist/commands/channel/index.d.ts +3 -0
  47. package/dist/commands/channel/index.d.ts.map +1 -0
  48. package/dist/commands/channel/index.js +531 -0
  49. package/dist/commands/channel/index.js.map +1 -0
  50. package/dist/commands/channel/interrupt.d.ts +10 -0
  51. package/dist/commands/channel/interrupt.d.ts.map +1 -0
  52. package/dist/commands/channel/interrupt.js +22 -0
  53. package/dist/commands/channel/interrupt.js.map +1 -0
  54. package/dist/commands/channel/kill.d.ts +7 -0
  55. package/dist/commands/channel/kill.d.ts.map +1 -0
  56. package/dist/commands/channel/kill.js +121 -0
  57. package/dist/commands/channel/kill.js.map +1 -0
  58. package/dist/commands/channel/list.d.ts +17 -0
  59. package/dist/commands/channel/list.d.ts.map +1 -0
  60. package/dist/commands/channel/list.js +233 -0
  61. package/dist/commands/channel/list.js.map +1 -0
  62. package/dist/commands/channel/messages.d.ts +15 -0
  63. package/dist/commands/channel/messages.d.ts.map +1 -0
  64. package/dist/commands/channel/messages.js +245 -0
  65. package/dist/commands/channel/messages.js.map +1 -0
  66. package/dist/commands/channel/rm.d.ts +27 -0
  67. package/dist/commands/channel/rm.d.ts.map +1 -0
  68. package/dist/commands/channel/rm.js +216 -0
  69. package/dist/commands/channel/rm.js.map +1 -0
  70. package/dist/commands/channel/run.d.ts +30 -0
  71. package/dist/commands/channel/run.d.ts.map +1 -0
  72. package/dist/commands/channel/run.js +130 -0
  73. package/dist/commands/channel/run.js.map +1 -0
  74. package/dist/commands/channel/send.d.ts +11 -0
  75. package/dist/commands/channel/send.d.ts.map +1 -0
  76. package/dist/commands/channel/send.js +24 -0
  77. package/dist/commands/channel/send.js.map +1 -0
  78. package/dist/commands/channel/spawn.d.ts +40 -0
  79. package/dist/commands/channel/spawn.d.ts.map +1 -0
  80. package/dist/commands/channel/spawn.js +244 -0
  81. package/dist/commands/channel/spawn.js.map +1 -0
  82. package/dist/commands/channel/store/events.d.ts +39 -0
  83. package/dist/commands/channel/store/events.d.ts.map +1 -0
  84. package/dist/commands/channel/store/events.js +87 -0
  85. package/dist/commands/channel/store/events.js.map +1 -0
  86. package/dist/commands/channel/store/filter.d.ts +3 -0
  87. package/dist/commands/channel/store/filter.d.ts.map +1 -0
  88. package/dist/commands/channel/store/filter.js +2 -0
  89. package/dist/commands/channel/store/filter.js.map +1 -0
  90. package/dist/commands/channel/store/lock.d.ts +23 -0
  91. package/dist/commands/channel/store/lock.d.ts.map +1 -0
  92. package/dist/commands/channel/store/lock.js +99 -0
  93. package/dist/commands/channel/store/lock.js.map +1 -0
  94. package/dist/commands/channel/store/paths.d.ts +63 -0
  95. package/dist/commands/channel/store/paths.d.ts.map +1 -0
  96. package/dist/commands/channel/store/paths.js +246 -0
  97. package/dist/commands/channel/store/paths.js.map +1 -0
  98. package/dist/commands/channel/store/schema.d.ts +27 -0
  99. package/dist/commands/channel/store/schema.d.ts.map +1 -0
  100. package/dist/commands/channel/store/schema.js +34 -0
  101. package/dist/commands/channel/store/schema.js.map +1 -0
  102. package/dist/commands/channel/store/thread-state.d.ts +5 -0
  103. package/dist/commands/channel/store/thread-state.d.ts.map +1 -0
  104. package/dist/commands/channel/store/thread-state.js +16 -0
  105. package/dist/commands/channel/store/thread-state.js.map +1 -0
  106. package/dist/commands/channel/store/watch.d.ts +19 -0
  107. package/dist/commands/channel/store/watch.d.ts.map +1 -0
  108. package/dist/commands/channel/store/watch.js +146 -0
  109. package/dist/commands/channel/store/watch.js.map +1 -0
  110. package/dist/commands/channel/supervisor/idle.d.ts +46 -0
  111. package/dist/commands/channel/supervisor/idle.d.ts.map +1 -0
  112. package/dist/commands/channel/supervisor/idle.js +72 -0
  113. package/dist/commands/channel/supervisor/idle.js.map +1 -0
  114. package/dist/commands/channel/supervisor/inbox.d.ts +30 -0
  115. package/dist/commands/channel/supervisor/inbox.d.ts.map +1 -0
  116. package/dist/commands/channel/supervisor/inbox.js +160 -0
  117. package/dist/commands/channel/supervisor/inbox.js.map +1 -0
  118. package/dist/commands/channel/supervisor/shutdown.d.ts +68 -0
  119. package/dist/commands/channel/supervisor/shutdown.d.ts.map +1 -0
  120. package/dist/commands/channel/supervisor/shutdown.js +146 -0
  121. package/dist/commands/channel/supervisor/shutdown.js.map +1 -0
  122. package/dist/commands/channel/supervisor/stdout.d.ts +51 -0
  123. package/dist/commands/channel/supervisor/stdout.d.ts.map +1 -0
  124. package/dist/commands/channel/supervisor/stdout.js +121 -0
  125. package/dist/commands/channel/supervisor/stdout.js.map +1 -0
  126. package/dist/commands/channel/supervisor/turns.d.ts +31 -0
  127. package/dist/commands/channel/supervisor/turns.d.ts.map +1 -0
  128. package/dist/commands/channel/supervisor/turns.js +45 -0
  129. package/dist/commands/channel/supervisor/turns.js.map +1 -0
  130. package/dist/commands/channel/supervisor/warning.d.ts +48 -0
  131. package/dist/commands/channel/supervisor/warning.d.ts.map +1 -0
  132. package/dist/commands/channel/supervisor/warning.js +77 -0
  133. package/dist/commands/channel/supervisor/warning.js.map +1 -0
  134. package/dist/commands/channel/supervisor.d.ts +59 -0
  135. package/dist/commands/channel/supervisor.d.ts.map +1 -0
  136. package/dist/commands/channel/supervisor.js +344 -0
  137. package/dist/commands/channel/supervisor.js.map +1 -0
  138. package/dist/commands/channel/text-body.d.ts +13 -0
  139. package/dist/commands/channel/text-body.d.ts.map +1 -0
  140. package/dist/commands/channel/text-body.js +47 -0
  141. package/dist/commands/channel/text-body.js.map +1 -0
  142. package/dist/commands/channel/threads.d.ts +39 -0
  143. package/dist/commands/channel/threads.d.ts.map +1 -0
  144. package/dist/commands/channel/threads.js +106 -0
  145. package/dist/commands/channel/threads.js.map +1 -0
  146. package/dist/commands/channel/title.d.ts +12 -0
  147. package/dist/commands/channel/title.d.ts.map +1 -0
  148. package/dist/commands/channel/title.js +24 -0
  149. package/dist/commands/channel/title.js.map +1 -0
  150. package/dist/commands/channel/wait.d.ts +17 -0
  151. package/dist/commands/channel/wait.d.ts.map +1 -0
  152. package/dist/commands/channel/wait.js +75 -0
  153. package/dist/commands/channel/wait.js.map +1 -0
  154. package/dist/commands/init.d.ts +3 -0
  155. package/dist/commands/init.d.ts.map +1 -1
  156. package/dist/commands/init.js +162 -43
  157. package/dist/commands/init.js.map +1 -1
  158. package/dist/commands/mem.d.ts +13 -217
  159. package/dist/commands/mem.d.ts.map +1 -1
  160. package/dist/commands/mem.js +142 -1587
  161. package/dist/commands/mem.js.map +1 -1
  162. package/dist/commands/uninstall.d.ts.map +1 -1
  163. package/dist/commands/uninstall.js +28 -2
  164. package/dist/commands/uninstall.js.map +1 -1
  165. package/dist/commands/update.d.ts.map +1 -1
  166. package/dist/commands/update.js +104 -7
  167. package/dist/commands/update.js.map +1 -1
  168. package/dist/commands/upgrade.d.ts +28 -0
  169. package/dist/commands/upgrade.d.ts.map +1 -0
  170. package/dist/commands/upgrade.js +84 -0
  171. package/dist/commands/upgrade.js.map +1 -0
  172. package/dist/commands/workflow.d.ts +35 -0
  173. package/dist/commands/workflow.d.ts.map +1 -0
  174. package/dist/commands/workflow.js +232 -0
  175. package/dist/commands/workflow.js.map +1 -0
  176. package/dist/configurators/claude.d.ts.map +1 -1
  177. package/dist/configurators/claude.js +1 -0
  178. package/dist/configurators/claude.js.map +1 -1
  179. package/dist/configurators/index.d.ts.map +1 -1
  180. package/dist/configurators/index.js +5 -0
  181. package/dist/configurators/index.js.map +1 -1
  182. package/dist/configurators/reasonix.d.ts +23 -0
  183. package/dist/configurators/reasonix.d.ts.map +1 -0
  184. package/dist/configurators/reasonix.js +60 -0
  185. package/dist/configurators/reasonix.js.map +1 -0
  186. package/dist/configurators/shared.d.ts.map +1 -1
  187. package/dist/configurators/shared.js +8 -0
  188. package/dist/configurators/shared.js.map +1 -1
  189. package/dist/configurators/workflow.d.ts +8 -0
  190. package/dist/configurators/workflow.d.ts.map +1 -1
  191. package/dist/configurators/workflow.js +14 -3
  192. package/dist/configurators/workflow.js.map +1 -1
  193. package/dist/constants/paths.d.ts +4 -0
  194. package/dist/constants/paths.d.ts.map +1 -1
  195. package/dist/constants/paths.js +4 -0
  196. package/dist/constants/paths.js.map +1 -1
  197. package/dist/migrations/manifests/0.5.13.json +9 -0
  198. package/dist/migrations/manifests/0.5.14.json +9 -0
  199. package/dist/migrations/manifests/0.5.15.json +9 -0
  200. package/dist/migrations/manifests/0.5.16.json +9 -0
  201. package/dist/migrations/manifests/0.5.17.json +9 -0
  202. package/dist/migrations/manifests/0.5.18.json +9 -0
  203. package/dist/migrations/manifests/0.5.19.json +9 -0
  204. package/dist/migrations/manifests/0.6.0-beta.10.json +9 -0
  205. package/dist/migrations/manifests/0.6.0-beta.11.json +9 -0
  206. package/dist/migrations/manifests/0.6.0-beta.12.json +9 -0
  207. package/dist/migrations/manifests/0.6.0-beta.13.json +9 -0
  208. package/dist/migrations/manifests/0.6.0-beta.14.json +9 -0
  209. package/dist/migrations/manifests/0.6.0-beta.15.json +9 -0
  210. package/dist/migrations/manifests/0.6.0-beta.16.json +9 -0
  211. package/dist/migrations/manifests/0.6.0-beta.17.json +9 -0
  212. package/dist/migrations/manifests/0.6.0-beta.18.json +16 -0
  213. package/dist/migrations/manifests/0.6.0-beta.19.json +9 -0
  214. package/dist/migrations/manifests/0.6.0-beta.20.json +9 -0
  215. package/dist/migrations/manifests/0.6.0-beta.21.json +9 -0
  216. package/dist/migrations/manifests/0.6.0-beta.22.json +9 -0
  217. package/dist/migrations/manifests/0.6.0-beta.23.json +88 -0
  218. package/dist/migrations/manifests/0.6.0-beta.9.json +9 -0
  219. package/dist/migrations/manifests/0.6.0-rc.0.json +9 -0
  220. package/dist/templates/claude/agents/trellis-check.md +12 -6
  221. package/dist/templates/claude/agents/trellis-implement.md +1 -1
  222. package/dist/templates/claude/agents/trellis-research.md +1 -1
  223. package/dist/templates/claude/settings.json +4 -4
  224. package/dist/templates/codebuddy/agents/trellis-check.md +12 -6
  225. package/dist/templates/codebuddy/agents/trellis-implement.md +1 -1
  226. package/dist/templates/codebuddy/agents/trellis-research.md +1 -1
  227. package/dist/templates/codebuddy/settings.json +4 -4
  228. package/dist/templates/codex/agents/trellis-check.toml +0 -25
  229. package/dist/templates/codex/agents/trellis-implement.toml +0 -25
  230. package/dist/templates/codex/config.toml +9 -16
  231. package/dist/templates/codex/hooks/session-start.py +22 -0
  232. package/dist/templates/codex/hooks.json +2 -2
  233. package/dist/templates/codex/skills/brainstorm/SKILL.md +69 -519
  234. package/dist/templates/common/bundled-skills/trellis-meta/references/local-architecture/task-system.md +27 -0
  235. package/dist/templates/common/bundled-skills/trellis-session-insight/SKILL.md +81 -0
  236. package/dist/templates/common/bundled-skills/trellis-session-insight/references/cli-quick-reference.md +66 -0
  237. package/dist/templates/common/bundled-skills/trellis-session-insight/references/triggering-patterns.md +93 -0
  238. package/dist/templates/common/bundled-skills/trellis-spec-bootstrap/SKILL.md +41 -0
  239. package/dist/templates/common/bundled-skills/trellis-spec-bootstrap/references/mcp-setup.md +90 -0
  240. package/dist/templates/common/bundled-skills/trellis-spec-bootstrap/references/repository-analysis.md +59 -0
  241. package/dist/templates/common/bundled-skills/trellis-spec-bootstrap/references/spec-task-planning.md +61 -0
  242. package/dist/templates/common/bundled-skills/trellis-spec-bootstrap/references/spec-writing.md +70 -0
  243. package/dist/templates/common/skills/brainstorm.md +68 -518
  244. package/dist/templates/copilot/hooks/session-start.py +36 -11
  245. package/dist/templates/copilot/hooks.json +2 -2
  246. package/dist/templates/copilot/prompts/brainstorm.prompt.md +69 -519
  247. package/dist/templates/cursor/agents/trellis-check.md +12 -6
  248. package/dist/templates/cursor/agents/trellis-implement.md +1 -1
  249. package/dist/templates/cursor/agents/trellis-research.md +1 -1
  250. package/dist/templates/cursor/hooks.json +1 -7
  251. package/dist/templates/droid/droids/trellis-check.md +12 -6
  252. package/dist/templates/droid/droids/trellis-implement.md +1 -1
  253. package/dist/templates/droid/droids/trellis-research.md +1 -1
  254. package/dist/templates/droid/settings.json +4 -4
  255. package/dist/templates/gemini/agents/trellis-check.md +11 -5
  256. package/dist/templates/gemini/settings.json +2 -2
  257. package/dist/templates/kiro/agents/trellis-check.json +1 -1
  258. package/dist/templates/markdown/spec/guides/code-reuse-thinking-guide.md.txt +127 -9
  259. package/dist/templates/markdown/spec/guides/cross-layer-thinking-guide.md.txt +171 -6
  260. package/dist/templates/markdown/spec/guides/cross-platform-thinking-guide.md.txt +48 -4
  261. package/dist/templates/markdown/spec/guides/index.md.txt +18 -0
  262. package/dist/templates/opencode/agents/trellis-check.md +11 -5
  263. package/dist/templates/opencode/lib/trellis-context.js +73 -11
  264. package/dist/templates/opencode/plugins/inject-subagent-context.js +112 -26
  265. package/dist/templates/opencode/plugins/inject-workflow-state.js +8 -1
  266. package/dist/templates/opencode/plugins/session-start.js +9 -1
  267. package/dist/templates/pi/agents/trellis-check.md +5 -4
  268. package/dist/templates/pi/agents/trellis-implement.md +5 -4
  269. package/dist/templates/pi/extensions/trellis/index.ts.txt +1339 -913
  270. package/dist/templates/pi/settings.json +0 -9
  271. package/dist/templates/qoder/agents/trellis-check.md +12 -6
  272. package/dist/templates/qoder/agents/trellis-implement.md +1 -1
  273. package/dist/templates/qoder/agents/trellis-research.md +1 -1
  274. package/dist/templates/qoder/settings.json +4 -4
  275. package/dist/templates/reasonix/agents/trellis-check.md +36 -0
  276. package/dist/templates/reasonix/agents/trellis-implement.md +41 -0
  277. package/dist/templates/reasonix/index.d.ts +13 -0
  278. package/dist/templates/reasonix/index.d.ts.map +1 -0
  279. package/dist/templates/reasonix/index.js +16 -0
  280. package/dist/templates/reasonix/index.js.map +1 -0
  281. package/dist/templates/shared-hooks/index.d.ts.map +1 -1
  282. package/dist/templates/shared-hooks/index.js +0 -1
  283. package/dist/templates/shared-hooks/index.js.map +1 -1
  284. package/dist/templates/shared-hooks/inject-workflow-state.py +22 -0
  285. package/dist/templates/shared-hooks/session-start.py +25 -8
  286. package/dist/templates/trellis/agents/check.md +70 -0
  287. package/dist/templates/trellis/agents/implement.md +71 -0
  288. package/dist/templates/trellis/config.yaml +20 -0
  289. package/dist/templates/trellis/index.d.ts +13 -0
  290. package/dist/templates/trellis/index.d.ts.map +1 -1
  291. package/dist/templates/trellis/index.js +22 -0
  292. package/dist/templates/trellis/index.js.map +1 -1
  293. package/dist/templates/trellis/scripts/common/safe_commit.py +49 -19
  294. package/dist/templates/trellis/scripts/common/session_context.py +215 -138
  295. package/dist/templates/trellis/scripts/common/task_store.py +94 -16
  296. package/dist/templates/trellis/workflow.md +21 -0
  297. package/dist/types/ai-tools.d.ts +4 -4
  298. package/dist/types/ai-tools.d.ts.map +1 -1
  299. package/dist/types/ai-tools.js +16 -0
  300. package/dist/types/ai-tools.js.map +1 -1
  301. package/dist/utils/agent-refs.d.ts +31 -0
  302. package/dist/utils/agent-refs.d.ts.map +1 -0
  303. package/dist/utils/agent-refs.js +63 -0
  304. package/dist/utils/agent-refs.js.map +1 -0
  305. package/dist/utils/cwd-guard.d.ts +38 -0
  306. package/dist/utils/cwd-guard.d.ts.map +1 -0
  307. package/dist/utils/cwd-guard.js +62 -0
  308. package/dist/utils/cwd-guard.js.map +1 -0
  309. package/dist/utils/file-writer.d.ts +13 -0
  310. package/dist/utils/file-writer.d.ts.map +1 -1
  311. package/dist/utils/file-writer.js +59 -1
  312. package/dist/utils/file-writer.js.map +1 -1
  313. package/dist/utils/manifest-prune.d.ts +61 -0
  314. package/dist/utils/manifest-prune.d.ts.map +1 -0
  315. package/dist/utils/manifest-prune.js +136 -0
  316. package/dist/utils/manifest-prune.js.map +1 -0
  317. package/dist/utils/registry-config.d.ts +7 -0
  318. package/dist/utils/registry-config.d.ts.map +1 -0
  319. package/dist/utils/registry-config.js +171 -0
  320. package/dist/utils/registry-config.js.map +1 -0
  321. package/dist/utils/task-json.d.ts +9 -42
  322. package/dist/utils/task-json.d.ts.map +1 -1
  323. package/dist/utils/task-json.js +8 -45
  324. package/dist/utils/task-json.js.map +1 -1
  325. package/dist/utils/template-fetcher.d.ts +11 -0
  326. package/dist/utils/template-fetcher.d.ts.map +1 -1
  327. package/dist/utils/template-fetcher.js +51 -2
  328. package/dist/utils/template-fetcher.js.map +1 -1
  329. package/dist/utils/template-hash.d.ts +32 -6
  330. package/dist/utils/template-hash.d.ts.map +1 -1
  331. package/dist/utils/template-hash.js +53 -31
  332. package/dist/utils/template-hash.js.map +1 -1
  333. package/dist/utils/workflow-resolver.d.ts +86 -0
  334. package/dist/utils/workflow-resolver.d.ts.map +1 -0
  335. package/dist/utils/workflow-resolver.js +265 -0
  336. package/dist/utils/workflow-resolver.js.map +1 -0
  337. package/package.json +9 -8
@@ -215,20 +215,26 @@ home = Path.home()
215
215
  ```
216
216
 
217
217
  **Rule 2**: When injecting environment variables into shell commands, generate
218
- the prefix for the actual host shell. Do not assume `export` works everywhere.
219
- AI tool "Bash" surfaces on Windows may execute through PowerShell.
218
+ the prefix for the actual shell that will parse the command. Do not choose
219
+ syntax from OS alone. AI tool "Bash" surfaces on Windows may execute through
220
+ PowerShell, Git Bash, MSYS2, or another POSIX-like shell.
220
221
 
221
222
  ```javascript
222
223
  // BAD - breaks when the host shell is PowerShell
223
224
  command = `export TRELLIS_CONTEXT_ID=${shellQuote(contextKey)}; ${command}`;
224
225
 
225
- // GOOD - shell-aware command prefix
226
- const prefix = process.platform === "win32"
226
+ // GOOD - shell-dialect-aware command prefix
227
+ const prefix = process.platform === "win32" && !isWindowsPosixShell(process.env)
227
228
  ? `$env:TRELLIS_CONTEXT_ID = ${powershellQuote(contextKey)}; `
228
229
  : `export TRELLIS_CONTEXT_ID=${shellQuote(contextKey)}; `;
229
230
  command = `${prefix}${command}`;
230
231
  ```
231
232
 
233
+ On Windows, treat `MSYSTEM`, `MINGW_PREFIX`, `OSTYPE=msys|mingw|cygwin`,
234
+ `SHELL=...bash`, or a platform-specific Git Bash setting as POSIX-shell
235
+ signals. Keep PowerShell as the Windows default when there is no POSIX-shell
236
+ signal.
237
+
232
238
  Also make duplicate-injection detection shell-aware. A guard that only matches
233
239
  `export VAR=` will miss PowerShell's `$env:VAR = ...` form and can wrap an
234
240
  already-correct command a second time.
@@ -587,3 +593,41 @@ const { getMigrationsForVersion } = require('./dist/migrations/index.js');
587
593
  console.log('From 0.2.12:', getMigrationsForVersion('0.2.12', 'CURRENT').length);
588
594
  "
589
595
  ```
596
+
597
+ ## Release Checklist: Bundled Assets
598
+
599
+ When release notes or docs claim an asset is bundled, installed automatically, or
600
+ included with Trellis, verify the whole distribution path:
601
+
602
+ - [ ] Source file exists in the branch being tagged, not only in another branch,
603
+ docs submodule, or marketplace tree.
604
+ - [ ] `pnpm build` copies the asset into `dist/templates/**`.
605
+ - [ ] `npm pack --dry-run --json` includes the expected `dist/**` path.
606
+ - [ ] The built binary installs the asset in a fresh temp repository.
607
+ - [ ] `.trellis/.template-hashes.json` tracks the generated asset path.
608
+ - [ ] `trellis update --dry-run` reports `Already up to date!` in that temp
609
+ repository.
610
+
611
+ **Why this matters**: docs/changelog text can move independently from the code
612
+ branch that owns distributable templates. A feature can be documented as bundled
613
+ while the published npm tarball still lacks the files.
614
+
615
+ ```bash
616
+ pnpm --filter @mindfoldhq/trellis build
617
+
618
+ cd packages/cli
619
+ npm pack --dry-run --json | grep 'dist/templates/common/bundled-skills/<skill>/SKILL.md'
620
+ cd ../..
621
+
622
+ tmpdir=$(mktemp -d /tmp/trellis-built-bin-smoke-XXXXXX)
623
+ printf '{"name":"trellis-smoke","version":"0.0.0"}\n' > "$tmpdir/package.json"
624
+ git -C "$tmpdir" init -q
625
+ (
626
+ cd "$tmpdir"
627
+ node /path/to/Trellis/packages/cli/bin/trellis.js init -u smoke --yes --claude --codex
628
+ test -f .claude/skills/<skill>/SKILL.md
629
+ test -f .agents/skills/<skill>/SKILL.md
630
+ grep -q '<skill>' .trellis/.template-hashes.json
631
+ node /path/to/Trellis/packages/cli/bin/trellis.js update --dry-run
632
+ )
633
+ ```
@@ -34,6 +34,8 @@ These guides help you **ask the right questions before coding**.
34
34
  - [ ] Data format changes between layers
35
35
  - [ ] Multiple consumers need the same data
36
36
  - [ ] You're not sure where to put some logic
37
+ - [ ] You are adding an event kind, JSONL record, RPC payload, or config field
38
+ - [ ] UI / command code starts casting raw payload fields directly
37
39
 
38
40
  → Read [Cross-Layer Thinking Guide](./cross-layer-thinking-guide.md)
39
41
 
@@ -44,9 +46,25 @@ These guides help you **ask the right questions before coding**.
44
46
  - [ ] You're adding a new field to multiple places
45
47
  - [ ] **You're modifying any constant or config**
46
48
  - [ ] **You're creating a new utility/helper function** ← Search first!
49
+ - [ ] Two files read the same untyped payload field with local casts
50
+ - [ ] Multiple branches update the same derived state from `kind` / `action`
47
51
 
48
52
  → Read [Code Reuse Thinking Guide](./code-reuse-thinking-guide.md)
49
53
 
54
+ ### When Verifying AI Cross-Review Results
55
+
56
+ - [ ] Reviewer claims "user input can be malicious" → Check the actual data source (internal manifest? user config? external API?)
57
+ - [ ] Reviewer flags "missing validation" → Is the data from a trusted internal source?
58
+ - [ ] Reviewer says "behavior change" → Read the code comments — is it intentional design?
59
+ - [ ] Reviewer identifies a "bug" in test → Mentally delete the feature being tested — does the test still pass? If yes → tautological test
60
+
61
+ **Common AI reviewer false-positive patterns**:
62
+ 1. **Trust boundary confusion**: Treating internal data (bundled JSON manifests) as untrusted external input
63
+ 2. **Ignoring design comments**: Flagging intentional behavior documented in code comments as bugs
64
+ 3. **Variable misreading**: Not tracing a variable to its actual definition (e.g., Map keyed by path vs name)
65
+
66
+ **Verification rule**: Every CRITICAL/WARNING finding must be verified against the actual code before prioritizing. Budget ~35% false-positive rate for AI reviews.
67
+
50
68
  ---
51
69
 
52
70
  ## Pre-Modification Rule (CRITICAL)
@@ -34,14 +34,18 @@ Look for the `<!-- trellis-hook-injected -->` marker in your input above.
34
34
 
35
35
  Before checking, read:
36
36
  - `.trellis/spec/` - Development guidelines
37
+ - Task `prd.md` - Requirements document
38
+ - Task `design.md` - Technical design (if exists)
39
+ - Task `implement.md` - Execution plan (if exists)
37
40
  - Pre-commit checklist for quality standards
38
41
 
39
42
  ## Core Responsibilities
40
43
 
41
44
  1. **Get code changes** - Use git diff to get uncommitted code
42
- 2. **Check against specs** - Verify code follows guidelines
43
- 3. **Self-fix** - Fix issues yourself, not just report them
44
- 4. **Run verification** - typecheck and lint
45
+ 2. **Review task artifacts** - Check changes against prd.md, design.md if present, and implement.md if present
46
+ 3. **Check against specs** - Verify code follows guidelines
47
+ 4. **Self-fix** - Fix issues yourself, not just report them
48
+ 5. **Run verification** - typecheck and lint
45
49
 
46
50
  ## Important
47
51
 
@@ -60,10 +64,12 @@ git diff --name-only # List changed files
60
64
  git diff # View specific changes
61
65
  ```
62
66
 
63
- ### Step 2: Check Against Specs
67
+ ### Step 2: Check Against Specs and Task Artifacts
64
68
 
65
- Read relevant specs in `.trellis/spec/` to check code:
69
+ Read the task's prd.md, design.md if present, and implement.md if present, then read relevant specs in `.trellis/spec/` to check code:
66
70
 
71
+ - Does it satisfy the task requirements
72
+ - Does it follow the technical design and implementation plan when present
67
73
  - Does it follow directory structure conventions
68
74
  - Does it follow naming conventions
69
75
  - Does it follow code patterns
@@ -63,6 +63,21 @@ function buildContextKey(platformName, kind, value) {
63
63
  return safeValue ? `${platformName}_${safeValue}` : `${platformName}_${hashValue(value)}`
64
64
  }
65
65
 
66
+ // Matches `trellis-implement`, `trellis-check`, `trellis-research` exactly.
67
+ // Used by chat.message plugins to skip injection inside Trellis sub-agent turns.
68
+ const TRELLIS_SUBAGENT_RE = /^trellis-(implement|check|research)$/
69
+
70
+ /**
71
+ * Return true when the OpenCode `chat.message` input represents a Trellis
72
+ * sub-agent turn. `input.agent` is set by OpenCode when a Task tool spawns a
73
+ * child session with a custom agent (see `packages/opencode/src/tool/task.ts`).
74
+ */
75
+ export function isTrellisSubagent(input) {
76
+ if (!input || typeof input !== "object") return false
77
+ const agent = typeof input.agent === "string" ? input.agent.trim() : ""
78
+ return TRELLIS_SUBAGENT_RE.test(agent)
79
+ }
80
+
66
81
  /**
67
82
  * Trellis Context Manager
68
83
  */
@@ -116,27 +131,74 @@ export class TrellisContext {
116
131
 
117
132
  /**
118
133
  * Get active task from session runtime context.
134
+ *
135
+ * Resolution order (mirrors Python `active_task.resolve_active_task`):
136
+ * 1. Lookup the runtime file for the input-derived context key.
137
+ * 2. If that misses and exactly one session runtime file exists locally,
138
+ * use it (`_resolveSingleSessionFallback`). Refuses to guess when 0 or
139
+ * ≥2 files exist so multi-window isolation holds.
119
140
  */
120
141
  getActiveTask(platformInput = null) {
121
142
  const contextKey = this.getContextKey(platformInput)
122
- if (!contextKey) {
123
- return { taskPath: null, source: "none", stale: false }
143
+ if (contextKey) {
144
+ const context = this.readContext(contextKey)
145
+ const taskRef = this.normalizeTaskRef(context?.current_task || "")
146
+ if (taskRef) {
147
+ const taskDir = this.resolveTaskDir(taskRef)
148
+ return {
149
+ taskPath: taskRef,
150
+ source: `session:${contextKey}`,
151
+ stale: !taskDir || !existsSync(taskDir),
152
+ }
153
+ }
124
154
  }
125
155
 
126
- const context = this.readContext(contextKey)
127
- const taskRef = this.normalizeTaskRef(context?.current_task || "")
128
- if (taskRef) {
129
- const taskDir = this.resolveTaskDir(taskRef)
130
- return {
131
- taskPath: taskRef,
132
- source: `session:${contextKey}`,
133
- stale: !taskDir || !existsSync(taskDir),
134
- }
156
+ const fallback = this._resolveSingleSessionFallback()
157
+ if (fallback) {
158
+ return fallback
135
159
  }
136
160
 
137
161
  return { taskPath: null, source: "none", stale: false }
138
162
  }
139
163
 
164
+ /**
165
+ * Mirror of Python `_resolve_single_session_fallback`. Returns the task
166
+ * pointed at by the sole session runtime file when exactly one exists,
167
+ * else null.
168
+ */
169
+ _resolveSingleSessionFallback() {
170
+ const sessionsDir = join(this.directory, ".trellis", ".runtime", "sessions")
171
+ if (!existsSync(sessionsDir)) return null
172
+
173
+ let files
174
+ try {
175
+ files = readdirSync(sessionsDir)
176
+ .filter(name => name.endsWith(".json"))
177
+ .sort()
178
+ } catch {
179
+ return null
180
+ }
181
+ if (files.length !== 1) return null
182
+
183
+ const sessionFile = join(sessionsDir, files[0])
184
+ let context
185
+ try {
186
+ context = JSON.parse(readFileSync(sessionFile, "utf-8"))
187
+ } catch {
188
+ return null
189
+ }
190
+ const taskRef = this.normalizeTaskRef(context?.current_task || "")
191
+ if (!taskRef) return null
192
+
193
+ const taskDir = this.resolveTaskDir(taskRef)
194
+ const fallbackKey = files[0].replace(/\.json$/, "")
195
+ return {
196
+ taskPath: taskRef,
197
+ source: `session-fallback:${fallbackKey}`,
198
+ stale: !taskDir || !existsSync(taskDir),
199
+ }
200
+ }
201
+
140
202
  getCurrentTask(platformInput = null) {
141
203
  return this.getActiveTask(platformInput).taskPath
142
204
  }
@@ -14,29 +14,44 @@ import { TrellisContext, debugLog } from "../lib/trellis-context.js"
14
14
  const AGENTS_ALL = ["implement", "check", "research"]
15
15
  const AGENTS_REQUIRE_TASK = ["implement", "check"]
16
16
 
17
+ // Match `Active task: <path>` on the first non-empty line of the dispatch
18
+ // prompt. Mirrors the contract in workflow.md's [workflow-state:in_progress]
19
+ // breadcrumb so multi-window users can disambiguate which task is targeted.
20
+ const ACTIVE_TASK_HINT_RE = /^\s*Active task:\s*(\S+)\s*$/m
21
+
22
+ function extractActiveTaskHint(prompt) {
23
+ if (typeof prompt !== "string" || !prompt) return null
24
+ const match = prompt.match(ACTIVE_TASK_HINT_RE)
25
+ return match ? match[1].trim() : null
26
+ }
27
+
17
28
  /**
18
- * Get context for implement agent
29
+ * Get context for implement agent. `taskDir` may be relative
30
+ * (`.trellis/tasks/foo`) or absolute; both are resolved via
31
+ * `ctx.resolveTaskDir`.
19
32
  */
20
33
  function getImplementContext(ctx, taskDir) {
21
34
  const parts = []
35
+ const taskDirFull = ctx.resolveTaskDir(taskDir)
36
+ if (!taskDirFull) return ""
22
37
 
23
- const jsonlPath = join(ctx.directory, taskDir, "implement.jsonl")
38
+ const jsonlPath = join(taskDirFull, "implement.jsonl")
24
39
  const entries = ctx.readJsonlWithFiles(jsonlPath)
25
40
  if (entries.length > 0) {
26
41
  parts.push(ctx.buildContextFromEntries(entries))
27
42
  }
28
43
 
29
- const prd = ctx.readProjectFile(join(taskDir, "prd.md"))
44
+ const prd = ctx.readFile(join(taskDirFull, "prd.md"))
30
45
  if (prd) {
31
46
  parts.push(`=== ${taskDir}/prd.md (Requirements) ===\n${prd}`)
32
47
  }
33
48
 
34
- const design = ctx.readProjectFile(join(taskDir, "design.md"))
49
+ const design = ctx.readFile(join(taskDirFull, "design.md"))
35
50
  if (design) {
36
51
  parts.push(`=== ${taskDir}/design.md (Technical Design) ===\n${design}`)
37
52
  }
38
53
 
39
- const implementPlan = ctx.readProjectFile(join(taskDir, "implement.md"))
54
+ const implementPlan = ctx.readFile(join(taskDirFull, "implement.md"))
40
55
  if (implementPlan) {
41
56
  parts.push(`=== ${taskDir}/implement.md (Execution Plan) ===\n${implementPlan}`)
42
57
  }
@@ -45,28 +60,30 @@ function getImplementContext(ctx, taskDir) {
45
60
  }
46
61
 
47
62
  /**
48
- * Get context for check agent
63
+ * Get context for check agent. `taskDir` may be relative or absolute.
49
64
  */
50
65
  function getCheckContext(ctx, taskDir) {
51
66
  const parts = []
67
+ const taskDirFull = ctx.resolveTaskDir(taskDir)
68
+ if (!taskDirFull) return ""
52
69
 
53
- const jsonlPath = join(ctx.directory, taskDir, "check.jsonl")
70
+ const jsonlPath = join(taskDirFull, "check.jsonl")
54
71
  const entries = ctx.readJsonlWithFiles(jsonlPath)
55
72
  if (entries.length > 0) {
56
73
  parts.push(ctx.buildContextFromEntries(entries))
57
74
  }
58
75
 
59
- const prd = ctx.readProjectFile(join(taskDir, "prd.md"))
76
+ const prd = ctx.readFile(join(taskDirFull, "prd.md"))
60
77
  if (prd) {
61
78
  parts.push(`=== ${taskDir}/prd.md (Requirements) ===\n${prd}`)
62
79
  }
63
80
 
64
- const design = ctx.readProjectFile(join(taskDir, "design.md"))
81
+ const design = ctx.readFile(join(taskDirFull, "design.md"))
65
82
  if (design) {
66
83
  parts.push(`=== ${taskDir}/design.md (Technical Design) ===\n${design}`)
67
84
  }
68
85
 
69
- const implementPlan = ctx.readProjectFile(join(taskDir, "implement.md"))
86
+ const implementPlan = ctx.readFile(join(taskDirFull, "implement.md"))
70
87
  if (implementPlan) {
71
88
  parts.push(`=== ${taskDir}/implement.md (Execution Plan) ===\n${implementPlan}`)
72
89
  }
@@ -143,7 +160,8 @@ function getResearchContext(ctx) {
143
160
  */
144
161
  function buildPrompt(agentType, originalPrompt, context, isFinish = false) {
145
162
  const templates = {
146
- implement: `# Implement Agent Task
163
+ implement: `<!-- trellis-hook-injected -->
164
+ # Implement Agent Task
147
165
 
148
166
  You are the Implement Agent in the Multi-Agent Pipeline.
149
167
 
@@ -172,7 +190,8 @@ ${originalPrompt}
172
190
  - Follow all dev specs injected above
173
191
  - Report list of modified/created files when done`,
174
192
 
175
- check: isFinish ? `# Finish Agent Task
193
+ check: isFinish ? `<!-- trellis-hook-injected -->
194
+ # Finish Agent Task
176
195
 
177
196
  You are performing the final check before creating a PR.
178
197
 
@@ -207,7 +226,8 @@ ${originalPrompt}
207
226
  - If critical CODE issues found, report them clearly (fix specs, not code)
208
227
  - Verify all acceptance criteria in prd.md are met
209
228
  - Verify design.md and implement.md constraints when those files are present` :
210
- `# Check Agent Task
229
+ `<!-- trellis-hook-injected -->
230
+ # Check Agent Task
211
231
 
212
232
  You are the Check Agent in the Multi-Agent Pipeline.
213
233
 
@@ -235,7 +255,8 @@ ${originalPrompt}
235
255
  - Fix issues yourself, don't just report
236
256
  - Must execute complete checklist`,
237
257
 
238
- research: `# Research Agent Task
258
+ research: `<!-- trellis-hook-injected -->
259
+ # Research Agent Task
239
260
 
240
261
  You are the Research Agent in the Multi-Agent Pipeline.
241
262
 
@@ -280,9 +301,29 @@ function powershellQuote(value) {
280
301
  return `'${String(value).replace(/'/g, "''")}'`
281
302
  }
282
303
 
283
- function buildTrellisContextPrefix(contextKey, hostPlatform = process.platform) {
284
- if (hostPlatform === "win32") {
285
- // OpenCode's Windows Bash tool runs through PowerShell, not a POSIX shell.
304
+ function envValue(env, key) {
305
+ const value = env?.[key]
306
+ return typeof value === "string" && value.trim() ? value.trim() : null
307
+ }
308
+
309
+ function shellBasename(value) {
310
+ return value.replace(/\\/g, "/").split("/").pop()?.toLowerCase() || ""
311
+ }
312
+
313
+ function isWindowsPosixShell(env = process.env) {
314
+ if (envValue(env, "MSYSTEM")) return true
315
+ if (envValue(env, "MINGW_PREFIX")) return true
316
+ if (envValue(env, "OPENCODE_GIT_BASH_PATH")) return true
317
+
318
+ const ostype = envValue(env, "OSTYPE")?.toLowerCase() || ""
319
+ if (/(msys|mingw|cygwin)/.test(ostype)) return true
320
+
321
+ const shell = shellBasename(envValue(env, "SHELL") || "")
322
+ return /^(bash|sh|zsh)(\.exe)?$/.test(shell)
323
+ }
324
+
325
+ function buildTrellisContextPrefix(contextKey, hostPlatform = process.platform, env = process.env) {
326
+ if (hostPlatform === "win32" && !isWindowsPosixShell(env)) {
286
327
  return `$env:TRELLIS_CONTEXT_ID = ${powershellQuote(contextKey)}; `
287
328
  }
288
329
 
@@ -301,7 +342,7 @@ function commandStartsWithTrellisContext(command) {
301
342
  return (
302
343
  /^TRELLIS_CONTEXT_ID\s*=/.test(firstCommand) ||
303
344
  /^export\s+TRELLIS_CONTEXT_ID\s*=/.test(firstCommand) ||
304
- /^env\s+(?:[^\s=]+\s+)*TRELLIS_CONTEXT_ID\s*=/.test(firstCommand) ||
345
+ /^env\s+(?:(?:-\S+|[A-Za-z_][A-Za-z0-9_]*=\S*)\s+)*TRELLIS_CONTEXT_ID\s*=/.test(firstCommand) ||
305
346
  /^\$env:TRELLIS_CONTEXT_ID\s*=/i.test(firstCommand)
306
347
  )
307
348
  }
@@ -310,7 +351,7 @@ function commandStartsWithTrellisContext(command) {
310
351
  * OpenCode TUI may not expose OPENCODE_RUN_ID to Bash. The plugin hook still
311
352
  * receives session identity, so inject it into Bash commands before execution.
312
353
  */
313
- function injectTrellisContextIntoBash(ctx, input, output, hostPlatform) {
354
+ function injectTrellisContextIntoBash(ctx, input, output, hostPlatform, env) {
314
355
  const args = output?.args
315
356
  const commandKey = getBashCommandKey(args)
316
357
  if (!commandKey) return false
@@ -322,7 +363,7 @@ function injectTrellisContextIntoBash(ctx, input, output, hostPlatform) {
322
363
  const contextKey = ctx.getContextKey(input)
323
364
  if (!contextKey) return false
324
365
 
325
- args[commandKey] = `${buildTrellisContextPrefix(contextKey, hostPlatform)}${command}`
366
+ args[commandKey] = `${buildTrellisContextPrefix(contextKey, hostPlatform, env)}${command}`
326
367
  return true
327
368
  }
328
369
 
@@ -331,7 +372,7 @@ function injectTrellisContextIntoBash(ctx, input, output, hostPlatform) {
331
372
  // (packages/opencode/src/plugin/index.ts — `for ([_, fn] of Object.entries(mod)) await fn(input)`);
332
373
  // the previous `{ id, server }` object shape failed with
333
374
  // `TypeError: fn is not a function` in 1.2.x.
334
- export default async ({ directory, platform: hostPlatform = process.platform }) => {
375
+ export default async ({ directory, platform: hostPlatform = process.platform, env = process.env }) => {
335
376
  const ctx = new TrellisContext(directory)
336
377
  debugLog("inject", "Plugin loaded, directory:", directory)
337
378
 
@@ -345,7 +386,7 @@ export default async ({ directory, platform: hostPlatform = process.platform })
345
386
 
346
387
  const toolName = input?.tool?.toLowerCase()
347
388
  if (toolName === "bash") {
348
- if (injectTrellisContextIntoBash(ctx, input, output, hostPlatform)) {
389
+ if (injectTrellisContextIntoBash(ctx, input, output, hostPlatform, env)) {
349
390
  debugLog("inject", "Injected TRELLIS_CONTEXT_ID into Bash command")
350
391
  }
351
392
  return
@@ -370,8 +411,53 @@ export default async ({ directory, platform: hostPlatform = process.platform })
370
411
  return
371
412
  }
372
413
 
373
- // Resolve active task through session runtime context.
374
- const taskDir = ctx.getCurrentTask(input)
414
+ // Resolve active task in this priority order (only later steps
415
+ // run when earlier ones miss):
416
+ // 1. Exact session runtime context lookup for input.sessionID
417
+ // 2. `Active task: <path>` hint in the dispatch prompt
418
+ // (explicit per-dispatch override — beats single-session
419
+ // inference so multi-window users can disambiguate)
420
+ // 3. Single-session fallback — only when exactly 1 session
421
+ // runtime file exists locally
422
+ let taskDir = null
423
+ let taskSource = null
424
+
425
+ const contextKey = ctx.getContextKey(input)
426
+ if (contextKey) {
427
+ const context = ctx.readContext(contextKey)
428
+ const exactRef = ctx.normalizeTaskRef(context?.current_task || "")
429
+ if (exactRef) {
430
+ taskDir = exactRef
431
+ taskSource = `session:${contextKey}`
432
+ }
433
+ }
434
+
435
+ if (!taskDir) {
436
+ const hintRef = extractActiveTaskHint(originalPrompt)
437
+ if (hintRef) {
438
+ const hintNormalized = ctx.normalizeTaskRef(hintRef)
439
+ if (hintNormalized) {
440
+ const hintDir = ctx.resolveTaskDir(hintNormalized)
441
+ if (hintDir && existsSync(hintDir)) {
442
+ taskDir = hintNormalized
443
+ taskSource = "prompt-hint"
444
+ debugLog("inject", "Resolved task from Active task: hint:", hintNormalized)
445
+ }
446
+ }
447
+ }
448
+ }
449
+
450
+ if (!taskDir) {
451
+ const fallback = ctx._resolveSingleSessionFallback()
452
+ if (fallback?.taskPath) {
453
+ const fallbackDir = ctx.resolveTaskDir(fallback.taskPath)
454
+ if (fallbackDir && existsSync(fallbackDir)) {
455
+ taskDir = fallback.taskPath
456
+ taskSource = fallback.source
457
+ debugLog("inject", "Resolved task via single-session fallback:", taskDir, "source:", taskSource)
458
+ }
459
+ }
460
+ }
375
461
 
376
462
  // Agents requiring task directory
377
463
  if (AGENTS_REQUIRE_TASK.includes(subagentType)) {
@@ -380,8 +466,8 @@ export default async ({ directory, platform: hostPlatform = process.platform })
380
466
  debugLog("inject", "Skipping - no current task")
381
467
  return
382
468
  }
383
- const taskDirFull = join(directory, taskDir)
384
- if (!existsSync(taskDirFull)) {
469
+ const taskDirFull = ctx.resolveTaskDir(taskDir)
470
+ if (!taskDirFull || !existsSync(taskDirFull)) {
385
471
  debugLog("inject", "Skipping - task directory not found")
386
472
  return
387
473
  }
@@ -25,7 +25,7 @@
25
25
 
26
26
  import { existsSync, readFileSync } from "fs"
27
27
  import { join } from "path"
28
- import { TrellisContext, debugLog } from "../lib/trellis-context.js"
28
+ import { TrellisContext, debugLog, isTrellisSubagent } from "../lib/trellis-context.js"
29
29
 
30
30
  // Supports STATUS values with letters, digits, underscores, hyphens
31
31
  // (so "in-review" / "blocked-by-team" work alongside "in_progress").
@@ -108,6 +108,13 @@ export default async ({ directory }) => {
108
108
  // so it persists in conversation history.
109
109
  "chat.message": async (input, output) => {
110
110
  try {
111
+ // Skip Trellis sub-agent turns — the per-turn breadcrumb is for the
112
+ // main session only; sub-agent context comes from the parent's
113
+ // tool.execute.before injection.
114
+ if (isTrellisSubagent(input)) {
115
+ debugLog("workflow-state", "Skipping trellis subagent turn:", input?.agent)
116
+ return
117
+ }
111
118
  if (process.env.TRELLIS_HOOKS === "0" || process.env.TRELLIS_DISABLE_HOOKS === "1") {
112
119
  return
113
120
  }
@@ -6,7 +6,7 @@
6
6
  * Uses OpenCode's chat.message hook directly so the context persists in history.
7
7
  */
8
8
 
9
- import { TrellisContext, contextCollector, debugLog } from "../lib/trellis-context.js"
9
+ import { TrellisContext, contextCollector, debugLog, isTrellisSubagent } from "../lib/trellis-context.js"
10
10
  import {
11
11
  buildSessionContext,
12
12
  hasPersistedInjectedContext,
@@ -43,6 +43,14 @@ export default async ({ directory, client }) => {
43
43
  const agent = input.agent || "unknown"
44
44
  debugLog("session", "chat.message called, sessionID:", sessionID, "agent:", agent)
45
45
 
46
+ // Skip Trellis sub-agent turns — sub-agent context is injected by
47
+ // `inject-subagent-context.js` on the parent's tool.execute.before;
48
+ // re-injecting the main-session SessionStart here would drown that.
49
+ if (isTrellisSubagent(input)) {
50
+ debugLog("session", "Skipping trellis subagent turn:", agent)
51
+ return
52
+ }
53
+
46
54
  if (process.env.TRELLIS_HOOKS === "0" || process.env.TRELLIS_DISABLE_HOOKS === "1") {
47
55
  debugLog("session", "Skipping - TRELLIS_HOOKS disabled")
48
56
  return
@@ -19,10 +19,11 @@ You are already the `trellis-check` sub-agent that the main session dispatched.
19
19
  ## Core Responsibilities
20
20
 
21
21
  1. Inspect the current git diff.
22
- 2. Read and follow the spec and research files listed in the task's `check.jsonl`.
23
- 3. Review all changed code against the task PRD and project specs.
24
- 4. Fix issues directly when they are within scope.
25
- 5. Run the relevant lint, typecheck, and focused tests available for the touched code.
22
+ 2. Read `prd.md`, `design.md` if present, and `implement.md` if present.
23
+ 3. Read and follow the spec and research files listed in the task's `check.jsonl`.
24
+ 4. Review all changed code against the task artifacts and project specs.
25
+ 5. Fix issues directly when they are within scope.
26
+ 6. Run the relevant lint, typecheck, and focused tests available for the touched code.
26
27
 
27
28
  ## Review Priorities
28
29
 
@@ -19,10 +19,11 @@ You are already the `trellis-implement` sub-agent that the main session dispatch
19
19
  ## Core Responsibilities
20
20
 
21
21
  1. Understand the active task requirements.
22
- 2. Read and follow the spec and research files listed in the task's `implement.jsonl`.
23
- 3. Implement the requested change using existing project patterns.
24
- 4. Run the relevant lint, typecheck, and focused tests available for the touched code.
25
- 5. Report files changed and verification results.
22
+ 2. Read `prd.md`, `design.md` if present, and `implement.md` if present.
23
+ 3. Read and follow the spec and research files listed in the task's `implement.jsonl`.
24
+ 4. Implement the requested change using existing project patterns.
25
+ 5. Run the relevant lint, typecheck, and focused tests available for the touched code.
26
+ 6. Report files changed and verification results.
26
27
 
27
28
  ## Forbidden Operations
28
29