@mindfoldhq/trellis 0.6.0-beta.2 → 0.6.0-beta.21

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 (331) hide show
  1. package/README.md +1 -1
  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 +58 -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 +2 -0
  155. package/dist/commands/init.d.ts.map +1 -1
  156. package/dist/commands/init.js +97 -42
  157. package/dist/commands/init.js.map +1 -1
  158. package/dist/commands/mem.d.ts +13 -117
  159. package/dist/commands/mem.d.ts.map +1 -1
  160. package/dist/commands/mem.js +168 -1074
  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 +31 -111
  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 +219 -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/codex.d.ts.map +1 -1
  180. package/dist/configurators/codex.js +5 -3
  181. package/dist/configurators/codex.js.map +1 -1
  182. package/dist/configurators/shared.js +4 -4
  183. package/dist/configurators/shared.js.map +1 -1
  184. package/dist/configurators/workflow.d.ts +8 -0
  185. package/dist/configurators/workflow.d.ts.map +1 -1
  186. package/dist/configurators/workflow.js +3 -2
  187. package/dist/configurators/workflow.js.map +1 -1
  188. package/dist/migrations/manifests/0.5.10.json +9 -0
  189. package/dist/migrations/manifests/0.5.11.json +16 -0
  190. package/dist/migrations/manifests/0.5.12.json +9 -0
  191. package/dist/migrations/manifests/0.5.13.json +9 -0
  192. package/dist/migrations/manifests/0.5.14.json +9 -0
  193. package/dist/migrations/manifests/0.5.15.json +9 -0
  194. package/dist/migrations/manifests/0.5.16.json +9 -0
  195. package/dist/migrations/manifests/0.5.17.json +9 -0
  196. package/dist/migrations/manifests/0.5.18.json +9 -0
  197. package/dist/migrations/manifests/0.6.0-beta.10.json +9 -0
  198. package/dist/migrations/manifests/0.6.0-beta.11.json +9 -0
  199. package/dist/migrations/manifests/0.6.0-beta.12.json +9 -0
  200. package/dist/migrations/manifests/0.6.0-beta.13.json +9 -0
  201. package/dist/migrations/manifests/0.6.0-beta.14.json +9 -0
  202. package/dist/migrations/manifests/0.6.0-beta.15.json +9 -0
  203. package/dist/migrations/manifests/0.6.0-beta.16.json +9 -0
  204. package/dist/migrations/manifests/0.6.0-beta.17.json +9 -0
  205. package/dist/migrations/manifests/0.6.0-beta.18.json +16 -0
  206. package/dist/migrations/manifests/0.6.0-beta.19.json +9 -0
  207. package/dist/migrations/manifests/0.6.0-beta.20.json +9 -0
  208. package/dist/migrations/manifests/0.6.0-beta.21.json +9 -0
  209. package/dist/migrations/manifests/0.6.0-beta.3.json +9 -0
  210. package/dist/migrations/manifests/0.6.0-beta.4.json +9 -0
  211. package/dist/migrations/manifests/0.6.0-beta.5.json +9 -0
  212. package/dist/migrations/manifests/0.6.0-beta.6.json +16 -0
  213. package/dist/migrations/manifests/0.6.0-beta.7.json +9 -0
  214. package/dist/migrations/manifests/0.6.0-beta.8.json +9 -0
  215. package/dist/migrations/manifests/0.6.0-beta.9.json +9 -0
  216. package/dist/templates/claude/agents/trellis-check.md +13 -7
  217. package/dist/templates/claude/agents/trellis-implement.md +8 -7
  218. package/dist/templates/claude/settings.json +4 -4
  219. package/dist/templates/codebuddy/agents/trellis-check.md +13 -7
  220. package/dist/templates/codebuddy/agents/trellis-implement.md +8 -7
  221. package/dist/templates/codebuddy/settings.json +4 -4
  222. package/dist/templates/codex/agents/trellis-check.toml +4 -4
  223. package/dist/templates/codex/agents/trellis-implement.toml +4 -4
  224. package/dist/templates/codex/config.toml +9 -16
  225. package/dist/templates/codex/hooks/session-start.py +205 -119
  226. package/dist/templates/codex/hooks.json +2 -2
  227. package/dist/templates/codex/skills/before-dev/SKILL.md +12 -6
  228. package/dist/templates/codex/skills/brainstorm/SKILL.md +69 -457
  229. package/dist/templates/codex/skills/check/SKILL.md +86 -18
  230. package/dist/templates/codex/skills/start/SKILL.md +33 -323
  231. package/dist/templates/common/bundled-skills/trellis-meta/references/customize-local/change-context-loading.md +7 -4
  232. package/dist/templates/common/bundled-skills/trellis-meta/references/customize-local/change-spec-structure.md +1 -1
  233. package/dist/templates/common/bundled-skills/trellis-meta/references/customize-local/change-workflow.md +3 -2
  234. package/dist/templates/common/bundled-skills/trellis-meta/references/local-architecture/context-injection.md +5 -5
  235. package/dist/templates/common/bundled-skills/trellis-meta/references/local-architecture/spec-system.md +1 -1
  236. package/dist/templates/common/bundled-skills/trellis-meta/references/local-architecture/task-system.md +35 -6
  237. package/dist/templates/common/bundled-skills/trellis-meta/references/platform-files/agents.md +5 -4
  238. package/dist/templates/common/bundled-skills/trellis-spec-bootstarp/SKILL.md +41 -0
  239. package/dist/templates/common/bundled-skills/trellis-spec-bootstarp/references/mcp-setup.md +90 -0
  240. package/dist/templates/common/bundled-skills/trellis-spec-bootstarp/references/repository-analysis.md +59 -0
  241. package/dist/templates/common/bundled-skills/trellis-spec-bootstarp/references/spec-task-planning.md +61 -0
  242. package/dist/templates/common/bundled-skills/trellis-spec-bootstarp/references/spec-writing.md +70 -0
  243. package/dist/templates/common/commands/continue.md +6 -5
  244. package/dist/templates/common/commands/start.md +9 -6
  245. package/dist/templates/common/skills/before-dev.md +12 -6
  246. package/dist/templates/common/skills/brainstorm.md +68 -504
  247. package/dist/templates/common/skills/check.md +7 -1
  248. package/dist/templates/copilot/hooks/session-start.py +219 -101
  249. package/dist/templates/copilot/hooks.json +2 -2
  250. package/dist/templates/copilot/prompts/before-dev.prompt.md +12 -6
  251. package/dist/templates/copilot/prompts/brainstorm.prompt.md +69 -457
  252. package/dist/templates/copilot/prompts/check.prompt.md +86 -18
  253. package/dist/templates/copilot/prompts/parallel.prompt.md +16 -8
  254. package/dist/templates/copilot/prompts/start.prompt.md +33 -367
  255. package/dist/templates/cursor/agents/trellis-check.md +13 -7
  256. package/dist/templates/cursor/agents/trellis-implement.md +8 -7
  257. package/dist/templates/cursor/hooks.json +1 -7
  258. package/dist/templates/droid/droids/trellis-check.md +13 -7
  259. package/dist/templates/droid/droids/trellis-implement.md +8 -7
  260. package/dist/templates/droid/settings.json +4 -4
  261. package/dist/templates/gemini/agents/trellis-check.md +11 -5
  262. package/dist/templates/gemini/agents/trellis-implement.md +7 -6
  263. package/dist/templates/gemini/settings.json +2 -2
  264. package/dist/templates/kiro/agents/trellis-check.json +1 -1
  265. package/dist/templates/kiro/agents/trellis-implement.json +1 -1
  266. package/dist/templates/markdown/spec/guides/code-reuse-thinking-guide.md.txt +127 -9
  267. package/dist/templates/markdown/spec/guides/cross-layer-thinking-guide.md.txt +171 -6
  268. package/dist/templates/markdown/spec/guides/cross-platform-thinking-guide.md.txt +333 -43
  269. package/dist/templates/markdown/spec/guides/index.md.txt +18 -0
  270. package/dist/templates/opencode/agents/trellis-check.md +13 -7
  271. package/dist/templates/opencode/agents/trellis-implement.md +9 -8
  272. package/dist/templates/opencode/lib/session-utils.js +212 -123
  273. package/dist/templates/opencode/lib/trellis-context.js +73 -11
  274. package/dist/templates/opencode/plugins/inject-subagent-context.js +131 -29
  275. package/dist/templates/opencode/plugins/inject-workflow-state.js +9 -5
  276. package/dist/templates/opencode/plugins/session-start.js +9 -1
  277. package/dist/templates/pi/agents/trellis-check.md +5 -4
  278. package/dist/templates/pi/agents/trellis-implement.md +5 -4
  279. package/dist/templates/pi/extensions/trellis/index.ts.txt +1357 -754
  280. package/dist/templates/qoder/agents/trellis-check.md +11 -5
  281. package/dist/templates/qoder/agents/trellis-implement.md +7 -6
  282. package/dist/templates/qoder/settings.json +4 -4
  283. package/dist/templates/shared-hooks/index.d.ts.map +1 -1
  284. package/dist/templates/shared-hooks/index.js +0 -1
  285. package/dist/templates/shared-hooks/index.js.map +1 -1
  286. package/dist/templates/shared-hooks/inject-subagent-context.py +36 -14
  287. package/dist/templates/shared-hooks/inject-workflow-state.py +40 -42
  288. package/dist/templates/shared-hooks/session-start.py +222 -171
  289. package/dist/templates/trellis/config.yaml +38 -0
  290. package/dist/templates/trellis/index.d.ts +1 -0
  291. package/dist/templates/trellis/index.d.ts.map +1 -1
  292. package/dist/templates/trellis/index.js +2 -0
  293. package/dist/templates/trellis/index.js.map +1 -1
  294. package/dist/templates/trellis/scripts/add_session.py +50 -24
  295. package/dist/templates/trellis/scripts/common/config.py +57 -1
  296. package/dist/templates/trellis/scripts/common/safe_commit.py +285 -0
  297. package/dist/templates/trellis/scripts/common/session_context.py +384 -137
  298. package/dist/templates/trellis/scripts/common/task_context.py +3 -3
  299. package/dist/templates/trellis/scripts/common/task_store.py +161 -15
  300. package/dist/templates/trellis/scripts/common/workflow_phase.py +7 -10
  301. package/dist/templates/trellis/scripts/task.py +3 -3
  302. package/dist/templates/trellis/workflow.md +119 -98
  303. package/dist/utils/cwd-guard.d.ts +38 -0
  304. package/dist/utils/cwd-guard.d.ts.map +1 -0
  305. package/dist/utils/cwd-guard.js +62 -0
  306. package/dist/utils/cwd-guard.js.map +1 -0
  307. package/dist/utils/file-writer.d.ts +13 -0
  308. package/dist/utils/file-writer.d.ts.map +1 -1
  309. package/dist/utils/file-writer.js +59 -1
  310. package/dist/utils/file-writer.js.map +1 -1
  311. package/dist/utils/manifest-prune.d.ts +61 -0
  312. package/dist/utils/manifest-prune.d.ts.map +1 -0
  313. package/dist/utils/manifest-prune.js +136 -0
  314. package/dist/utils/manifest-prune.js.map +1 -0
  315. package/dist/utils/task-json.d.ts +9 -42
  316. package/dist/utils/task-json.d.ts.map +1 -1
  317. package/dist/utils/task-json.js +8 -45
  318. package/dist/utils/task-json.js.map +1 -1
  319. package/dist/utils/template-hash.d.ts +32 -6
  320. package/dist/utils/template-hash.d.ts.map +1 -1
  321. package/dist/utils/template-hash.js +53 -31
  322. package/dist/utils/template-hash.js.map +1 -1
  323. package/dist/utils/uninstall-scrubbers.d.ts +1 -0
  324. package/dist/utils/uninstall-scrubbers.d.ts.map +1 -1
  325. package/dist/utils/uninstall-scrubbers.js +21 -0
  326. package/dist/utils/uninstall-scrubbers.js.map +1 -1
  327. package/dist/utils/workflow-resolver.d.ts +86 -0
  328. package/dist/utils/workflow-resolver.d.ts.map +1 -0
  329. package/dist/utils/workflow-resolver.js +265 -0
  330. package/dist/utils/workflow-resolver.js.map +1 -0
  331. package/package.json +9 -8
@@ -26,37 +26,68 @@
26
26
  | `python3` command | ✅ Always available | ⚠️ May need `python` |
27
27
  | `python` command | ⚠️ May be Python 2 | ✅ Usually Python 3 |
28
28
 
29
- **Rule 1**: Always use explicit `python3` in documentation, help text, and error messages.
29
+ **Rule 1**: For user-facing docs, help text, and error messages, either:
30
+
31
+ - state the platform rule explicitly (`python` on Windows, `python3` elsewhere), or
32
+ - render the command through the same platform-aware helper / placeholder the code uses.
30
33
 
31
34
  ```python
32
35
  # BAD - Assumes shebang works
33
36
  print("Usage: ./script.py <args>")
34
37
  print("Run: script.py <args>")
35
38
 
36
- # GOOD - Explicit interpreter
37
- print("Usage: python3 script.py <args>")
38
- print("Run: python3 ./script.py <args>")
39
+ # GOOD - Platform-aware wording
40
+ print("Usage: python on Windows, python3 elsewhere")
41
+ print("Run: {{PYTHON_CMD}} ./.trellis/scripts/task.py <args>")
39
42
  ```
40
43
 
41
- **Rule 2**: When calling Python from TypeScript/Node.js, detect the available command:
44
+ **Rule 2**: When generating config files at init time, use placeholder + platform detection:
42
45
 
43
46
  ```typescript
47
+ // In template file (settings.json):
48
+ { "command": "{{PYTHON_CMD}} .claude/hooks/script.py" }
49
+
50
+ // In configurator:
44
51
  function getPythonCommand(): string {
52
+ return process.platform === "win32" ? "python" : "python3";
53
+ }
54
+
55
+ function replacePlaceholders(content: string): string {
56
+ return content.replace(/\{\{PYTHON_CMD\}\}/g, getPythonCommand());
57
+ }
58
+ ```
59
+
60
+ **Rule 3**: When calling Python at runtime from JavaScript, detect platform dynamically:
61
+
62
+ ```javascript
63
+ import { platform } from "os"
64
+
65
+ const PYTHON_CMD = platform() === "win32" ? "python" : "python3"
66
+ execSync(`${PYTHON_CMD} "${scriptPath}"`, { ... })
67
+ ```
68
+
69
+ **Rule 4**: If you need to verify Python is actually installed (not just choose
70
+ the command), probe the same platform-selected alias you will later render or
71
+ execute:
72
+
73
+ ```typescript
74
+ function getPythonCommand(platform = process.platform): string {
75
+ return platform === "win32" ? "python" : "python3";
76
+ }
77
+
78
+ function warnIfPythonTooOld(): void {
79
+ const cmd = getPythonCommand();
45
80
  try {
46
- execSync("python3 --version", { stdio: "pipe" });
47
- return "python3";
81
+ execSync(`${cmd} --version`, { stdio: "pipe" });
48
82
  } catch {
49
- try {
50
- execSync("python --version", { stdio: "pipe" });
51
- return "python";
52
- } catch {
53
- return "python3"; // Default, will fail with clear error
54
- }
83
+ // Missing Python is a separate error path; don't silently swap aliases.
55
84
  }
56
85
  }
57
86
  ```
58
87
 
59
- **Rule 3**: When calling Python from Python, use `sys.executable`:
88
+ **Rule 5**: Don't assume the Python version the AI CLI uses matches your shell's `python3`. The user's terminal may resolve `python3` → homebrew 3.11, but AI CLI hosts (including enterprise-forked Claude Code / Cursor distributions) spawn hook subprocesses with a minimal PATH that resolves `python3` → `/usr/bin/python3` → macOS system 3.9. Distributed templates must either target the lowest plausible version or use `from __future__ import annotations` for PEP 604 syntax. See `cli/backend/script-conventions.md` → **CRITICAL: PEP 604 Annotations Require `from __future__ import annotations`** for the hard rule and audit check.
89
+
90
+ **Rule 6**: When calling Python from Python, use `sys.executable`:
60
91
 
61
92
  ```python
62
93
  import sys
@@ -69,30 +100,6 @@ subprocess.run(["python3", "other_script.py"])
69
100
  subprocess.run([sys.executable, "other_script.py"])
70
101
  ```
71
102
 
72
- **Rule 4**: Don't assume the Python version your AI CLI uses matches your shell's `python3`. Your terminal may resolve `python3` → 3.11 (via homebrew/pyenv), but AI CLI hosts often spawn hook subprocesses with a minimal PATH that resolves `python3` → the system Python (3.9 on macOS). Any `.py` file run as an AI-CLI hook must be written for the lowest plausible Python version.
73
-
74
- Concrete failure: PEP 604 union syntax (`str | None`) requires Python 3.10+. If your hook file uses it, start with `from __future__ import annotations` so annotations become lazy strings and work on Python 3.7+:
75
-
76
- ```python
77
- #!/usr/bin/env python3
78
- """My hook."""
79
- from __future__ import annotations # REQUIRED for PEP 604 annotations
80
-
81
- def handler(x: str | None) -> dict | None: # OK — lazy annotation
82
- ...
83
- ```
84
-
85
- ```python
86
- # BAD — crashes on Python < 3.10:
87
- # TypeError: unsupported operand type(s) for |: 'type' and 'NoneType'
88
- def handler(x: str | None) -> dict | None:
89
- ...
90
- ```
91
-
92
- Note: `from __future__ import annotations` only covers **annotations**. Runtime expressions like `isinstance(x, int | str)` still require Python 3.10+. Avoid them in hook scripts.
93
-
94
- Applies to anything the AI CLI executes as a hook: `match/case` statements (3.10+), `tomllib` (3.11+), `ExceptionGroup` / `except*` (3.11+) — all crash on older Python regardless of `__future__`.
95
-
96
103
  ### 2. Path Handling
97
104
 
98
105
  | Assumption | macOS/Linux | Windows |
@@ -101,7 +108,7 @@ Applies to anything the AI CLI executes as a hook: `match/case` statements (3.10
101
108
  | `\` separator | ❌ Escape char | ✅ Native |
102
109
  | `pathlib.Path` | ✅ Works | ✅ Works |
103
110
 
104
- **Rule**: Use `pathlib.Path` for all path operations.
111
+ **Rule (Python)**: Use `pathlib.Path` for all path operations.
105
112
 
106
113
  ```python
107
114
  # BAD - String concatenation
@@ -112,6 +119,51 @@ from pathlib import Path
112
119
  path = Path(base) / filename
113
120
  ```
114
121
 
122
+ #### Logical key vs filesystem path (TypeScript)
123
+
124
+ A path string has two distinct roles. **Treat them differently.**
125
+
126
+ | Role | OS-native (`\` on Windows) | Always POSIX (`/`) |
127
+ |------|---------------------------|--------------------|
128
+ | `fs.readFileSync(p)` / `path.join(cwd, x)` for fs call | ✅ Required | ❌ May fail on Windows |
129
+ | `Map<relPath, content>` key, JSON field, hash dictionary key, anything persisted across OS | ❌ Cross-OS mismatch | ✅ Required |
130
+
131
+ **Rule**: Anywhere a path string crosses OS or persists (Map keys consumed by another OS, JSON fields, hash dictionary keys), normalize to POSIX. Anywhere it goes straight to `fs.*`, leave OS-native.
132
+
133
+ **Single source of truth**: `packages/cli/src/utils/posix.ts` exports `toPosix(p)`. Don't sprinkle `replaceAll('\\', '/')` at every `path.join` site — apply `toPosix` **once at the boundary**: collector exit (Map key entering hash dictionary) or write-time (`saveHashes` before `JSON.stringify`).
134
+
135
+ ```typescript
136
+ // BAD - logical key carries OS-native separator
137
+ function collectTemplates(): Map<string, string> {
138
+ const files = new Map<string, string>();
139
+ for (const entry of walk(dir)) {
140
+ files.set(path.join(".opencode", entry), readFile(entry)); // \ on Windows
141
+ }
142
+ return files;
143
+ }
144
+
145
+ // GOOD - normalize at the boundary
146
+ import { toPosix } from "../utils/posix.js";
147
+
148
+ function collectTemplates(): Map<string, string> {
149
+ const files = new Map<string, string>();
150
+ for (const entry of walk(dir)) {
151
+ files.set(toPosix(path.join(".opencode", entry)), readFile(entry));
152
+ }
153
+ return files;
154
+ }
155
+
156
+ // ALSO ACCEPTABLE - write-side defense (for storage helpers like saveHashes)
157
+ function saveHashes(cwd: string, hashes: Record<string, string>): void {
158
+ const normalized = Object.fromEntries(
159
+ Object.entries(hashes).map(([k, v]) => [toPosix(k), v])
160
+ );
161
+ fs.writeFileSync(getHashesPath(cwd), JSON.stringify(normalized, null, 2));
162
+ }
163
+ ```
164
+
165
+ **Common offender**: `path.relative(cwd, fullPath)` produces `\` on Windows. If you then use that string as a hash dictionary lookup key (`hashes[relPath]`), `toPosix` it first, or the lookup misses on Windows.
166
+
115
167
  ### 3. Line Endings
116
168
 
117
169
  | Format | macOS/Linux | Windows | Git |
@@ -119,7 +171,7 @@ path = Path(base) / filename
119
171
  | `\n` (LF) | ✅ Native | ⚠️ Some tools | ✅ Normalized |
120
172
  | `\r\n` (CRLF) | ⚠️ Extra char | ✅ Native | Converted |
121
173
 
122
- **Rule**: Use `.gitattributes` to enforce consistent line endings.
174
+ **Rule 1**: Use `.gitattributes` to enforce consistent line endings.
123
175
 
124
176
  ```gitattributes
125
177
  * text=auto eol=lf
@@ -127,6 +179,23 @@ path = Path(base) / filename
127
179
  *.py text eol=lf
128
180
  ```
129
181
 
182
+ **Rule 2**: When hashing or comparing **content** across platforms, normalize line endings before computing the hash. `.gitattributes` only governs git checkout — files written by users, scripts, or `core.autocrlf=true` may still arrive as CRLF, and `sha256(LF)` ≠ `sha256(CRLF)` for otherwise-identical content.
183
+
184
+ ```typescript
185
+ // BAD - Windows users with autocrlf=true get a different hash
186
+ export function computeHash(content: string): string {
187
+ return createHash("sha256").update(content, "utf-8").digest("hex");
188
+ }
189
+
190
+ // GOOD - normalize before hashing so logical content hashes identically
191
+ export function computeHash(content: string): string {
192
+ const normalized = content.replace(/\r\n/g, "\n");
193
+ return createHash("sha256").update(normalized, "utf-8").digest("hex");
194
+ }
195
+ ```
196
+
197
+ Apply this rule wherever the hash crosses OS boundaries (template hash dictionary, content fingerprints stored in JSON, integrity checks against a remote registry).
198
+
130
199
  ### 4. Environment Variables
131
200
 
132
201
  | Variable | macOS/Linux | Windows |
@@ -135,7 +204,7 @@ path = Path(base) / filename
135
204
  | `PATH` separator | `:` | `;` |
136
205
  | Case sensitivity | ✅ Case-sensitive | ❌ Case-insensitive |
137
206
 
138
- **Rule**: Use `pathlib.Path.home()` instead of environment variables.
207
+ **Rule 1**: Use `pathlib.Path.home()` instead of environment variables.
139
208
 
140
209
  ```python
141
210
  # BAD
@@ -145,6 +214,31 @@ home = os.environ.get("HOME")
145
214
  home = Path.home()
146
215
  ```
147
216
 
217
+ **Rule 2**: When injecting environment variables into shell commands, generate
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.
221
+
222
+ ```javascript
223
+ // BAD - breaks when the host shell is PowerShell
224
+ command = `export TRELLIS_CONTEXT_ID=${shellQuote(contextKey)}; ${command}`;
225
+
226
+ // GOOD - shell-dialect-aware command prefix
227
+ const prefix = process.platform === "win32" && !isWindowsPosixShell(process.env)
228
+ ? `$env:TRELLIS_CONTEXT_ID = ${powershellQuote(contextKey)}; `
229
+ : `export TRELLIS_CONTEXT_ID=${shellQuote(contextKey)}; `;
230
+ command = `${prefix}${command}`;
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
+
238
+ Also make duplicate-injection detection shell-aware. A guard that only matches
239
+ `export VAR=` will miss PowerShell's `$env:VAR = ...` form and can wrap an
240
+ already-correct command a second time.
241
+
148
242
  ### 5. Command Availability
149
243
 
150
244
  | Command | macOS/Linux | Windows |
@@ -173,6 +267,25 @@ def tail_follow(file_path: Path) -> None:
173
267
  time.sleep(0.1)
174
268
  ```
175
269
 
270
+ ### Optional Advisory Checks in Agent Sandboxes
271
+
272
+ AI CLI subprocesses may run with outbound network disabled even when the user's
273
+ normal terminal has network access. Prefer local CLI probes over optional
274
+ network probes when the local CLI already exposes the needed information.
275
+
276
+ **Rule 1**: Do not let a failed optional advisory check consume a once-per-session
277
+ marker. Write the marker only after the script resolves a usable value and can
278
+ make the intended decision. Otherwise a transient sandbox/network failure hides
279
+ the hint for the rest of the session.
280
+
281
+ **Rule 2**: If a local command can provide the needed value, try it with a short
282
+ timeout and captured output. For example, `trellis --version` already runs the
283
+ CLI's version comparison logic and can support an actionable update prompt
284
+ without duplicating npm registry parsing.
285
+
286
+ **Rule 3**: Keep advisory checks silent on failure. The user-facing context output
287
+ must not fail or become noisy because an advisory check could not complete.
288
+
176
289
  ### 6. File Encoding
177
290
 
178
291
  | Default Encoding | macOS/Linux | Windows |
@@ -183,6 +296,9 @@ def tail_follow(file_path: Path) -> None:
183
296
 
184
297
  **Rule**: Always explicitly specify `encoding="utf-8"` and use `errors="replace"`.
185
298
 
299
+ > **Checklist**: When writing scripts that print non-ASCII, did you configure stdout encoding?
300
+ > See `backend/script-conventions.md` for the specific pattern.
301
+
186
302
  ```python
187
303
  # BAD - Relies on system default
188
304
  with open(file, "r") as f:
@@ -223,6 +339,12 @@ result = subprocess.run(
223
339
 
224
340
  When making platform-related changes, check **all these locations**:
225
341
 
342
+ ### Commands / Skills Sync
343
+ - [ ] New command/skill added to ALL platforms (claude, cursor, iflow, codex, and any new platform)
344
+ - [ ] Each platform's test file updated with new entry in `EXPECTED_COMMAND_NAMES` / `EXPECTED_SKILL_NAMES`
345
+ - [ ] Platform-integration spec's required command table updated if adding a new required command
346
+ - [ ] Command format matches platform convention (see `platform-integration.md` → Command Format by Platform)
347
+
226
348
  ### Documentation & Help Text
227
349
  - [ ] Docstrings at top of Python files
228
350
  - [ ] `--help` output / argparse descriptions
@@ -239,7 +361,7 @@ When making platform-related changes, check **all these locations**:
239
361
  ```bash
240
362
  # Find all places that might need updating
241
363
  grep -r "python [a-z]" --include="*.py" --include="*.md"
242
- grep -r "\./" --include="*.py" --include="*.md" | grep -v python3
364
+ grep -r "{{PYTHON_CMD}}\\|python3\\|python " --include="*.py" --include="*.md"
243
365
  ```
244
366
 
245
367
  ---
@@ -248,10 +370,15 @@ grep -r "\./" --include="*.py" --include="*.md" | grep -v python3
248
370
 
249
371
  Before committing cross-platform code:
250
372
 
251
- - [ ] All Python invocations use `python3` explicitly (docs) or `sys.executable` (code)
373
+ - [ ] User-facing Python invocations are platform-aware (`python` on Windows, `python3` elsewhere) or use `{{PYTHON_CMD}}`
374
+ - [ ] Python subprocesses from Python use `sys.executable`
252
375
  - [ ] All paths use `pathlib.Path`
253
376
  - [ ] No hardcoded path separators (`/` or `\`)
377
+ - [ ] Path strings used as logical/persisted keys (Map keys, JSON fields, hash dictionary keys) are normalized via `toPosix()`; `fs.*` calls keep OS-native paths
378
+ - [ ] Content hashes computed across OSes normalize line endings (`\r\n` → `\n`) before hashing
379
+ - [ ] Cross-OS JSON with potential legacy pollution carries a `__version` sentinel and the loader discards unknown/legacy versions
254
380
  - [ ] No platform-specific commands without fallbacks (e.g., `tail -f`)
381
+ - [ ] Optional advisory checks do not burn once-per-session markers on failure
255
382
  - [ ] All file I/O specifies `encoding="utf-8"` and `errors="replace"`
256
383
  - [ ] All subprocess calls specify `encoding="utf-8"` and `errors="replace"`
257
384
  - [ ] Git commands use `-c i18n.logOutputEncoding=UTF-8`
@@ -283,6 +410,101 @@ output = {
283
410
 
284
411
  ---
285
412
 
413
+ ## Cross-Platform Persisted JSON: Schema Migration Sentinel
414
+
415
+ When a JSON file may be read/written across OSes (committed to git, synced via cloud, copied between machines) **and an older format may already exist on user disks with cross-platform pollution** (Windows-style keys, CRLF-derived hashes, locale-encoded strings), add a `__version` sentinel and let the loader discard old formats so the writer regenerates clean data.
416
+
417
+ **Why not migrate-in-place?** Path-key migration (`\\` → `/`) plus hash-input migration (CRLF → LF re-hash) plus encoding fixes are correlated — trying to translate the old payload risks producing wrong values. Discarding and regenerating is **safe**: the data is recomputable from disk, and `loadX` returning `{}` triggers the existing init/update path to rebuild canonical entries.
418
+
419
+ ```typescript
420
+ const SCHEMA_VERSION = 2;
421
+ type StoredV2 = { __version: number; hashes: Record<string, string> };
422
+
423
+ export function loadHashes(cwd: string): Record<string, string> {
424
+ const file = getHashesPath(cwd);
425
+ if (!fs.existsSync(file)) return {};
426
+
427
+ try {
428
+ const parsed = JSON.parse(fs.readFileSync(file, "utf-8")) as unknown;
429
+
430
+ // Reject legacy flat format (no __version) and unknown versions.
431
+ // The next saveHashes / initializeHashes will write a fresh v2 file.
432
+ if (
433
+ !parsed ||
434
+ typeof parsed !== "object" ||
435
+ (parsed as StoredV2).__version !== SCHEMA_VERSION ||
436
+ typeof (parsed as StoredV2).hashes !== "object"
437
+ ) {
438
+ return {};
439
+ }
440
+ return (parsed as StoredV2).hashes;
441
+ } catch {
442
+ return {};
443
+ }
444
+ }
445
+
446
+ export function saveHashes(cwd: string, hashes: Record<string, string>): void {
447
+ const payload: StoredV2 = { __version: SCHEMA_VERSION, hashes };
448
+ fs.writeFileSync(getHashesPath(cwd), JSON.stringify(payload, null, 2));
449
+ }
450
+ ```
451
+
452
+ **When to apply**:
453
+ - Hash dictionaries / content fingerprints (e.g., `.template-hashes.json`)
454
+ - Cache files where stale entries are recomputable from authoritative source
455
+ - Any cross-OS persisted file where format change correlates with cross-platform fixes
456
+
457
+ **When NOT to apply** — if losing the data hurts the user (task state, drafts, settings the user typed). Use real migration there. Sentinel + discard is only safe when data is recomputable.
458
+
459
+ **Reference**: `packages/cli/src/utils/template-hash.ts` v2 envelope.
460
+
461
+ ---
462
+
463
+ ## JSON/External Data Defensive Checks
464
+
465
+ When parsing JSON or external data, TypeScript types are **compile-time only**. Runtime data may not match.
466
+
467
+ **Rule**: Always add defensive checks for required fields before using them.
468
+
469
+ ```typescript
470
+ // BAD - Trusts TypeScript type definition
471
+ interface MigrationItem {
472
+ from: string; // TypeScript says required
473
+ to?: string;
474
+ }
475
+
476
+ function process(item: MigrationItem) {
477
+ const path = item.from; // Runtime: could be undefined!
478
+ }
479
+
480
+ // GOOD - Defensive check before use
481
+ function process(item: MigrationItem) {
482
+ if (!item.from) return; // Skip invalid data
483
+ const path = item.from; // Now guaranteed
484
+ }
485
+ ```
486
+
487
+ **When to apply**:
488
+ - Parsing JSON files (manifests, configs)
489
+ - API responses
490
+ - User input
491
+ - Any data from external sources
492
+
493
+ **Pattern**: Check existence → then use
494
+
495
+ ```typescript
496
+ // Filter pattern - skip invalid items
497
+ const validItems = items.filter(item => item.from && item.to);
498
+
499
+ // Early return pattern - bail on invalid
500
+ if (!data.requiredField) {
501
+ console.warn("Missing required field");
502
+ return defaultValue;
503
+ }
504
+ ```
505
+
506
+ ---
507
+
286
508
  ## Common Mistakes
287
509
 
288
510
  ### 1. "It works on my Mac"
@@ -318,6 +540,9 @@ python3 script.py # Works!
318
540
  # User's Windows (Python from python.org)
319
541
  python3 script.py # 'python3' is not recognized
320
542
  python script.py # Works!
543
+
544
+ # Trellis docs/config should say the rule, not guess one alias everywhere
545
+ {{PYTHON_CMD}} script.py
321
546
  ```
322
547
 
323
548
  ### 5. "UTF-8 is the default everywhere"
@@ -328,6 +553,9 @@ subprocess.run(cmd, capture_output=True, text=True) # Works!
328
553
 
329
554
  # User's Windows (GBK/CP1252 default)
330
555
  subprocess.run(cmd, capture_output=True, text=True) # Garbled Chinese/Unicode
556
+ ```
557
+
558
+ > **Note**: stdout encoding is also affected. See `backend/script-conventions.md` for the fix.
331
559
 
332
560
  ---
333
561
 
@@ -341,3 +569,65 @@ subprocess.run(cmd, capture_output=True, text=True) # Garbled Chinese/Unicode
341
569
  ---
342
570
 
343
571
  **Core Principle**: If it's not explicit, it's an assumption. And assumptions break.
572
+
573
+ ---
574
+
575
+ ## Release Checklist: Versioned Files
576
+
577
+ When releasing a new version, ensure **all versioned files** are created/updated:
578
+
579
+ - [ ] `src/migrations/manifests/{version}.json` - Migration manifest exists
580
+ - [ ] Manifest has correct version, description, changelog
581
+ - [ ] `pnpm build` copies manifests to `dist/`
582
+ - [ ] Test upgrade path from older versions (not just adjacent)
583
+
584
+ **Why this matters**: Missing manifests cause "path undefined" errors when users upgrade from older versions.
585
+
586
+ ```bash
587
+ # Verify all expected manifests exist
588
+ ls src/migrations/manifests/
589
+
590
+ # Test upgrade path
591
+ node -e "
592
+ const { getMigrationsForVersion } = require('./dist/migrations/index.js');
593
+ console.log('From 0.2.12:', getMigrationsForVersion('0.2.12', 'CURRENT').length);
594
+ "
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)
@@ -27,21 +27,25 @@ You are already the `trellis-check` sub-agent that the main session dispatched.
27
27
 
28
28
  Look for the `<!-- trellis-hook-injected -->` marker in your input above.
29
29
 
30
- - **If the marker is present**: prd / spec / research files have already been auto-loaded for you above. Proceed with the check work directly.
31
- - **If the marker is absent**: hook injection didn't fire (Windows + Claude Code, `--continue` resume, fork distribution, hooks disabled, etc.). Find the active task path from your dispatch prompt's first line `Active task: <path>` (or run `python3 ./.trellis/scripts/task.py current --source` as a fallback), then Read `<task-path>/prd.md` and the spec files listed in `<task-path>/check.jsonl` yourself before doing the work.
30
+ - **If the marker is present**: task artifacts, spec, and research files have already been auto-loaded for you above. Proceed with the check work directly.
31
+ - **If the marker is absent**: hook injection didn't fire (Windows + Claude Code, `--continue` resume, fork distribution, hooks disabled, etc.). Find the active task path from your dispatch prompt's first line `Active task: <path>` (or run `python3 ./.trellis/scripts/task.py current --source` as a fallback), then Read `<task-path>/check.jsonl`, each listed file, `<task-path>/prd.md`, `<task-path>/design.md` if present, and `<task-path>/implement.md` if present before doing the work.
32
32
 
33
33
  ## Context
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
@@ -27,8 +27,8 @@ You are already the `trellis-implement` sub-agent that the main session dispatch
27
27
 
28
28
  Look for the `<!-- trellis-hook-injected -->` marker in your input above.
29
29
 
30
- - **If the marker is present**: prd / spec / research files have already been auto-loaded for you above. Proceed with the implementation work directly.
31
- - **If the marker is absent**: hook injection didn't fire (Windows + Claude Code, `--continue` resume, fork distribution, hooks disabled, etc.). Find the active task path from your dispatch prompt's first line `Active task: <path>` (or run `python3 ./.trellis/scripts/task.py current --source` as a fallback), then Read `<task-path>/prd.md`, `<task-path>/info.md` (if it exists), and the spec files listed in `<task-path>/implement.jsonl` yourself before doing the work.
30
+ - **If the marker is present**: task artifacts, spec, and research files have already been auto-loaded for you above. Proceed with the implementation work directly.
31
+ - **If the marker is absent**: hook injection didn't fire (Windows + Claude Code, `--continue` resume, fork distribution, hooks disabled, etc.). Find the active task path from your dispatch prompt's first line `Active task: <path>` (or run `python3 ./.trellis/scripts/task.py current --source` as a fallback), then Read `<task-path>/implement.jsonl`, each listed file, `<task-path>/prd.md`, `<task-path>/design.md` if present, and `<task-path>/implement.md` if present before doing the work.
32
32
 
33
33
  ## Context
34
34
 
@@ -36,13 +36,14 @@ Before implementing, read:
36
36
  - `.trellis/workflow.md` - Project workflow
37
37
  - `.trellis/spec/` - Development guidelines
38
38
  - Task `prd.md` - Requirements document
39
- - Task `info.md` - Technical design (if exists)
39
+ - Task `design.md` - Technical design (if exists)
40
+ - Task `implement.md` - Execution plan (if exists)
40
41
 
41
42
  ## Core Responsibilities
42
43
 
43
44
  1. **Understand specs** - Read relevant spec files in `.trellis/spec/`
44
- 2. **Understand requirements** - Read prd.md and info.md
45
- 3. **Implement features** - Write code following specs and design
45
+ 2. **Understand task artifacts** - Read prd.md, design.md if present, and implement.md if present
46
+ 3. **Implement features** - Write code following specs and task artifacts
46
47
  4. **Self-check** - Ensure code quality
47
48
  5. **Report results** - Report completion status
48
49
 
@@ -68,15 +69,15 @@ Read relevant specs based on task type:
68
69
 
69
70
  ### 2. Understand Requirements
70
71
 
71
- Read the task's prd.md and info.md:
72
+ Read the task's prd.md, design.md if present, and implement.md if present:
72
73
 
73
74
  - What are the core requirements
74
75
  - Key points of technical design
75
- - Which files to modify/create
76
+ - Implementation order, validation commands, and rollback points
76
77
 
77
78
  ### 3. Implement Features
78
79
 
79
- - Write code following specs and technical design
80
+ - Write code following specs and task artifacts
80
81
  - Follow existing code patterns
81
82
  - Only do what's required, no over-engineering
82
83