@mindfoldhq/trellis 0.5.0-beta.14 → 0.5.0-beta.16

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 (127) hide show
  1. package/README.md +5 -5
  2. package/dist/cli/index.js +1 -0
  3. package/dist/cli/index.js.map +1 -1
  4. package/dist/commands/init.d.ts +1 -0
  5. package/dist/commands/init.d.ts.map +1 -1
  6. package/dist/commands/init.js +24 -20
  7. package/dist/commands/init.js.map +1 -1
  8. package/dist/commands/update.d.ts.map +1 -1
  9. package/dist/commands/update.js +44 -13
  10. package/dist/commands/update.js.map +1 -1
  11. package/dist/configurators/claude.js +1 -1
  12. package/dist/configurators/claude.js.map +1 -1
  13. package/dist/configurators/codebuddy.js +1 -1
  14. package/dist/configurators/codebuddy.js.map +1 -1
  15. package/dist/configurators/codex.d.ts.map +1 -1
  16. package/dist/configurators/codex.js +3 -6
  17. package/dist/configurators/codex.js.map +1 -1
  18. package/dist/configurators/copilot.d.ts.map +1 -1
  19. package/dist/configurators/copilot.js +4 -11
  20. package/dist/configurators/copilot.js.map +1 -1
  21. package/dist/configurators/cursor.js +1 -1
  22. package/dist/configurators/cursor.js.map +1 -1
  23. package/dist/configurators/droid.js +1 -1
  24. package/dist/configurators/droid.js.map +1 -1
  25. package/dist/configurators/gemini.d.ts.map +1 -1
  26. package/dist/configurators/gemini.js +1 -3
  27. package/dist/configurators/gemini.js.map +1 -1
  28. package/dist/configurators/index.d.ts.map +1 -1
  29. package/dist/configurators/index.js +24 -38
  30. package/dist/configurators/index.js.map +1 -1
  31. package/dist/configurators/kiro.js +1 -1
  32. package/dist/configurators/kiro.js.map +1 -1
  33. package/dist/configurators/opencode.d.ts.map +1 -1
  34. package/dist/configurators/opencode.js +4 -1
  35. package/dist/configurators/opencode.js.map +1 -1
  36. package/dist/configurators/pi.d.ts +3 -0
  37. package/dist/configurators/pi.d.ts.map +1 -0
  38. package/dist/configurators/pi.js +39 -0
  39. package/dist/configurators/pi.js.map +1 -0
  40. package/dist/configurators/qoder.d.ts.map +1 -1
  41. package/dist/configurators/qoder.js +1 -3
  42. package/dist/configurators/qoder.js.map +1 -1
  43. package/dist/configurators/shared.d.ts +2 -4
  44. package/dist/configurators/shared.d.ts.map +1 -1
  45. package/dist/configurators/shared.js +6 -9
  46. package/dist/configurators/shared.js.map +1 -1
  47. package/dist/migrations/manifests/0.5.0-beta.15.json +116 -0
  48. package/dist/migrations/manifests/0.5.0-beta.16.json +9 -0
  49. package/dist/templates/claude/agents/trellis-research.md +1 -1
  50. package/dist/templates/claude/settings.json +0 -4
  51. package/dist/templates/codebuddy/agents/trellis-research.md +1 -1
  52. package/dist/templates/codex/agents/trellis-check.toml +0 -16
  53. package/dist/templates/codex/agents/trellis-implement.toml +0 -16
  54. package/dist/templates/codex/agents/trellis-research.toml +3 -2
  55. package/dist/templates/codex/hooks/session-start.py +51 -21
  56. package/dist/templates/codex/skills/start/SKILL.md +1 -1
  57. package/dist/templates/copilot/hooks/session-start.py +51 -21
  58. package/dist/templates/copilot/prompts/start.prompt.md +1 -1
  59. package/dist/templates/cursor/agents/trellis-check.md +1 -1
  60. package/dist/templates/cursor/agents/trellis-implement.md +1 -1
  61. package/dist/templates/cursor/agents/trellis-research.md +2 -2
  62. package/dist/templates/cursor/hooks.json +7 -1
  63. package/dist/templates/droid/droids/trellis-research.md +1 -1
  64. package/dist/templates/extract.d.ts +6 -0
  65. package/dist/templates/extract.d.ts.map +1 -1
  66. package/dist/templates/extract.js +14 -0
  67. package/dist/templates/extract.js.map +1 -1
  68. package/dist/templates/gemini/agents/trellis-research.md +1 -1
  69. package/dist/templates/kiro/agents/trellis-research.json +1 -1
  70. package/dist/templates/markdown/agents.md +11 -12
  71. package/dist/templates/markdown/gitignore.txt +3 -0
  72. package/dist/templates/opencode/agents/trellis-check.md +1 -1
  73. package/dist/templates/opencode/agents/trellis-implement.md +1 -1
  74. package/dist/templates/opencode/agents/trellis-research.md +2 -2
  75. package/dist/templates/opencode/lib/trellis-context.js +100 -13
  76. package/dist/templates/opencode/plugins/inject-subagent-context.js +54 -4
  77. package/dist/templates/opencode/plugins/inject-workflow-state.js +48 -25
  78. package/dist/templates/opencode/plugins/session-start.js +29 -16
  79. package/dist/templates/pi/agents/trellis-check.md +28 -0
  80. package/dist/templates/pi/agents/trellis-implement.md +33 -0
  81. package/dist/templates/pi/agents/trellis-research.md +25 -0
  82. package/dist/templates/pi/extensions/trellis/index.ts.txt +549 -0
  83. package/dist/templates/pi/index.d.ts +5 -0
  84. package/dist/templates/pi/index.d.ts.map +1 -0
  85. package/dist/templates/pi/index.js +12 -0
  86. package/dist/templates/pi/index.js.map +1 -0
  87. package/dist/templates/pi/settings.json +12 -0
  88. package/dist/templates/qoder/agents/trellis-research.md +1 -1
  89. package/dist/templates/shared-hooks/index.d.ts +31 -0
  90. package/dist/templates/shared-hooks/index.d.ts.map +1 -1
  91. package/dist/templates/shared-hooks/index.js +59 -0
  92. package/dist/templates/shared-hooks/index.js.map +1 -1
  93. package/dist/templates/shared-hooks/inject-shell-session-context.py +180 -0
  94. package/dist/templates/shared-hooks/inject-subagent-context.py +128 -26
  95. package/dist/templates/shared-hooks/inject-workflow-state.py +99 -62
  96. package/dist/templates/shared-hooks/session-start.py +139 -24
  97. package/dist/templates/trellis/gitignore.txt +3 -0
  98. package/dist/templates/trellis/index.d.ts +1 -0
  99. package/dist/templates/trellis/index.d.ts.map +1 -1
  100. package/dist/templates/trellis/index.js +2 -0
  101. package/dist/templates/trellis/index.js.map +1 -1
  102. package/dist/templates/trellis/scripts/common/__init__.py +8 -0
  103. package/dist/templates/trellis/scripts/common/active_task.py +593 -0
  104. package/dist/templates/trellis/scripts/common/cli_adapter.py +43 -8
  105. package/dist/templates/trellis/scripts/common/paths.py +61 -58
  106. package/dist/templates/trellis/scripts/common/session_context.py +12 -0
  107. package/dist/templates/trellis/scripts/common/task_store.py +6 -8
  108. package/dist/templates/trellis/scripts/task.py +59 -17
  109. package/dist/templates/trellis/workflow.md +30 -26
  110. package/dist/types/ai-tools.d.ts +3 -3
  111. package/dist/types/ai-tools.d.ts.map +1 -1
  112. package/dist/types/ai-tools.js +16 -0
  113. package/dist/types/ai-tools.js.map +1 -1
  114. package/dist/utils/posix.d.ts +13 -0
  115. package/dist/utils/posix.d.ts.map +1 -0
  116. package/dist/utils/posix.js +15 -0
  117. package/dist/utils/posix.js.map +1 -0
  118. package/dist/utils/template-fetcher.d.ts +22 -6
  119. package/dist/utils/template-fetcher.d.ts.map +1 -1
  120. package/dist/utils/template-fetcher.js +405 -27
  121. package/dist/utils/template-fetcher.js.map +1 -1
  122. package/dist/utils/template-hash.d.ts +22 -3
  123. package/dist/utils/template-hash.d.ts.map +1 -1
  124. package/dist/utils/template-hash.js +80 -18
  125. package/dist/utils/template-hash.js.map +1 -1
  126. package/package.json +1 -1
  127. package/dist/templates/shared-hooks/statusline.py +0 -219
@@ -2,10 +2,6 @@
2
2
  "env": {
3
3
  "CLAUDE_BASH_MAINTAIN_PROJECT_WORKING_DIR": "1"
4
4
  },
5
- "statusLine": {
6
- "type": "command",
7
- "command": "{{PYTHON_CMD}} .claude/hooks/statusline.py"
8
- },
9
5
  "hooks": {
10
6
  "SessionStart": [
11
7
  {
@@ -29,7 +29,7 @@ Conversations get compacted; files don't. Every research output MUST end up as a
29
29
 
30
30
  ### Step 1: Resolve Current Task
31
31
 
32
- Read `.trellis/.current-task` → task directory (e.g. `.trellis/tasks/04-17-foo/`). If empty or missing, ask the user where to write output; do NOT guess.
32
+ Run `python3 ./.trellis/scripts/task.py current --source` → active task path. If no active task is set, ask the user where to write output; do NOT guess.
33
33
 
34
34
  Ensure `{TASK_DIR}/research/` exists:
35
35
 
@@ -3,22 +3,6 @@ description = "Workspace-write Trellis reviewer that self-fixes spec drift, lint
3
3
  sandbox_mode = "workspace-write"
4
4
 
5
5
  developer_instructions = """
6
- ## Required: Load Trellis Context First
7
-
8
- This platform does NOT auto-inject task context via hook. Before doing anything else, you MUST load context yourself:
9
-
10
- 1. Read `.trellis/.current-task` to find the current task path (e.g. `.trellis/tasks/04-17-foo/`).
11
- 2. Read the task's `prd.md` (requirements) and `info.md` if it exists (technical design).
12
- 3. Read `<task-path>/check.jsonl` — JSONL list of dev spec files relevant to this agent.
13
- 4. For each entry in the JSONL, Read its `file` path — these are the dev specs you must follow.
14
- **Skip rows without a `"file"` field** (e.g. `{"_example": "..."}` seed rows left over from `task.py create` before the curator ran).
15
-
16
- If `check.jsonl` has no curated entries (only a seed row, or the file is missing), fall back to: read `prd.md`, list available specs with `python3 ./.trellis/scripts/get_context.py --mode packages`, and pick the specs that match the task domain yourself. Do NOT block on the missing jsonl — proceed with prd-only context plus your spec judgment.
17
-
18
- If `.current-task` is missing or the task has no `prd.md`, ask the user what to work on; do NOT proceed without context.
19
-
20
- ---
21
-
22
6
  You are the Trellis reviewer agent.
23
7
 
24
8
  Your job is to review code changes against specs AND fix issues directly — not just report them. You have write access; use it.
@@ -3,22 +3,6 @@ description = "Workspace-write Trellis implementer that follows specs and keeps
3
3
  sandbox_mode = "workspace-write"
4
4
 
5
5
  developer_instructions = """
6
- ## Required: Load Trellis Context First
7
-
8
- This platform does NOT auto-inject task context via hook. Before doing anything else, you MUST load context yourself:
9
-
10
- 1. Read `.trellis/.current-task` to find the current task path (e.g. `.trellis/tasks/04-17-foo/`).
11
- 2. Read the task's `prd.md` (requirements) and `info.md` if it exists (technical design).
12
- 3. Read `<task-path>/implement.jsonl` — JSONL list of dev spec files relevant to this agent.
13
- 4. For each entry in the JSONL, Read its `file` path — these are the dev specs you must follow.
14
- **Skip rows without a `"file"` field** (e.g. `{"_example": "..."}` seed rows left over from `task.py create` before the curator ran).
15
-
16
- If `implement.jsonl` has no curated entries (only a seed row, or the file is missing), fall back to: read `prd.md`, list available specs with `python3 ./.trellis/scripts/get_context.py --mode packages`, and pick the specs that match the task domain yourself. Do NOT block on the missing jsonl — proceed with prd-only context plus your spec judgment.
17
-
18
- If `.current-task` is missing or the task has no `prd.md`, ask the user what to work on; do NOT proceed without context.
19
-
20
- ---
21
-
22
6
  You are the Trellis implementer agent.
23
7
 
24
8
  Rules:
@@ -13,8 +13,9 @@ through the chat reply is a failure.
13
13
 
14
14
  ## Workflow
15
15
 
16
- 1. Read `.trellis/.current-task` to get the task directory. If empty,
17
- ask the user where to write output; do not guess.
16
+ 1. Run `python3 ./.trellis/scripts/task.py current --source` to get the
17
+ active task path and source. If no active task is set, ask the user
18
+ where to write output; do not guess.
18
19
  2. Run `mkdir -p <TASK_DIR>/research` to ensure the directory exists.
19
20
  3. Read `.trellis/workflow.md`, relevant `.trellis/spec/` files, and
20
21
  target code before forming an opinion.
@@ -74,10 +74,32 @@ def read_file(path: Path, fallback: str = "") -> str:
74
74
  return fallback
75
75
 
76
76
 
77
- def run_script(script_path: Path) -> str:
77
+ def _resolve_context_key(project_dir: Path, hook_input: dict) -> str | None:
78
+ scripts_dir = project_dir / ".trellis" / "scripts"
79
+ if str(scripts_dir) not in sys.path:
80
+ sys.path.insert(0, str(scripts_dir))
81
+ try:
82
+ from common.active_task import resolve_context_key # type: ignore[import-not-found]
83
+ except Exception:
84
+ return None
85
+ return resolve_context_key(hook_input, platform="codex")
86
+
87
+
88
+ def _resolve_active_task(trellis_dir: Path, hook_input: dict):
89
+ scripts_dir = trellis_dir / "scripts"
90
+ if str(scripts_dir) not in sys.path:
91
+ sys.path.insert(0, str(scripts_dir))
92
+ from common.active_task import resolve_active_task # type: ignore[import-not-found]
93
+
94
+ return resolve_active_task(trellis_dir.parent, hook_input, platform="codex")
95
+
96
+
97
+ def run_script(script_path: Path, context_key: str | None = None) -> str:
78
98
  try:
79
99
  env = os.environ.copy()
80
100
  env["PYTHONIOENCODING"] = "utf-8"
101
+ if context_key:
102
+ env["TRELLIS_CONTEXT_ID"] = context_key
81
103
  cmd = [sys.executable, "-W", "ignore", str(script_path)]
82
104
  result = subprocess.run(
83
105
  cmd,
@@ -123,18 +145,15 @@ def _resolve_task_dir(trellis_dir: Path, task_ref: str) -> Path:
123
145
  return trellis_dir / "tasks" / path_obj
124
146
 
125
147
 
126
- def _get_task_status(trellis_dir: Path) -> str:
127
- current_task_file = trellis_dir / ".current-task"
128
- if not current_task_file.is_file():
129
- return "Status: NO ACTIVE TASK\nNext: Describe what you want to work on"
130
-
131
- task_ref = _normalize_task_ref(current_task_file.read_text(encoding="utf-8").strip())
132
- if not task_ref:
133
- return "Status: NO ACTIVE TASK\nNext: Describe what you want to work on"
148
+ def _get_task_status(trellis_dir: Path, hook_input: dict) -> str:
149
+ active = _resolve_active_task(trellis_dir, hook_input)
150
+ if not active.task_path:
151
+ return f"Status: NO ACTIVE TASK\nSource: {active.source}\nNext: Describe what you want to work on"
134
152
 
153
+ task_ref = active.task_path
135
154
  task_dir = _resolve_task_dir(trellis_dir, task_ref)
136
- if not task_dir.is_dir():
137
- return f"Status: STALE POINTER\nTask: {task_ref}\nNext: Task directory not found. Run: python3 ./.trellis/scripts/task.py finish"
155
+ if active.stale or not task_dir.is_dir():
156
+ return f"Status: STALE POINTER\nTask: {task_ref}\nSource: {active.source}\nNext: Task directory not found. Run: python3 ./.trellis/scripts/task.py finish"
138
157
 
139
158
  task_json_path = task_dir / "task.json"
140
159
  task_data: dict = {}
@@ -148,7 +167,7 @@ def _get_task_status(trellis_dir: Path) -> str:
148
167
  task_status = task_data.get("status", "unknown")
149
168
 
150
169
  if task_status == "completed":
151
- return f"Status: COMPLETED\nTask: {task_title}\nNext: Archive with `python3 ./.trellis/scripts/task.py archive {task_dir.name}` or start a new task"
170
+ return f"Status: COMPLETED\nTask: {task_title}\nSource: {active.source}\nNext: Archive with `python3 ./.trellis/scripts/task.py archive {task_dir.name}` or start a new task"
152
171
 
153
172
  has_context = False
154
173
  for jsonl_name in ("implement.jsonl", "check.jsonl", "spec.jsonl"):
@@ -160,16 +179,21 @@ def _get_task_status(trellis_dir: Path) -> str:
160
179
  has_prd = (task_dir / "prd.md").is_file()
161
180
 
162
181
  if not has_prd:
163
- return f"Status: NOT READY\nTask: {task_title}\nMissing: prd.md not created\nNext: Write PRD (see workflow.md Phase 1.1) then curate implement.jsonl per Phase 1.3"
182
+ return f"Status: NOT READY\nTask: {task_title}\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"
164
183
 
165
184
  if not has_context:
166
- return f"Status: NOT READY\nTask: {task_title}\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`"
185
+ return f"Status: NOT READY\nTask: {task_title}\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`"
167
186
 
168
187
  return (
169
188
  f"Status: READY\nTask: {task_title}\n"
189
+ f"Source: {active.source}\n"
170
190
  "Next required action: dispatch `trellis-implement` per Phase 2.1. "
171
- "For agent-capable platforms, do NOT edit code in the main session. "
172
- "After implementation, dispatch `trellis-check` per Phase 2.2 before reporting completion."
191
+ "For agent-capable platforms, the default is to NOT edit code in the main session. "
192
+ "After implementation, dispatch `trellis-check` per Phase 2.2 before reporting completion.\n"
193
+ "User override (per-turn escape hatch): if the user's CURRENT message explicitly tells the "
194
+ "main session to handle it directly (\"你直接改\" / \"别派 sub-agent\" / \"main session 写就行\" / "
195
+ "\"do it inline\" / \"不用 sub-agent\"), honor it for this turn and edit code directly. "
196
+ "Per-turn only; do NOT invent an override the user did not say."
173
197
  )
174
198
 
175
199
 
@@ -224,13 +248,17 @@ def main() -> None:
224
248
  # Read hook input from stdin
225
249
  try:
226
250
  hook_input = json.loads(sys.stdin.read())
251
+ if not isinstance(hook_input, dict):
252
+ hook_input = {}
227
253
  project_dir = Path(hook_input.get("cwd", ".")).resolve()
228
254
  except (json.JSONDecodeError, KeyError):
255
+ hook_input = {}
229
256
  project_dir = Path(".").resolve()
230
257
 
231
258
  configure_project_encoding(project_dir)
232
259
 
233
260
  trellis_dir = project_dir / ".trellis"
261
+ context_key = _resolve_context_key(project_dir, hook_input)
234
262
 
235
263
  output = StringIO()
236
264
 
@@ -245,7 +273,7 @@ Read and follow all instructions below carefully.
245
273
 
246
274
  output.write("<current-state>\n")
247
275
  context_script = trellis_dir / "scripts" / "get_context.py"
248
- output.write(run_script(context_script))
276
+ output.write(run_script(context_script, context_key))
249
277
  output.write("\n</current-state>\n\n")
250
278
 
251
279
  output.write("<workflow>\n")
@@ -260,9 +288,11 @@ Read and follow all instructions below carefully.
260
288
  "- If you're spawning an implement/check sub-agent, context is injected "
261
289
  "automatically via `{task}/implement.jsonl` / `check.jsonl`. You do NOT "
262
290
  "need to read these indexes yourself.\n"
263
- "- For agent-capable platforms, do NOT edit code directly in the main "
264
- "session; dispatch `trellis-implement` and `trellis-check` so JSONL "
265
- "context is loaded by the sub-agents.\n\n"
291
+ "- For agent-capable platforms, the default is to dispatch "
292
+ "`trellis-implement` and `trellis-check` (so JSONL context is loaded by "
293
+ "the sub-agents) rather than editing code in the main session. "
294
+ "Honor a per-turn user override only if the user's current message "
295
+ "explicitly opts out (see <task-status> below for override phrases).\n\n"
266
296
  )
267
297
 
268
298
  # guides/ inlined (cross-package thinking, broadly useful)
@@ -306,7 +336,7 @@ Read and follow all instructions below carefully.
306
336
  )
307
337
  output.write("</guidelines>\n\n")
308
338
 
309
- task_status = _get_task_status(trellis_dir)
339
+ task_status = _get_task_status(trellis_dir, hook_input)
310
340
  output.write(f"<task-status>\n{task_status}\n</task-status>\n\n")
311
341
 
312
342
  output.write("""<ready>
@@ -269,7 +269,7 @@ python3 ./.trellis/scripts/task.py add-context "$TASK_DIR" check "<path>" "<reas
269
269
  python3 ./.trellis/scripts/task.py start "$TASK_DIR"
270
270
  ```
271
271
 
272
- This sets `.current-task` so hooks can inject context.
272
+ This sets the active task through Trellis' session resolver so hooks can inject context for this AI session. If the command fails because no session identity is available, rerun it from an IDE/session that exposes session identity or set `TRELLIS_CONTEXT_ID`.
273
273
 
274
274
  ---
275
275
 
@@ -71,10 +71,32 @@ def read_file(path: Path, fallback: str = "") -> str:
71
71
  return fallback
72
72
 
73
73
 
74
- def run_script(script_path: Path) -> str:
74
+ def _resolve_context_key(project_dir: Path, hook_input: dict) -> str | None:
75
+ scripts_dir = project_dir / ".trellis" / "scripts"
76
+ if str(scripts_dir) not in sys.path:
77
+ sys.path.insert(0, str(scripts_dir))
78
+ try:
79
+ from common.active_task import resolve_context_key # type: ignore[import-not-found]
80
+ except Exception:
81
+ return None
82
+ return resolve_context_key(hook_input, platform="copilot")
83
+
84
+
85
+ def _resolve_active_task(trellis_dir: Path, hook_input: dict):
86
+ scripts_dir = trellis_dir / "scripts"
87
+ if str(scripts_dir) not in sys.path:
88
+ sys.path.insert(0, str(scripts_dir))
89
+ from common.active_task import resolve_active_task # type: ignore[import-not-found]
90
+
91
+ return resolve_active_task(trellis_dir.parent, hook_input, platform="copilot")
92
+
93
+
94
+ def run_script(script_path: Path, context_key: str | None = None) -> str:
75
95
  try:
76
96
  env = os.environ.copy()
77
97
  env["PYTHONIOENCODING"] = "utf-8"
98
+ if context_key:
99
+ env["TRELLIS_CONTEXT_ID"] = context_key
78
100
  cmd = [sys.executable, "-W", "ignore", str(script_path)]
79
101
  result = subprocess.run(
80
102
  cmd,
@@ -120,18 +142,15 @@ def _resolve_task_dir(trellis_dir: Path, task_ref: str) -> Path:
120
142
  return trellis_dir / "tasks" / path_obj
121
143
 
122
144
 
123
- def _get_task_status(trellis_dir: Path) -> str:
124
- current_task_file = trellis_dir / ".current-task"
125
- if not current_task_file.is_file():
126
- return "Status: NO ACTIVE TASK\nNext: Describe what you want to work on"
127
-
128
- task_ref = _normalize_task_ref(current_task_file.read_text(encoding="utf-8").strip())
129
- if not task_ref:
130
- return "Status: NO ACTIVE TASK\nNext: Describe what you want to work on"
145
+ def _get_task_status(trellis_dir: Path, hook_input: dict) -> str:
146
+ active = _resolve_active_task(trellis_dir, hook_input)
147
+ if not active.task_path:
148
+ return f"Status: NO ACTIVE TASK\nSource: {active.source}\nNext: Describe what you want to work on"
131
149
 
150
+ task_ref = active.task_path
132
151
  task_dir = _resolve_task_dir(trellis_dir, task_ref)
133
- if not task_dir.is_dir():
134
- return f"Status: STALE POINTER\nTask: {task_ref}\nNext: Task directory not found. Run: python3 ./.trellis/scripts/task.py finish"
152
+ if active.stale or not task_dir.is_dir():
153
+ return f"Status: STALE POINTER\nTask: {task_ref}\nSource: {active.source}\nNext: Task directory not found. Run: python3 ./.trellis/scripts/task.py finish"
135
154
 
136
155
  task_json_path = task_dir / "task.json"
137
156
  task_data: dict = {}
@@ -145,7 +164,7 @@ def _get_task_status(trellis_dir: Path) -> str:
145
164
  task_status = task_data.get("status", "unknown")
146
165
 
147
166
  if task_status == "completed":
148
- return f"Status: COMPLETED\nTask: {task_title}\nNext: Archive with `python3 ./.trellis/scripts/task.py archive {task_dir.name}` or start a new task"
167
+ return f"Status: COMPLETED\nTask: {task_title}\nSource: {active.source}\nNext: Archive with `python3 ./.trellis/scripts/task.py archive {task_dir.name}` or start a new task"
149
168
 
150
169
  has_context = False
151
170
  for jsonl_name in ("implement.jsonl", "check.jsonl", "spec.jsonl"):
@@ -157,16 +176,21 @@ def _get_task_status(trellis_dir: Path) -> str:
157
176
  has_prd = (task_dir / "prd.md").is_file()
158
177
 
159
178
  if not has_prd:
160
- return f"Status: NOT READY\nTask: {task_title}\nMissing: prd.md not created\nNext: Write PRD (see workflow.md Phase 1.1) then curate implement.jsonl per Phase 1.3"
179
+ return f"Status: NOT READY\nTask: {task_title}\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"
161
180
 
162
181
  if not has_context:
163
- return f"Status: NOT READY\nTask: {task_title}\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`"
182
+ return f"Status: NOT READY\nTask: {task_title}\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`"
164
183
 
165
184
  return (
166
185
  f"Status: READY\nTask: {task_title}\n"
186
+ f"Source: {active.source}\n"
167
187
  "Next required action: dispatch `trellis-implement` per Phase 2.1. "
168
- "For agent-capable platforms, do NOT edit code in the main session. "
169
- "After implementation, dispatch `trellis-check` per Phase 2.2 before reporting completion."
188
+ "For agent-capable platforms, the default is to NOT edit code in the main session. "
189
+ "After implementation, dispatch `trellis-check` per Phase 2.2 before reporting completion.\n"
190
+ "User override (per-turn escape hatch): if the user's CURRENT message explicitly tells the "
191
+ "main session to handle it directly (\"你直接改\" / \"别派 sub-agent\" / \"main session 写就行\" / "
192
+ "\"do it inline\" / \"不用 sub-agent\"), honor it for this turn and edit code directly. "
193
+ "Per-turn only; do NOT invent an override the user did not say."
170
194
  )
171
195
 
172
196
 
@@ -221,13 +245,17 @@ def main() -> None:
221
245
  # Read hook input from stdin
222
246
  try:
223
247
  hook_input = json.loads(sys.stdin.read())
248
+ if not isinstance(hook_input, dict):
249
+ hook_input = {}
224
250
  project_dir = Path(hook_input.get("cwd", ".")).resolve()
225
251
  except (json.JSONDecodeError, KeyError):
252
+ hook_input = {}
226
253
  project_dir = Path(".").resolve()
227
254
 
228
255
  configure_project_encoding(project_dir)
229
256
 
230
257
  trellis_dir = project_dir / ".trellis"
258
+ context_key = _resolve_context_key(project_dir, hook_input)
231
259
 
232
260
  output = StringIO()
233
261
 
@@ -240,7 +268,7 @@ Read and follow all instructions below carefully.
240
268
 
241
269
  output.write("<current-state>\n")
242
270
  context_script = trellis_dir / "scripts" / "get_context.py"
243
- output.write(run_script(context_script))
271
+ output.write(run_script(context_script, context_key))
244
272
  output.write("\n</current-state>\n\n")
245
273
 
246
274
  output.write("<workflow>\n")
@@ -255,9 +283,11 @@ Read and follow all instructions below carefully.
255
283
  "- If you're spawning an implement/check sub-agent, context is injected "
256
284
  "automatically via `{task}/implement.jsonl` / `check.jsonl`. You do NOT "
257
285
  "need to read these indexes yourself.\n"
258
- "- For agent-capable platforms, do NOT edit code directly in the main "
259
- "session; dispatch `trellis-implement` and `trellis-check` so JSONL "
260
- "context is loaded by the sub-agents.\n\n"
286
+ "- For agent-capable platforms, the default is to dispatch "
287
+ "`trellis-implement` and `trellis-check` (so JSONL context is loaded by "
288
+ "the sub-agents) rather than editing code in the main session. "
289
+ "Honor a per-turn user override only if the user's current message "
290
+ "explicitly opts out (see <task-status> below for override phrases).\n\n"
261
291
  )
262
292
 
263
293
  # guides/ inlined (cross-package thinking, broadly useful)
@@ -301,7 +331,7 @@ Read and follow all instructions below carefully.
301
331
  )
302
332
  output.write("</guidelines>\n\n")
303
333
 
304
- task_status = _get_task_status(trellis_dir)
334
+ task_status = _get_task_status(trellis_dir, hook_input)
305
335
  output.write(f"<task-status>\n{task_status}\n</task-status>\n\n")
306
336
 
307
337
  output.write("""<ready>
@@ -298,7 +298,7 @@ python3 ./.trellis/scripts/task.py add-context "$TASK_DIR" check "<path>" "<reas
298
298
  python3 ./.trellis/scripts/task.py start "$TASK_DIR"
299
299
  ```
300
300
 
301
- This sets `.current-task` so hooks can inject context.
301
+ This sets the active task through Trellis' session resolver so hooks can inject context for this AI session. If the command fails because no session identity is available, rerun it from an IDE/session that exposes session identity or set `TRELLIS_CONTEXT_ID`.
302
302
 
303
303
  ---
304
304
 
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: trellis-check
3
3
  description: |
4
- Code quality check expert. Reviews code changes against specs and self-fixes issues.
4
+ Trellis quality check agent. Use this exact agent for Trellis task verification, check.jsonl context injection, and self-fixing code review. Do not use generic/default/generalPurpose agents for Trellis checks.
5
5
  tools: Read, Write, Edit, Bash, Glob, Grep, mcp__exa__web_search_exa, mcp__exa__get_code_context_exa
6
6
  ---
7
7
  # Check Agent
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: trellis-implement
3
3
  description: |
4
- Code implementation expert. Understands specs and requirements, then implements features. No git commit allowed.
4
+ Trellis implementation agent. Use this exact agent for Trellis task implementation, implement.jsonl context injection, and hook-injection tests. Do not use generic/default/generalPurpose agents for Trellis implementation. No git commit allowed.
5
5
  tools: Read, Write, Edit, Bash, Glob, Grep, mcp__exa__web_search_exa, mcp__exa__get_code_context_exa
6
6
  ---
7
7
  # Implement Agent
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: trellis-research
3
3
  description: |
4
- Code and tech search expert. Finds files, patterns, and tech solutions, and PERSISTS every finding to the current task's research/ directory. No code modifications outside that directory.
4
+ Trellis research agent. Use this exact agent for Trellis task research and research/ persistence. Do not use generic/default/generalPurpose agents for Trellis research.
5
5
  tools: Read, Write, Glob, Grep, Bash, mcp__exa__web_search_exa, mcp__exa__get_code_context_exa, Skill, mcp__chrome-devtools__*
6
6
  ---
7
7
  # Research Agent
@@ -29,7 +29,7 @@ Conversations get compacted; files don't. Every research output MUST end up as a
29
29
 
30
30
  ### Step 1: Resolve Current Task
31
31
 
32
- Read `.trellis/.current-task` → task directory (e.g. `.trellis/tasks/04-17-foo/`). If empty or missing, ask the user where to write output; do NOT guess.
32
+ Run `python3 ./.trellis/scripts/task.py current --source` → active task path. If no active task is set, ask the user where to write output; do NOT guess.
33
33
 
34
34
  Ensure `{TASK_DIR}/research/` exists:
35
35
 
@@ -4,7 +4,7 @@
4
4
  "preToolUse": [
5
5
  {
6
6
  "command": "{{PYTHON_CMD}} .cursor/hooks/inject-subagent-context.py",
7
- "matcher": "Task",
7
+ "matcher": "Task|Subagent",
8
8
  "timeout": 30
9
9
  }
10
10
  ],
@@ -19,6 +19,12 @@
19
19
  "command": "{{PYTHON_CMD}} .cursor/hooks/inject-workflow-state.py",
20
20
  "timeout": 5
21
21
  }
22
+ ],
23
+ "beforeShellExecution": [
24
+ {
25
+ "command": "{{PYTHON_CMD}} .cursor/hooks/inject-shell-session-context.py",
26
+ "timeout": 5
27
+ }
22
28
  ]
23
29
  }
24
30
  }
@@ -29,7 +29,7 @@ Conversations get compacted; files don't. Every research output MUST end up as a
29
29
 
30
30
  ### Step 1: Resolve Current Task
31
31
 
32
- Read `.trellis/.current-task` → task directory (e.g. `.trellis/tasks/04-17-foo/`). If empty or missing, ask the user where to write output; do NOT guess.
32
+ Run `python3 ./.trellis/scripts/task.py current --source` → active task path. If no active task is set, ask the user where to write output; do NOT guess.
33
33
 
34
34
  Ensure `{TASK_DIR}/research/` exists:
35
35
 
@@ -13,6 +13,12 @@ export declare function getClaudeTemplatePath(): string;
13
13
  * Get the path to the opencode templates directory (agents, plugins, lib).
14
14
  */
15
15
  export declare function getOpenCodeTemplatePath(): string;
16
+ /**
17
+ * Get the path to the Pi Agent templates directory (agents, extension, settings).
18
+ */
19
+ export declare function getPiTemplatePath(): string;
20
+ /** @deprecated Use getPiTemplatePath() instead. */
21
+ export declare function getPiSourcePath(): string;
16
22
  /**
17
23
  * Read a file from the trellis template directory.
18
24
  */
@@ -1 +1 @@
1
- {"version":3,"file":"extract.d.ts","sourceRoot":"","sources":["../../src/templates/extract.ts"],"names":[],"mappings":"AAQA,KAAK,gBAAgB,GAAG,SAAS,GAAG,UAAU,GAAG,UAAU,CAAC;AAE5D;;GAEG;AACH,wBAAgB,sBAAsB,IAAI,MAAM,CAQ/C;AAED,wDAAwD;AACxD,wBAAgB,oBAAoB,IAAI,MAAM,CAE7C;AAED;;GAEG;AACH,wBAAgB,qBAAqB,IAAI,MAAM,CAQ9C;AAED;;GAEG;AACH,wBAAgB,uBAAuB,IAAI,MAAM,CAQhD;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAI5D;AAED;;GAEG;AACH,wBAAgB,YAAY,CAC1B,QAAQ,EAAE,gBAAgB,EAC1B,QAAQ,EAAE,MAAM,GACf,MAAM,CAGR;AAED,wBAAgB,UAAU,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAEvD;AAED,wBAAgB,YAAY,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAEzD;AAED,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAEpD;AAED;;GAEG;AACH,wBAAsB,cAAc,CAClC,eAAe,EAAE,MAAM,EACvB,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE;IAAE,UAAU,CAAC,EAAE,OAAO,CAAA;CAAE,GACjC,OAAO,CAAC,IAAI,CAAC,CAIf"}
1
+ {"version":3,"file":"extract.d.ts","sourceRoot":"","sources":["../../src/templates/extract.ts"],"names":[],"mappings":"AAQA,KAAK,gBAAgB,GAAG,SAAS,GAAG,UAAU,GAAG,UAAU,CAAC;AAE5D;;GAEG;AACH,wBAAgB,sBAAsB,IAAI,MAAM,CAQ/C;AAED,wDAAwD;AACxD,wBAAgB,oBAAoB,IAAI,MAAM,CAE7C;AAED;;GAEG;AACH,wBAAgB,qBAAqB,IAAI,MAAM,CAQ9C;AAED;;GAEG;AACH,wBAAgB,uBAAuB,IAAI,MAAM,CAQhD;AAED;;GAEG;AACH,wBAAgB,iBAAiB,IAAI,MAAM,CAQ1C;AAED,mDAAmD;AACnD,wBAAgB,eAAe,IAAI,MAAM,CAExC;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAI5D;AAED;;GAEG;AACH,wBAAgB,YAAY,CAC1B,QAAQ,EAAE,gBAAgB,EAC1B,QAAQ,EAAE,MAAM,GACf,MAAM,CAGR;AAED,wBAAgB,UAAU,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAEvD;AAED,wBAAgB,YAAY,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAEzD;AAED,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAEpD;AAED;;GAEG;AACH,wBAAsB,cAAc,CAClC,eAAe,EAAE,MAAM,EACvB,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE;IAAE,UAAU,CAAC,EAAE,OAAO,CAAA;CAAE,GACjC,OAAO,CAAC,IAAI,CAAC,CAIf"}
@@ -38,6 +38,20 @@ export function getOpenCodeTemplatePath() {
38
38
  }
39
39
  throw new Error("Could not find opencode templates directory. Expected at templates/opencode/");
40
40
  }
41
+ /**
42
+ * Get the path to the Pi Agent templates directory (agents, extension, settings).
43
+ */
44
+ export function getPiTemplatePath() {
45
+ const templatePath = path.join(__dirname, "pi");
46
+ if (fs.existsSync(templatePath)) {
47
+ return templatePath;
48
+ }
49
+ throw new Error("Could not find pi templates directory. Expected at templates/pi/");
50
+ }
51
+ /** @deprecated Use getPiTemplatePath() instead. */
52
+ export function getPiSourcePath() {
53
+ return getPiTemplatePath();
54
+ }
41
55
  /**
42
56
  * Read a file from the trellis template directory.
43
57
  */
@@ -1 +1 @@
1
- {"version":3,"file":"extract.js","sourceRoot":"","sources":["../../src/templates/extract.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AAE/D,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAClD,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;AAI3C;;GAEG;AACH,MAAM,UAAU,sBAAsB;IACpC,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;IACrD,IAAI,EAAE,CAAC,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;QAChC,OAAO,YAAY,CAAC;IACtB,CAAC;IACD,MAAM,IAAI,KAAK,CACb,4EAA4E,CAC7E,CAAC;AACJ,CAAC;AAED,wDAAwD;AACxD,MAAM,UAAU,oBAAoB;IAClC,OAAO,sBAAsB,EAAE,CAAC;AAClC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,qBAAqB;IACnC,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;IACpD,IAAI,EAAE,CAAC,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;QAChC,OAAO,YAAY,CAAC;IACtB,CAAC;IACD,MAAM,IAAI,KAAK,CACb,0EAA0E,CAC3E,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,uBAAuB;IACrC,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC;IACtD,IAAI,EAAE,CAAC,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;QAChC,OAAO,YAAY,CAAC;IACtB,CAAC;IACD,MAAM,IAAI,KAAK,CACb,8EAA8E,CAC/E,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,eAAe,CAAC,YAAoB;IAClD,MAAM,WAAW,GAAG,oBAAoB,EAAE,CAAC;IAC3C,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,YAAY,CAAC,CAAC;IACtD,OAAO,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;AAC5C,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,YAAY,CAC1B,QAA0B,EAC1B,QAAgB;IAEhB,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC;IAC9D,OAAO,EAAE,CAAC,YAAY,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;AAChD,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,YAAoB;IAC7C,OAAO,eAAe,CAAC,WAAW,YAAY,EAAE,CAAC,CAAC;AACpD,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,YAAoB;IAC/C,OAAO,eAAe,CAAC,YAAY,CAAC,CAAC;AACvC,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,QAAgB;IAC1C,OAAO,YAAY,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;AAC5C,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,eAAuB,EACvB,QAAgB,EAChB,OAAkC;IAElC,MAAM,WAAW,GAAG,oBAAoB,EAAE,CAAC;IAC3C,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,eAAe,CAAC,CAAC;IACxD,MAAM,gBAAgB,CAAC,OAAO,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;AACrD,CAAC;AAED,KAAK,UAAU,gBAAgB,CAC7B,GAAW,EACX,IAAY,EACZ,OAAkC;IAElC,SAAS,CAAC,IAAI,CAAC,CAAC;IAEhB,KAAK,MAAM,KAAK,IAAI,EAAE,CAAC,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC;QACxC,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;QACtC,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;QACxC,MAAM,IAAI,GAAG,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;QAElC,IAAI,IAAI,CAAC,WAAW,EAAE,EAAE,CAAC;YACvB,MAAM,gBAAgB,CAAC,OAAO,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;QACrD,CAAC;aAAM,CAAC;YACN,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;YAClD,MAAM,YAAY,GAChB,OAAO,EAAE,UAAU,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC;YAC1E,MAAM,SAAS,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,UAAU,EAAE,YAAY,EAAE,CAAC,CAAC;QACnE,CAAC;IACH,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"extract.js","sourceRoot":"","sources":["../../src/templates/extract.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AAE/D,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAClD,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;AAI3C;;GAEG;AACH,MAAM,UAAU,sBAAsB;IACpC,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;IACrD,IAAI,EAAE,CAAC,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;QAChC,OAAO,YAAY,CAAC;IACtB,CAAC;IACD,MAAM,IAAI,KAAK,CACb,4EAA4E,CAC7E,CAAC;AACJ,CAAC;AAED,wDAAwD;AACxD,MAAM,UAAU,oBAAoB;IAClC,OAAO,sBAAsB,EAAE,CAAC;AAClC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,qBAAqB;IACnC,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;IACpD,IAAI,EAAE,CAAC,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;QAChC,OAAO,YAAY,CAAC;IACtB,CAAC;IACD,MAAM,IAAI,KAAK,CACb,0EAA0E,CAC3E,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,uBAAuB;IACrC,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC;IACtD,IAAI,EAAE,CAAC,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;QAChC,OAAO,YAAY,CAAC;IACtB,CAAC;IACD,MAAM,IAAI,KAAK,CACb,8EAA8E,CAC/E,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,iBAAiB;IAC/B,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;IAChD,IAAI,EAAE,CAAC,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;QAChC,OAAO,YAAY,CAAC;IACtB,CAAC;IACD,MAAM,IAAI,KAAK,CACb,kEAAkE,CACnE,CAAC;AACJ,CAAC;AAED,mDAAmD;AACnD,MAAM,UAAU,eAAe;IAC7B,OAAO,iBAAiB,EAAE,CAAC;AAC7B,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,eAAe,CAAC,YAAoB;IAClD,MAAM,WAAW,GAAG,oBAAoB,EAAE,CAAC;IAC3C,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,YAAY,CAAC,CAAC;IACtD,OAAO,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;AAC5C,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,YAAY,CAC1B,QAA0B,EAC1B,QAAgB;IAEhB,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC;IAC9D,OAAO,EAAE,CAAC,YAAY,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;AAChD,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,YAAoB;IAC7C,OAAO,eAAe,CAAC,WAAW,YAAY,EAAE,CAAC,CAAC;AACpD,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,YAAoB;IAC/C,OAAO,eAAe,CAAC,YAAY,CAAC,CAAC;AACvC,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,QAAgB;IAC1C,OAAO,YAAY,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;AAC5C,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,eAAuB,EACvB,QAAgB,EAChB,OAAkC;IAElC,MAAM,WAAW,GAAG,oBAAoB,EAAE,CAAC;IAC3C,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,eAAe,CAAC,CAAC;IACxD,MAAM,gBAAgB,CAAC,OAAO,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;AACrD,CAAC;AAED,KAAK,UAAU,gBAAgB,CAC7B,GAAW,EACX,IAAY,EACZ,OAAkC;IAElC,SAAS,CAAC,IAAI,CAAC,CAAC;IAEhB,KAAK,MAAM,KAAK,IAAI,EAAE,CAAC,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC;QACxC,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;QACtC,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;QACxC,MAAM,IAAI,GAAG,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;QAElC,IAAI,IAAI,CAAC,WAAW,EAAE,EAAE,CAAC;YACvB,MAAM,gBAAgB,CAAC,OAAO,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;QACrD,CAAC;aAAM,CAAC;YACN,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;YAClD,MAAM,YAAY,GAChB,OAAO,EAAE,UAAU,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC;YAC1E,MAAM,SAAS,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,UAAU,EAAE,YAAY,EAAE,CAAC,CAAC;QACnE,CAAC;IACH,CAAC;AACH,CAAC"}
@@ -29,7 +29,7 @@ Conversations get compacted; files don't. Every research output MUST end up as a
29
29
 
30
30
  ### Step 1: Resolve Current Task
31
31
 
32
- Read `.trellis/.current-task` → task directory (e.g. `.trellis/tasks/04-17-foo/`). If empty or missing, ask the user where to write output; do NOT guess.
32
+ Run `python3 ./.trellis/scripts/task.py current --source` → active task path. If no active task is set, ask the user where to write output; do NOT guess.
33
33
 
34
34
  Ensure `{TASK_DIR}/research/` exists:
35
35
 
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "trellis-research",
3
3
  "description": "Code and tech search expert. Persists findings to {TASK_DIR}/research/. No writes outside that directory.",
4
- "instructions": "# Research Agent\n\nYou are the Research Agent in the Trellis workflow.\n\n## Core Principle\n\n**You do one thing: find, explain, and PERSIST information.**\n\nConversations get compacted; files don't. Every research output MUST end up as a file under `{TASK_DIR}/research/`. Returning findings only through the chat reply is a failure — the caller cannot read them next session.\n\n---\n\n## Core Responsibilities\n\n1. **Internal Search** — locate files/components, understand code logic, discover patterns (Glob, Grep, Read)\n2. **External Search** — library docs, API references, best practices (web search)\n3. **Persist** — write each research topic to `{TASK_DIR}/research/<topic>.md`\n4. **Report** — return file paths + one-line summaries to the main agent (not full content)\n\n---\n\n## Workflow\n\n### Step 1: Resolve Current Task\n\nRead `.trellis/.current-task` → task directory (e.g. `.trellis/tasks/04-17-foo/`). If empty or missing, ask the user where to write output; do NOT guess.\n\nEnsure `{TASK_DIR}/research/` exists:\n\n```bash\nmkdir -p <TASK_DIR>/research\n```\n\n### Step 2: Understand Search Request\n\nClassify: internal / external / mixed. Determine scope (global / specific directory) and expected shape (file list / pattern notes / tech comparison).\n\n### Step 3: Execute Search\n\nRun independent searches in parallel (Glob + Grep + web) for efficiency.\n\n### Step 4: Persist Each Topic\n\nFor each distinct research topic, Write a markdown file at `{TASK_DIR}/research/<topic-slug>.md`. Use the File Format below.\n\n### Step 5: Report to Main Agent\n\nReply with ONLY:\n\n- List of files written (paths relative to repo root)\n- One-line summary per file\n- Any critical caveats that the main agent needs to know right now\n\nDo NOT paste full research content into the reply. The files are the contract.\n\n---\n\n## Scope Limits (Strict)\n\n### Write ALLOWED\n\n- `{TASK_DIR}/research/*.md` — your own output\n- Creating `{TASK_DIR}/research/` if it doesn't exist (via `mkdir -p`)\n\n### Write FORBIDDEN\n\n- Code files (`src/`, `lib/`, …)\n- Spec files (`.trellis/spec/`) — main agent should use `update-spec` skill instead\n- `.trellis/scripts/`, `.trellis/workflow.md`, platform config (`.claude/`, `.cursor/`, etc.)\n- Other task directories\n- Any git operation (commit / push / branch / merge)\n\nIf the user asks you to edit code, decline and suggest spawning `implement` instead.\n\n---\n\n## File Format\n\nEach `{TASK_DIR}/research/<topic>.md` should follow:\n\n```markdown\n# Research: <topic>\n\n- **Query**: <original query>\n- **Scope**: <internal / external / mixed>\n- **Date**: <YYYY-MM-DD>\n\n## Findings\n\n### Files Found\n\n| File Path | Description |\n|---|---|\n| `src/services/xxx.ts` | Main implementation |\n| `src/types/xxx.ts` | Type definitions |\n\n### Code Patterns\n\n<describe patterns, cite file:line>\n\n### External References\n\n- [Library X docs](url) — <why relevant, version constraints>\n\n### Related Specs\n\n- `.trellis/spec/xxx.md` — <description>\n\n## Caveats / Not Found\n\n<anything incomplete or uncertain>\n```\n\n---\n\n## Guidelines\n\n### DO\n\n- Provide specific file paths and line numbers\n- Quote actual code snippets\n- Persist every topic to its own file\n- Return file paths in your reply, not the full content\n- Mark \"not found\" explicitly when searches come up empty\n\n### DON'T\n\n- Don't write code or modify files outside `{TASK_DIR}/research/`\n- Don't guess uncertain info\n- Don't paste full research text into the reply (files are the deliverable)\n- Don't propose improvements or critique implementation (that's not your role)\n",
4
+ "instructions": "# Research Agent\n\nYou are the Research Agent in the Trellis workflow.\n\n## Core Principle\n\n**You do one thing: find, explain, and PERSIST information.**\n\nConversations get compacted; files don't. Every research output MUST end up as a file under `{TASK_DIR}/research/`. Returning findings only through the chat reply is a failure — the caller cannot read them next session.\n\n---\n\n## Core Responsibilities\n\n1. **Internal Search** — locate files/components, understand code logic, discover patterns (Glob, Grep, Read)\n2. **External Search** — library docs, API references, best practices (web search)\n3. **Persist** — write each research topic to `{TASK_DIR}/research/<topic>.md`\n4. **Report** — return file paths + one-line summaries to the main agent (not full content)\n\n---\n\n## Workflow\n\n### Step 1: Resolve Current Task\n\nRun `python3 ./.trellis/scripts/task.py current --source` → active task path. If no active task is set, ask the user where to write output; do NOT guess.\n\nEnsure `{TASK_DIR}/research/` exists:\n\n```bash\nmkdir -p <TASK_DIR>/research\n```\n\n### Step 2: Understand Search Request\n\nClassify: internal / external / mixed. Determine scope (global / specific directory) and expected shape (file list / pattern notes / tech comparison).\n\n### Step 3: Execute Search\n\nRun independent searches in parallel (Glob + Grep + web) for efficiency.\n\n### Step 4: Persist Each Topic\n\nFor each distinct research topic, Write a markdown file at `{TASK_DIR}/research/<topic-slug>.md`. Use the File Format below.\n\n### Step 5: Report to Main Agent\n\nReply with ONLY:\n\n- List of files written (paths relative to repo root)\n- One-line summary per file\n- Any critical caveats that the main agent needs to know right now\n\nDo NOT paste full research content into the reply. The files are the contract.\n\n---\n\n## Scope Limits (Strict)\n\n### Write ALLOWED\n\n- `{TASK_DIR}/research/*.md` — your own output\n- Creating `{TASK_DIR}/research/` if it doesn't exist (via `mkdir -p`)\n\n### Write FORBIDDEN\n\n- Code files (`src/`, `lib/`, …)\n- Spec files (`.trellis/spec/`) — main agent should use `update-spec` skill instead\n- `.trellis/scripts/`, `.trellis/workflow.md`, platform config (`.claude/`, `.cursor/`, etc.)\n- Other task directories\n- Any git operation (commit / push / branch / merge)\n\nIf the user asks you to edit code, decline and suggest spawning `implement` instead.\n\n---\n\n## File Format\n\nEach `{TASK_DIR}/research/<topic>.md` should follow:\n\n```markdown\n# Research: <topic>\n\n- **Query**: <original query>\n- **Scope**: <internal / external / mixed>\n- **Date**: <YYYY-MM-DD>\n\n## Findings\n\n### Files Found\n\n| File Path | Description |\n|---|---|\n| `src/services/xxx.ts` | Main implementation |\n| `src/types/xxx.ts` | Type definitions |\n\n### Code Patterns\n\n<describe patterns, cite file:line>\n\n### External References\n\n- [Library X docs](url) — <why relevant, version constraints>\n\n### Related Specs\n\n- `.trellis/spec/xxx.md` — <description>\n\n## Caveats / Not Found\n\n<anything incomplete or uncertain>\n```\n\n---\n\n## Guidelines\n\n### DO\n\n- Provide specific file paths and line numbers\n- Quote actual code snippets\n- Persist every topic to its own file\n- Return file paths in your reply, not the full content\n- Mark \"not found\" explicitly when searches come up empty\n\n### DON'T\n\n- Don't write code or modify files outside `{TASK_DIR}/research/`\n- Don't guess uncertain info\n- Don't paste full research text into the reply (files are the deliverable)\n- Don't propose improvements or critique implementation (that's not your role)\n",
5
5
  "tools": [
6
6
  "read",
7
7
  "write",
@@ -3,20 +3,19 @@
3
3
 
4
4
  These instructions are for AI assistants working in this project.
5
5
 
6
- Use the `/trellis:start` command when starting a new session to:
7
- - Initialize your developer identity
8
- - Understand current project context
9
- - Read relevant guidelines
6
+ This project is managed by Trellis. The working knowledge you need lives under `.trellis/`:
10
7
 
11
- Use `@/.trellis/` to learn:
12
- - Development workflow (`workflow.md`)
13
- - Project structure guidelines (`spec/`)
14
- - Developer workspace (`workspace/`)
8
+ - `.trellis/workflow.md` — development phases, when to create tasks, skill routing
9
+ - `.trellis/spec/` package- and layer-scoped coding guidelines (read before writing code in a given layer)
10
+ - `.trellis/workspace/` per-developer journals and session traces
11
+ - `.trellis/tasks/` active and archived tasks (PRDs, research, jsonl context)
15
12
 
16
- If you're using Codex, project-scoped helpers may also live in:
17
- - `.agents/skills/` for reusable Trellis skills
18
- - `.codex/agents/` for optional custom subagents
13
+ If a Trellis command is available on your platform (e.g. `/trellis:finish-work`, `/trellis:continue`), prefer it over manual steps. Not every platform exposes every command.
19
14
 
20
- Keep this managed block so 'trellis update' can refresh the instructions.
15
+ If you're using Codex or another agent-capable tool, additional project-scoped helpers may live in:
16
+ - `.agents/skills/` — reusable Trellis skills
17
+ - `.codex/agents/` — optional custom subagents
18
+
19
+ Managed by Trellis. Edits outside this block are preserved; edits inside may be overwritten by a future `trellis update`.
21
20
 
22
21
  <!-- TRELLIS:END -->
@@ -7,6 +7,9 @@
7
7
  # Current task pointer (local state)
8
8
  .current-task
9
9
 
10
+ # Session/window scoped runtime state
11
+ .runtime/
12
+
10
13
  # Agent runtime files (in worktree)
11
14
  .agent-log
12
15
  .session-id
@@ -21,7 +21,7 @@ You are the Check Agent in the Trellis workflow.
21
21
 
22
22
  Otherwise, load context yourself:
23
23
 
24
- 1. Read `.trellis/.current-task` → get task directory (e.g., `.trellis/tasks/xxx`)
24
+ 1. Run `python3 ./.trellis/scripts/task.py current --source` → get active task directory and source (e.g., `Current task: .trellis/tasks/xxx`)
25
25
  2. Read `{task_dir}/check.jsonl`
26
26
  3. For each entry in JSONL:
27
27
  - If `path` is a file → Read it
@@ -21,7 +21,7 @@ You are the Implement Agent in the Trellis workflow.
21
21
 
22
22
  Otherwise, load context yourself:
23
23
 
24
- 1. Read `.trellis/.current-task` → get task directory (e.g., `.trellis/tasks/xxx`)
24
+ 1. Run `python3 ./.trellis/scripts/task.py current --source` → get active task directory and source (e.g., `Current task: .trellis/tasks/xxx`)
25
25
  2. Read `{task_dir}/implement.jsonl`
26
26
  3. For each entry in JSONL (JSON object per line):
27
27
  - Skip rows without a `"file"` field (e.g. `{"_example": "..."}` seed rows)