@mindfoldhq/trellis 0.6.0-beta.7 → 0.6.0-beta.8

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 (58) hide show
  1. package/dist/configurators/codex.d.ts.map +1 -1
  2. package/dist/configurators/codex.js +5 -3
  3. package/dist/configurators/codex.js.map +1 -1
  4. package/dist/configurators/shared.js +4 -4
  5. package/dist/configurators/shared.js.map +1 -1
  6. package/dist/migrations/manifests/0.6.0-beta.8.json +9 -0
  7. package/dist/templates/claude/agents/trellis-check.md +2 -2
  8. package/dist/templates/claude/agents/trellis-implement.md +8 -7
  9. package/dist/templates/codebuddy/agents/trellis-check.md +2 -2
  10. package/dist/templates/codebuddy/agents/trellis-implement.md +8 -7
  11. package/dist/templates/codex/agents/trellis-check.toml +4 -4
  12. package/dist/templates/codex/agents/trellis-implement.toml +4 -4
  13. package/dist/templates/codex/hooks/session-start.py +183 -119
  14. package/dist/templates/codex/skills/before-dev/SKILL.md +12 -6
  15. package/dist/templates/codex/skills/brainstorm/SKILL.md +113 -51
  16. package/dist/templates/codex/skills/check/SKILL.md +86 -18
  17. package/dist/templates/codex/skills/start/SKILL.md +33 -323
  18. package/dist/templates/common/bundled-skills/trellis-meta/references/customize-local/change-context-loading.md +7 -4
  19. package/dist/templates/common/bundled-skills/trellis-meta/references/customize-local/change-spec-structure.md +1 -1
  20. package/dist/templates/common/bundled-skills/trellis-meta/references/customize-local/change-workflow.md +3 -2
  21. package/dist/templates/common/bundled-skills/trellis-meta/references/local-architecture/context-injection.md +5 -5
  22. package/dist/templates/common/bundled-skills/trellis-meta/references/local-architecture/spec-system.md +1 -1
  23. package/dist/templates/common/bundled-skills/trellis-meta/references/local-architecture/task-system.md +8 -6
  24. package/dist/templates/common/bundled-skills/trellis-meta/references/platform-files/agents.md +5 -4
  25. package/dist/templates/common/commands/continue.md +6 -5
  26. package/dist/templates/common/commands/start.md +7 -6
  27. package/dist/templates/common/skills/before-dev.md +12 -6
  28. package/dist/templates/common/skills/brainstorm.md +56 -42
  29. package/dist/templates/common/skills/check.md +7 -1
  30. package/dist/templates/copilot/hooks/session-start.py +183 -90
  31. package/dist/templates/copilot/prompts/before-dev.prompt.md +12 -6
  32. package/dist/templates/copilot/prompts/brainstorm.prompt.md +146 -84
  33. package/dist/templates/copilot/prompts/check.prompt.md +86 -18
  34. package/dist/templates/copilot/prompts/parallel.prompt.md +16 -8
  35. package/dist/templates/copilot/prompts/start.prompt.md +33 -367
  36. package/dist/templates/cursor/agents/trellis-check.md +2 -2
  37. package/dist/templates/cursor/agents/trellis-implement.md +8 -7
  38. package/dist/templates/droid/droids/trellis-check.md +2 -2
  39. package/dist/templates/droid/droids/trellis-implement.md +8 -7
  40. package/dist/templates/gemini/agents/trellis-implement.md +7 -6
  41. package/dist/templates/kiro/agents/trellis-check.json +1 -1
  42. package/dist/templates/kiro/agents/trellis-implement.json +1 -1
  43. package/dist/templates/opencode/agents/trellis-check.md +2 -2
  44. package/dist/templates/opencode/agents/trellis-implement.md +9 -8
  45. package/dist/templates/opencode/lib/session-utils.js +212 -123
  46. package/dist/templates/opencode/plugins/inject-subagent-context.js +23 -7
  47. package/dist/templates/opencode/plugins/inject-workflow-state.js +1 -4
  48. package/dist/templates/pi/extensions/trellis/index.ts.txt +7 -5
  49. package/dist/templates/qoder/agents/trellis-implement.md +7 -6
  50. package/dist/templates/shared-hooks/inject-subagent-context.py +36 -14
  51. package/dist/templates/shared-hooks/inject-workflow-state.py +18 -42
  52. package/dist/templates/shared-hooks/session-start.py +197 -163
  53. package/dist/templates/trellis/scripts/common/task_context.py +3 -3
  54. package/dist/templates/trellis/scripts/common/task_store.py +39 -7
  55. package/dist/templates/trellis/scripts/common/workflow_phase.py +7 -10
  56. package/dist/templates/trellis/scripts/task.py +3 -3
  57. package/dist/templates/trellis/workflow.md +98 -98
  58. package/package.json +1 -1
@@ -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
 
@@ -1,6 +1,6 @@
1
1
  /* global process */
2
2
  import { existsSync, readFileSync, readdirSync, statSync } from "fs"
3
- import { basename, join } from "path"
3
+ import { join } from "path"
4
4
  import { execFileSync } from "child_process"
5
5
  import { platform } from "os"
6
6
  import { debugLog } from "./trellis-context.js"
@@ -8,9 +8,8 @@ import { debugLog } from "./trellis-context.js"
8
8
  const PYTHON_CMD = platform() === "win32" ? "python" : "python3"
9
9
 
10
10
  const FIRST_REPLY_NOTICE = `<first-reply-notice>
11
- On the first visible assistant reply in this session, begin with exactly one short Chinese sentence:
12
- Trellis SessionStart 已注入:workflow、当前任务状态、开发者身份、git 状态、active tasks、spec 索引已加载。
13
- Then continue directly with the user's request. This notice is one-shot: do not repeat it after the first assistant reply in the same session.
11
+ First visible reply: say once in Chinese that Trellis SessionStart context is loaded, then answer directly.
12
+ This notice is one-shot: do not repeat it after the first assistant reply in the same session.
14
13
  </first-reply-notice>`
15
14
 
16
15
  function hasCuratedJsonlEntry(jsonlPath) {
@@ -38,13 +37,18 @@ function getTaskStatus(ctx, platformInput = null) {
38
37
  const active = ctx.getActiveTask(platformInput)
39
38
  const taskRef = active.taskPath
40
39
  if (!taskRef) {
41
- return `Status: NO ACTIVE TASK\nSource: ${active.source}\nNext: Describe what you want to work on`
40
+ return (
41
+ "Status: NO ACTIVE TASK\n" +
42
+ "Next-Action: Classify the current turn before creating any Trellis task. " +
43
+ "Simple conversation / small task asks only whether this turn should create a Trellis task. " +
44
+ "Complex task asks whether task creation and planning are allowed."
45
+ )
42
46
  }
43
47
 
44
48
  const taskDir = ctx.resolveTaskDir(taskRef)
45
49
 
46
50
  if (active.stale || !taskDir || !existsSync(taskDir)) {
47
- return `Status: STALE POINTER\nTask: ${taskRef}\nSource: ${active.source}\nNext: Task directory not found. Run: python3 ./.trellis/scripts/task.py finish`
51
+ return `Status: STALE POINTER\nTask: ${taskRef}\nNext-Action: Task directory not found. Run: python3 ./.trellis/scripts/task.py finish`
48
52
  }
49
53
 
50
54
  let taskData = {}
@@ -61,39 +65,49 @@ function getTaskStatus(ctx, platformInput = null) {
61
65
  const taskStatus = taskData.status || "unknown"
62
66
 
63
67
  if (taskStatus === "completed") {
64
- const dirName = basename(taskDir)
65
- return `Status: COMPLETED\nTask: ${taskTitle}\nSource: ${active.source}\nNext: Archive with \`python3 ./.trellis/scripts/task.py archive ${dirName}\` or start a new task`
66
- }
67
-
68
- let hasContext = false
69
- for (const jsonlName of ["implement.jsonl", "check.jsonl"]) {
70
- const jsonlPath = join(taskDir, jsonlName)
71
- if (existsSync(jsonlPath) && hasCuratedJsonlEntry(jsonlPath)) {
72
- hasContext = true
73
- break
74
- }
68
+ return `Status: COMPLETED\nTask: ${taskTitle}\nNext-Action: Run /trellis:finish-work. If the working tree is dirty, return to Phase 3.4 first.`
75
69
  }
76
70
 
77
71
  const hasPrd = existsSync(join(taskDir, "prd.md"))
78
-
79
- if (!hasPrd) {
80
- return `Status: NOT READY\nTask: ${taskTitle}\nSource: ${active.source}\nMissing: prd.md not created\nNext: Write PRD (see workflow.md Phase 1.1) then curate implement.jsonl per Phase 1.3`
72
+ const hasDesign = existsSync(join(taskDir, "design.md"))
73
+ const hasImplementPlan = existsSync(join(taskDir, "implement.md"))
74
+ const artifactNames = ["prd.md", "design.md", "implement.md", "implement.jsonl", "check.jsonl"]
75
+ const present = artifactNames.filter(name => existsSync(join(taskDir, name)))
76
+ if (existsSync(join(taskDir, "research"))) present.push("research/")
77
+ const presentLine = present.length > 0 ? present.join(", ") : "(none)"
78
+ const implementJsonl = join(taskDir, "implement.jsonl")
79
+ const checkJsonl = join(taskDir, "check.jsonl")
80
+ const jsonlReady =
81
+ (!existsSync(implementJsonl) || hasCuratedJsonlEntry(implementJsonl)) &&
82
+ (!existsSync(checkJsonl) || hasCuratedJsonlEntry(checkJsonl))
83
+
84
+ if (taskStatus === "planning" && !hasPrd) {
85
+ return `Status: PLANNING\nTask: ${taskTitle}\nPresent: ${presentLine}\nNext-Action: Load trellis-brainstorm and write prd.md. Stay in planning.`
81
86
  }
82
87
 
83
- if (!hasContext) {
84
- return `Status: NOT READY\nTask: ${taskTitle}\nSource: ${active.source}\nMissing: implement.jsonl / check.jsonl missing or empty\nNext: Curate entries per workflow.md Phase 1.3 (spec + research files only), then \`task.py start\``
88
+ if (taskStatus === "planning") {
89
+ const missingComplex = []
90
+ if (!hasDesign) missingComplex.push("design.md")
91
+ if (!hasImplementPlan) missingComplex.push("implement.md")
92
+ const nextBits = []
93
+ if (missingComplex.length > 0) {
94
+ nextBits.push(
95
+ `Lightweight task can request start review with PRD-only; complex task must add ${missingComplex.join(", ")} before start`,
96
+ )
97
+ } else {
98
+ nextBits.push("Planning artifacts are present; ask for review before `task.py start`")
99
+ }
100
+ if (!jsonlReady) {
101
+ nextBits.push("curate `implement.jsonl` and `check.jsonl` before sub-agent mode start")
102
+ }
103
+ return `Status: PLANNING\nTask: ${taskTitle}\nPresent: ${presentLine}\nNext-Action: ${nextBits.join("; ")}. Do not enter implementation until the user confirms start.`
85
104
  }
86
105
 
87
106
  return (
88
- `Status: READY\nTask: ${taskTitle}\n` +
89
- `Source: ${active.source}\n` +
90
- "Next required action: dispatch `trellis-implement` per Phase 2.1. " +
91
- "For agent-capable platforms, the default is to NOT edit code in the main session. " +
92
- "After implementation, dispatch `trellis-check` per Phase 2.2 before reporting completion.\n" +
93
- "User override (per-turn escape hatch): if the user's CURRENT message explicitly tells the " +
94
- "main session to handle it directly (\"你直接改\" / \"别派 sub-agent\" / \"main session 写就行\" / " +
95
- "\"do it inline\" / \"不用 sub-agent\"), honor it for this turn and edit code directly. " +
96
- "Per-turn only; do NOT invent an override the user did not say."
107
+ `Status: ${String(taskStatus).toUpperCase()}\nTask: ${taskTitle}\n` +
108
+ `Present: ${presentLine}\n` +
109
+ "Next-Action: Follow the matching per-turn workflow-state. " +
110
+ "Implementation/check context order is jsonl entries -> `prd.md` -> `design.md if present` -> `implement.md if present`."
97
111
  )
98
112
  }
99
113
 
@@ -201,22 +215,163 @@ function resolveSpecScope(config) {
201
215
  return null
202
216
  }
203
217
 
218
+ function collectSpecIndexPaths(directory, allowedPkgs) {
219
+ const specDir = join(directory, ".trellis", "spec")
220
+ const paths = []
221
+
222
+ const guidesIndex = join(specDir, "guides", "index.md")
223
+ if (existsSync(guidesIndex)) {
224
+ paths.push(".trellis/spec/guides/index.md")
225
+ }
226
+
227
+ if (!existsSync(specDir)) return paths
228
+
229
+ try {
230
+ const subs = readdirSync(specDir).filter(name => {
231
+ if (name.startsWith(".") || name === "guides") return false
232
+ try {
233
+ return statSync(join(specDir, name)).isDirectory()
234
+ } catch {
235
+ return false
236
+ }
237
+ }).sort()
238
+
239
+ for (const sub of subs) {
240
+ const indexFile = join(specDir, sub, "index.md")
241
+ if (existsSync(indexFile)) {
242
+ paths.push(`.trellis/spec/${sub}/index.md`)
243
+ } else {
244
+ if (allowedPkgs !== null && !allowedPkgs.has(sub)) continue
245
+ try {
246
+ const nested = readdirSync(join(specDir, sub)).filter(name => {
247
+ try {
248
+ return statSync(join(specDir, sub, name)).isDirectory()
249
+ } catch {
250
+ return false
251
+ }
252
+ }).sort()
253
+ for (const layer of nested) {
254
+ const nestedIndex = join(specDir, sub, layer, "index.md")
255
+ if (existsSync(nestedIndex)) {
256
+ paths.push(`.trellis/spec/${sub}/${layer}/index.md`)
257
+ }
258
+ }
259
+ } catch {
260
+ // Ignore directory read errors
261
+ }
262
+ }
263
+ }
264
+ } catch {
265
+ // Ignore spec directory read errors
266
+ }
267
+
268
+ return paths
269
+ }
270
+
271
+ function readDeveloper(directory) {
272
+ try {
273
+ const content = readFileSync(join(directory, ".trellis", ".developer"), "utf-8")
274
+ for (const line of content.split(/\r?\n/)) {
275
+ if (line.startsWith("name=")) return line.slice("name=".length).trim()
276
+ }
277
+ } catch {
278
+ // Ignore missing developer file
279
+ }
280
+ return "(not initialized)"
281
+ }
282
+
283
+ function runGit(directory, args) {
284
+ try {
285
+ return execFileSync("git", args, {
286
+ cwd: directory,
287
+ timeout: 3000,
288
+ encoding: "utf-8",
289
+ stdio: ["pipe", "pipe", "pipe"],
290
+ }).trim()
291
+ } catch {
292
+ return ""
293
+ }
294
+ }
295
+
296
+ function buildCompactCurrentState(ctx, platformInput, specIndexPaths) {
297
+ const directory = ctx.directory
298
+ const lines = []
299
+ lines.push(`Developer: ${readDeveloper(directory)}`)
300
+
301
+ const branch = runGit(directory, ["branch", "--show-current"]) || "(detached)"
302
+ const dirtyCount = runGit(directory, ["status", "--porcelain"])
303
+ .split(/\r?\n/)
304
+ .filter(line => line.trim()).length
305
+ lines.push(`Git: branch ${branch}; ${dirtyCount === 0 ? "clean" : `dirty ${dirtyCount} paths`}.`)
306
+
307
+ const active = ctx.getActiveTask(platformInput)
308
+ if (active.taskPath) {
309
+ const taskDir = ctx.resolveTaskDir(active.taskPath)
310
+ let status = "unknown"
311
+ if (taskDir) {
312
+ try {
313
+ const data = JSON.parse(readFileSync(join(taskDir, "task.json"), "utf-8"))
314
+ status = data.status || "unknown"
315
+ } catch {
316
+ // Ignore parse errors
317
+ }
318
+ }
319
+ lines.push(`Current task: ${active.taskPath}; status=${status}.`)
320
+ } else {
321
+ lines.push("Current task: none.")
322
+ }
323
+
324
+ const tasksDir = join(directory, ".trellis", "tasks")
325
+ if (existsSync(tasksDir)) {
326
+ try {
327
+ const activeTasks = readdirSync(tasksDir, { withFileTypes: true })
328
+ .filter(entry => entry.isDirectory() && entry.name !== "archive" && existsSync(join(tasksDir, entry.name, "task.json")))
329
+ lines.push(`Active tasks: ${activeTasks.length} total. Use \`python3 ./.trellis/scripts/task.py list --mine\` only if needed.`)
330
+ } catch {
331
+ // Ignore task list errors
332
+ }
333
+ }
334
+
335
+ const developer = readDeveloper(directory)
336
+ const workspaceDir = join(directory, ".trellis", "workspace", developer)
337
+ if (developer !== "(not initialized)" && existsSync(workspaceDir)) {
338
+ try {
339
+ const journals = readdirSync(workspaceDir)
340
+ .filter(name => /^journal-\d+\.md$/.test(name))
341
+ .sort((a, b) => Number(a.match(/\d+/)?.[0] || 0) - Number(b.match(/\d+/)?.[0] || 0))
342
+ const journal = journals[journals.length - 1]
343
+ if (journal) {
344
+ const journalPath = join(workspaceDir, journal)
345
+ const lineCount = readFileSync(journalPath, "utf-8").split(/\r?\n/).length
346
+ lines.push(`Journal: .trellis/workspace/${developer}/${journal}, ${lineCount} / 2000 lines.`)
347
+ }
348
+ } catch {
349
+ // Ignore journal errors
350
+ }
351
+ }
352
+
353
+ if (specIndexPaths.length > 0) {
354
+ lines.push(`Spec indexes: ${specIndexPaths.length} available.`)
355
+ }
356
+
357
+ return lines.join("\n")
358
+ }
359
+
204
360
  export function buildSessionContext(ctx, platformInput = null) {
205
361
  const directory = ctx.directory
206
- const trellisDir = join(directory, ".trellis")
207
362
  const contextKey = typeof ctx.getContextKey === "function"
208
363
  ? ctx.getContextKey(platformInput)
209
364
  : null
210
365
 
211
366
  const config = loadTrellisConfig(directory, contextKey)
212
367
  const allowedPkgs = resolveSpecScope(config)
368
+ const paths = collectSpecIndexPaths(directory, allowedPkgs)
213
369
 
214
370
  const parts = []
215
371
 
216
- parts.push(`<trellis-context>
217
- You are starting a new session in a Trellis-managed project.
218
- Read and follow all instructions below carefully.
219
- </trellis-context>`)
372
+ parts.push(`<session-context>
373
+ Trellis compact SessionStart context. Use it to orient the session; load details on demand.
374
+ </session-context>`)
220
375
  parts.push(FIRST_REPLY_NOTICE)
221
376
 
222
377
  const legacyWarning = checkLegacySpec(directory, config)
@@ -224,29 +379,18 @@ Read and follow all instructions below carefully.
224
379
  parts.push(`<migration-warning>\n${legacyWarning}\n</migration-warning>`)
225
380
  }
226
381
 
227
- const contextScript = join(trellisDir, "scripts", "get_context.py")
228
- if (existsSync(contextScript)) {
229
- const output = ctx.runScript(contextScript, undefined, contextKey)
230
- if (output) {
231
- parts.push("<current-state>")
232
- parts.push(output)
233
- parts.push("</current-state>")
234
- }
235
- }
382
+ parts.push("<current-state>")
383
+ parts.push(buildCompactCurrentState(ctx, platformInput, paths))
384
+ parts.push("</current-state>")
236
385
 
237
386
  const workflowContent = ctx.readProjectFile(".trellis/workflow.md")
238
387
  if (workflowContent) {
239
388
  const allLines = workflowContent.split("\n")
240
389
  const overviewLines = [
241
- "# Development Workflow Section Index",
242
- "Full guide: .trellis/workflow.md (read on demand)",
390
+ "# Development Workflow - Session Summary",
391
+ "Full guide: .trellis/workflow.md. Step detail: `python3 ./.trellis/scripts/get_context.py --mode phase --step <X.Y>`.",
243
392
  "",
244
- "## Table of Contents",
245
393
  ]
246
- for (const line of allLines) {
247
- if (line.startsWith("## ")) overviewLines.push(line)
248
- }
249
- overviewLines.push("", "---", "")
250
394
 
251
395
  let rangeStart = -1
252
396
  let rangeEnd = allLines.length
@@ -254,89 +398,36 @@ Read and follow all instructions below carefully.
254
398
  const stripped = allLines[i].trim()
255
399
  if (rangeStart === -1 && stripped === "## Phase Index") {
256
400
  rangeStart = i
257
- } else if (rangeStart !== -1 && stripped === "## Workflow State Breadcrumbs") {
401
+ } else if (rangeStart !== -1 && stripped === "## Phase 1: Plan") {
258
402
  rangeEnd = i
259
403
  break
260
404
  }
261
405
  }
262
406
  if (rangeStart !== -1) {
263
- overviewLines.push(...allLines.slice(rangeStart, rangeEnd))
407
+ const strippedStateBlocks = allLines
408
+ .slice(rangeStart, rangeEnd)
409
+ .join("\n")
410
+ .replace(/\[workflow-state:([A-Za-z0-9_-]+)\]\s*\n[\s\S]*?\n\s*\[\/workflow-state:\1\]\n?/g, "")
411
+ .replace(/<!--[\s\S]*?-->/g, "")
412
+ .replace(/^\[(?!\/?workflow-state:)\/?[^\]\n]+\]\s*\n?/gm, "")
413
+ .replace(/\n{3,}/g, "\n\n")
414
+ overviewLines.push(strippedStateBlocks.trimEnd())
264
415
  }
265
416
 
266
- parts.push("<workflow>")
417
+ parts.push("<trellis-workflow>")
267
418
  parts.push(overviewLines.join("\n").trimEnd())
268
- parts.push("</workflow>")
419
+ parts.push("</trellis-workflow>")
269
420
  }
270
421
 
271
422
  parts.push("<guidelines>")
272
423
  parts.push(
273
- "Project spec indexes are listed by path below. Each index contains a " +
274
- "**Pre-Development Checklist** listing the specific guideline files to " +
275
- "read before coding.\n\n" +
276
- "- If you're spawning an implement/check sub-agent, context is injected " +
277
- "automatically via `{task}/implement.jsonl` / `check.jsonl`. You do NOT " +
278
- "need to read these indexes yourself.\n" +
279
- "- For agent-capable platforms, do NOT edit code directly in the main " +
280
- "session; dispatch `trellis-implement` and `trellis-check` so JSONL " +
281
- "context is loaded by the sub-agents.\n"
424
+ "Task context order for implementation/check: jsonl entries -> `prd.md` -> " +
425
+ "`design.md if present` -> `implement.md if present`. Missing optional artifacts " +
426
+ "are skipped for lightweight tasks.\n"
282
427
  )
283
428
 
284
- const specDir = join(directory, ".trellis", "spec")
285
-
286
- const guidesIndex = join(specDir, "guides", "index.md")
287
- if (existsSync(guidesIndex)) {
288
- const content = ctx.readFile(guidesIndex)
289
- if (content) {
290
- parts.push(`## guides (inlined — cross-package thinking guides)\n${content}\n`)
291
- }
292
- }
293
-
294
- const paths = []
295
- if (existsSync(specDir)) {
296
- try {
297
- const subs = readdirSync(specDir).filter(name => {
298
- if (name.startsWith(".")) return false
299
- try {
300
- return statSync(join(specDir, name)).isDirectory()
301
- } catch {
302
- return false
303
- }
304
- }).sort()
305
-
306
- for (const sub of subs) {
307
- if (sub === "guides") continue
308
-
309
- const indexFile = join(specDir, sub, "index.md")
310
- if (existsSync(indexFile)) {
311
- paths.push(`.trellis/spec/${sub}/index.md`)
312
- } else {
313
- if (allowedPkgs !== null && !allowedPkgs.has(sub)) continue
314
- try {
315
- const nested = readdirSync(join(specDir, sub)).filter(name => {
316
- try {
317
- return statSync(join(specDir, sub, name)).isDirectory()
318
- } catch {
319
- return false
320
- }
321
- }).sort()
322
- for (const layer of nested) {
323
- const nestedIndex = join(specDir, sub, layer, "index.md")
324
- if (existsSync(nestedIndex)) {
325
- paths.push(`.trellis/spec/${sub}/${layer}/index.md`)
326
- }
327
- }
328
- } catch {
329
- // Ignore directory read errors
330
- }
331
- }
332
- }
333
- } catch {
334
- // Ignore spec directory read errors
335
- }
336
- }
337
-
338
429
  if (paths.length > 0) {
339
- parts.push("## Available spec indexes (read on demand)")
430
+ parts.push("## Available indexes (read on demand)")
340
431
  for (const p of paths) {
341
432
  parts.push(`- ${p}`)
342
433
  }
@@ -353,9 +444,7 @@ Read and follow all instructions below carefully.
353
444
  parts.push(`<task-status>\n${taskStatus}\n</task-status>`)
354
445
 
355
446
  parts.push(`<ready>
356
- Context loaded. Workflow index, project state, and guidelines are already injected above — do NOT re-read them.
357
- When the user sends the first message, follow <task-status> and the workflow guide.
358
- If a task is READY, execute its Next required action without asking whether to continue.
447
+ Context loaded. Follow <task-status>. Load workflow/spec/task details only when needed.
359
448
  </ready>`)
360
449
 
361
450
  return parts.join("\n\n")
@@ -31,9 +31,14 @@ function getImplementContext(ctx, taskDir) {
31
31
  parts.push(`=== ${taskDir}/prd.md (Requirements) ===\n${prd}`)
32
32
  }
33
33
 
34
- const info = ctx.readProjectFile(join(taskDir, "info.md"))
35
- if (info) {
36
- parts.push(`=== ${taskDir}/info.md (Technical Design) ===\n${info}`)
34
+ const design = ctx.readProjectFile(join(taskDir, "design.md"))
35
+ if (design) {
36
+ parts.push(`=== ${taskDir}/design.md (Technical Design) ===\n${design}`)
37
+ }
38
+
39
+ const implementPlan = ctx.readProjectFile(join(taskDir, "implement.md"))
40
+ if (implementPlan) {
41
+ parts.push(`=== ${taskDir}/implement.md (Execution Plan) ===\n${implementPlan}`)
37
42
  }
38
43
 
39
44
  return parts.join("\n\n")
@@ -56,6 +61,16 @@ function getCheckContext(ctx, taskDir) {
56
61
  parts.push(`=== ${taskDir}/prd.md (Requirements) ===\n${prd}`)
57
62
  }
58
63
 
64
+ const design = ctx.readProjectFile(join(taskDir, "design.md"))
65
+ if (design) {
66
+ parts.push(`=== ${taskDir}/design.md (Technical Design) ===\n${design}`)
67
+ }
68
+
69
+ const implementPlan = ctx.readProjectFile(join(taskDir, "implement.md"))
70
+ if (implementPlan) {
71
+ parts.push(`=== ${taskDir}/implement.md (Execution Plan) ===\n${implementPlan}`)
72
+ }
73
+
59
74
  return parts.join("\n\n")
60
75
  }
61
76
 
@@ -147,8 +162,8 @@ ${originalPrompt}
147
162
  ## Workflow
148
163
 
149
164
  1. **Understand specs** - All dev specs are injected above
150
- 2. **Understand requirements** - Read requirements and technical design
151
- 3. **Implement feature** - Follow specs and design
165
+ 2. **Understand task artifacts** - Read requirements, technical design if present, and execution plan if present
166
+ 3. **Implement feature** - Follow specs and task artifacts
152
167
  4. **Self-check** - Ensure code quality
153
168
 
154
169
  ## Important Constraints
@@ -176,7 +191,7 @@ ${originalPrompt}
176
191
  ## Workflow
177
192
 
178
193
  1. **Review changes** - Run \`git diff --name-only\` to see all changed files
179
- 2. **Verify requirements** - Check each requirement in prd.md is implemented
194
+ 2. **Verify task artifacts** - Check prd.md and, when present, design.md / implement.md
180
195
  3. **Spec sync** - Analyze whether changes introduce new patterns, contracts, or conventions
181
196
  - If new pattern/convention found: read target spec file → update it → update index.md if needed
182
197
  - If infra/cross-layer change: follow the 7-section mandatory template from update-spec.md
@@ -190,7 +205,8 @@ ${originalPrompt}
190
205
  - MUST read the target spec file BEFORE editing (avoid duplicating existing content)
191
206
  - Do NOT update specs for trivial changes (typos, formatting, obvious fixes)
192
207
  - If critical CODE issues found, report them clearly (fix specs, not code)
193
- - Verify all acceptance criteria in prd.md are met` :
208
+ - Verify all acceptance criteria in prd.md are met
209
+ - Verify design.md and implement.md constraints when those files are present` :
194
210
  `# Check Agent Task
195
211
 
196
212
  You are the Check Agent in the Multi-Agent Pipeline.
@@ -89,15 +89,12 @@ function getActiveTask(ctx, platformInput = null) {
89
89
  * "Refer to workflow.md for current step." line
90
90
  * - no_task pseudo-status (id === null) → header omits task info
91
91
  */
92
- function buildBreadcrumb(id, status, templates, source = null) {
92
+ function buildBreadcrumb(id, status, templates) {
93
93
  let body = templates[status]
94
94
  if (body === undefined) {
95
95
  body = "Refer to workflow.md for current step."
96
96
  }
97
97
  let header = id === null ? `Status: ${status}` : `Task: ${id} (${status})`
98
- if (source) {
99
- header = `${header}\nSource: ${source}`
100
- }
101
98
  return `<workflow-state>\n${header}\n${body}\n</workflow-state>`
102
99
  }
103
100
 
@@ -615,7 +615,8 @@ function buildTrellisContext(
615
615
  }
616
616
 
617
617
  const prd = readText(join(taskDir, "prd.md"));
618
- const info = readText(join(taskDir, "info.md"));
618
+ const design = readText(join(taskDir, "design.md"));
619
+ const implementPlan = readText(join(taskDir, "implement.md"));
619
620
  const jsonlName = TRELLIS_AGENT_JSONL[agent] ?? "";
620
621
  const specContext = jsonlName
621
622
  ? readJsonlFiles(projectRoot, taskDir, jsonlName)
@@ -627,7 +628,8 @@ function buildTrellisContext(
627
628
  "",
628
629
  "### prd.md",
629
630
  prd || "(missing)",
630
- info ? "\n### info.md\n" + info : "",
631
+ design ? "\n### design.md\n" + design : "",
632
+ implementPlan ? "\n### implement.md\n" + implementPlan : "",
631
633
  specContext ? "\n### Curated Spec / Research Context\n" + specContext : "",
632
634
  ].join("\n");
633
635
  }
@@ -690,15 +692,15 @@ function buildWorkflowStateBreadcrumb(
690
692
  let header: string;
691
693
  let lookupKey: string;
692
694
  if (!taskDir) {
693
- header = "Status: no_task\nSource: session";
695
+ header = "Status: no_task";
694
696
  lookupKey = "no_task";
695
697
  } else {
696
698
  const info = readActiveTaskStatus(projectRoot, taskDir);
697
699
  if (!info) {
698
- header = "Status: no_task\nSource: session";
700
+ header = "Status: no_task";
699
701
  lookupKey = "no_task";
700
702
  } else {
701
- header = `Task: ${info.taskId} (${info.status})\nSource: session`;
703
+ header = `Task: ${info.taskId} (${info.status})`;
702
704
  lookupKey = info.status;
703
705
  }
704
706
  }
@@ -22,13 +22,14 @@ Before implementing, read:
22
22
  - `.trellis/workflow.md` - Project workflow
23
23
  - `.trellis/spec/` - Development guidelines
24
24
  - Task `prd.md` - Requirements document
25
- - Task `info.md` - Technical design (if exists)
25
+ - Task `design.md` - Technical design (if exists)
26
+ - Task `implement.md` - Execution plan (if exists)
26
27
 
27
28
  ## Core Responsibilities
28
29
 
29
30
  1. **Understand specs** - Read relevant spec files in `.trellis/spec/`
30
- 2. **Understand requirements** - Read prd.md and info.md
31
- 3. **Implement features** - Write code following specs and design
31
+ 2. **Understand task artifacts** - Read prd.md, design.md if present, and implement.md if present
32
+ 3. **Implement features** - Write code following specs and task artifacts
32
33
  4. **Self-check** - Ensure code quality
33
34
  5. **Report results** - Report completion status
34
35
 
@@ -53,15 +54,15 @@ Read relevant specs based on task type:
53
54
 
54
55
  ### 2. Understand Requirements
55
56
 
56
- Read the task's prd.md and info.md:
57
+ Read the task's prd.md, design.md if present, and implement.md if present:
57
58
 
58
59
  - What are the core requirements
59
60
  - Key points of technical design
60
- - Which files to modify/create
61
+ - Implementation order, validation commands, and rollback points
61
62
 
62
63
  ### 3. Implement Features
63
64
 
64
- - Write code following specs and technical design
65
+ - Write code following specs and task artifacts
65
66
  - Follow existing code patterns
66
67
  - Only do what's required, no over-engineering
67
68