@pennixrv/trellis 0.7.0-beta.32 → 0.7.0-beta.34

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 (32) hide show
  1. package/dist/commands/channel/index.d.ts.map +1 -1
  2. package/dist/commands/channel/index.js +15 -11
  3. package/dist/commands/channel/index.js.map +1 -1
  4. package/dist/commands/channel/spawn.d.ts.map +1 -1
  5. package/dist/commands/channel/spawn.js +16 -11
  6. package/dist/commands/channel/spawn.js.map +1 -1
  7. package/dist/migrations/manifests/0.7.0-beta.33.json +9 -0
  8. package/dist/migrations/manifests/0.7.0-beta.34.json +9 -0
  9. package/dist/templates/common/bundled-skills/trellis-channel/SKILL.md +3 -1
  10. package/dist/templates/common/bundled-skills/trellis-channel/references/command-reference.md +11 -10
  11. package/dist/templates/common/bundled-skills/trellis-channel/references/forum.md +4 -12
  12. package/dist/templates/common/bundled-skills/trellis-channel/references/multi-target-dispatch.md +113 -0
  13. package/dist/templates/common/bundled-skills/trellis-channel/references/progress-debugging.md +4 -4
  14. package/dist/templates/common/bundled-skills/trellis-channel/references/subnode-work.md +32 -7
  15. package/dist/templates/common/bundled-skills/trellis-channel/references/workers.md +2 -3
  16. package/dist/templates/common/bundled-skills/trellis-channel/references/workflows.md +11 -12
  17. package/dist/templates/common/bundled-skills/trellis-meta/references/customize-local/change-task-lifecycle.md +6 -2
  18. package/dist/templates/common/bundled-skills/trellis-meta/references/local-architecture/task-system.md +6 -1
  19. package/dist/templates/common/commands/continue.md +3 -2
  20. package/dist/templates/common/commands/start.md +1 -0
  21. package/dist/templates/common/skills/brainstorm.md +14 -1
  22. package/dist/templates/shared-hooks/inject-workflow-state.py +2 -1
  23. package/dist/templates/trellis/index.d.ts +1 -0
  24. package/dist/templates/trellis/index.d.ts.map +1 -1
  25. package/dist/templates/trellis/index.js +2 -0
  26. package/dist/templates/trellis/index.js.map +1 -1
  27. package/dist/templates/trellis/scripts/common/task_planning.py +133 -0
  28. package/dist/templates/trellis/scripts/common/task_store.py +20 -1
  29. package/dist/templates/trellis/scripts/subnode_artifact.py +32 -0
  30. package/dist/templates/trellis/scripts/task.py +96 -2
  31. package/dist/templates/trellis/workflow.md +39 -2
  32. package/package.json +2 -2
@@ -0,0 +1,113 @@
1
+ # Multiple Evidence Units
2
+
3
+ Use after the user has authorized independent evidence and the task owns a
4
+ reviewed unit mapping. Read `subnode-work.md` for artifact and acceptance rules.
5
+ Codex inline mode governs native implement/check agents; it does not disable
6
+ explicit Channel evidence. Missing independent reports cannot be replaced by
7
+ main-session pass claims.
8
+
9
+ ## Prepare And Dispatch In One Host Call
10
+
11
+ Choose units by work, complexity, evidence range, and relationship. Combine only
12
+ individually quick/simple and obviously related points with shared context and
13
+ a bounded total workload. Each scope item keeps its own evidence, conclusion,
14
+ unknowns, and stop condition. Neither eight slots nor eight owner domains imply
15
+ eight work packages. Store this mapping in the task's existing plan or matrix.
16
+
17
+ Read the actual native guard and current workers/reservations. Initially fill
18
+ all available capacity in FIFO order; a justified dependency or resource limit
19
+ belongs in the task record, not an arbitrary coordinator throttle. Initialize
20
+ all reviewed briefs before queue creation or spawning. A failed initialization
21
+ stops admission; preserve/reconcile partial artifacts without dispatching them.
22
+
23
+ For a configured subnode profile, `spawn --profile <id> --as <worker>` implies
24
+ the subnode role and inherits its Codex provider; do not repeat
25
+ `--agent subnode --provider codex`. Keep each worker ID and `send --to` explicit.
26
+ Author identity on `send` defaults to `TRELLIS_CHANNEL_AS` or `main`, so routine
27
+ dispatch need not repeat `--as main`.
28
+
29
+ Coalesce operations that can share one noninteractive host invocation. Use ONE
30
+ native `exec_command` containing a standard-library loop over existing CLI
31
+ commands. Multiple `exec_command` calls inside `functions.exec` still count as
32
+ multiple host calls. This is a procedure, not a new Channel batch API, scheduler,
33
+ or worker-state store. Keep init and dispatch as separate admission stages.
34
+
35
+ The following runnable pattern consumes a temporary, reviewed JSON array of
36
+ `{"target": "unit-id", "argv": ["trellis", "channel", ...]}` entries. Use
37
+ `[sys.executable, ".trellis/scripts/subnode_artifact.py", ...]` for artifact
38
+ commands. Put claim, spawn, and send in queue order; do not include waits. Review
39
+ each argument vector and the native capacity before executing. The input and
40
+ raw receipts are temporary command data, not task authority; retain only needed
41
+ non-sensitive evidence and clean the temporary input after use.
42
+
43
+ ```bash
44
+ # python on Windows; python3 elsewhere. Execute this whole block in ONE host call.
45
+ python3 - /absolute/path/to/reviewed-actions.json <<'PY'
46
+ import json
47
+ import subprocess
48
+ import sys
49
+
50
+ actions = json.load(open(sys.argv[1], encoding="utf-8"))
51
+ failed = False
52
+ for action in actions:
53
+ if failed:
54
+ print(json.dumps({"target": action["target"], "status": "not_attempted"}))
55
+ continue
56
+ argv = [sys.executable if part == "{python}" else part for part in action["argv"]]
57
+ try:
58
+ result = subprocess.run(argv, capture_output=True, text=True, check=False)
59
+ failed = result.returncode != 0
60
+ receipt = {"target": action["target"], "argv": argv,
61
+ "status": "error" if failed else "completed",
62
+ "exit_code": result.returncode,
63
+ "stdout": result.stdout, "stderr": result.stderr}
64
+ except OSError as error:
65
+ failed = True
66
+ receipt = {"target": action["target"], "argv": argv,
67
+ "status": "error", "error": str(error)}
68
+ print(json.dumps(receipt), flush=True)
69
+ sys.exit(1 if failed else 0)
70
+ PY
71
+ ```
72
+
73
+ The aggregate exit code is not per-target evidence. Inspect every receipt,
74
+ including missing or conflicting receipts; the first error stops later actions
75
+ and pauses the whole queue. Never retry a claimed attempt. A new approved
76
+ attempt needs a new brief and ID.
77
+
78
+ ## Rolling FIFO
79
+
80
+ 1. Capture a durable barrier before dispatch. Claim the earliest unclaimed unit,
81
+ spawn/send through native Channel, and preserve its receipt. The helper
82
+ enforces claim order; earlier claims need not be accepted to fill initial slots.
83
+ 2. Establish exactly one native waiter for the dispatched workers without
84
+ `--all`. Resume only its live host continuation until it returns, times out,
85
+ or errors; run no other host action meanwhile.
86
+ 3. Recheck dispatched items for failures, conflicts, and unresolved terminal
87
+ states. Still-running healthy workers do not need to finish. Validate the
88
+ completed worker's per-scope report, recheck sources and protected targets,
89
+ then write its create-once `accepted` disposition.
90
+ 4. That acceptance plus verified native capacity authorizes the next unclaimed
91
+ FIFO unit immediately, while other healthy workers continue. Preserve the
92
+ barrier/event cursor so already emitted terminal events cannot be lost.
93
+ 5. Incomplete/blocked/rejected results, validator concerns, capacity refusal,
94
+ missing/conflicting receipts, or unresolvable reservations pause the entire
95
+ queue. A terminal event alone never authorizes replacement. On recovery,
96
+ reconstruct claims, events, workers/reservations, reports, and dispositions;
97
+ never redispatch an old claim or require all healthy live predecessors to
98
+ complete merely to refill an accepted slot.
99
+
100
+ ## Temporary Task Switch
101
+
102
+ Save the old task's checkpoint. Pause refills and drain ALL already dispatched
103
+ units: wait, validate, and disposition each result, including failures; confirm
104
+ the live continuation, worker, and reservation boundaries are closed. A drain
105
+ does not dispatch pending queue items or turn a failure into acceptance. Do not
106
+ automatically kill, retry, or abandon the old queue. Preserve unclaimed work and
107
+ the old phase. Only after drain, run native `task.py select <new-task>`; it
108
+ changes context without status, branch, after_start hooks, or implementation
109
+ authority. With no in-flight work, select directly after saving the checkpoint.
110
+
111
+ When returning, reconstruct only the missing old-task facts and resume only
112
+ still-authorized work. Selecting a user-stopped audit never restarts it. Ordinary
113
+ continue and sufficient compaction recovery retain their direct checkpoint path.
@@ -127,7 +127,7 @@ wait command starts, capture a barrier before that operation and pass it back:
127
127
  ```bash
128
128
  BARRIER="$(trellis channel barrier T)"
129
129
  # spawn or trigger work that may emit a terminal event
130
- trellis channel wait T --as main --workers check \
130
+ trellis channel wait T --workers check \
131
131
  --after-seq "$BARRIER" --timeout 15m
132
132
  ```
133
133
 
@@ -146,10 +146,10 @@ The separate event-filter mode wakes on:
146
146
  Useful filters:
147
147
 
148
148
  ```bash
149
- trellis channel wait T --as main --from check --kind done --timeout 15m
150
- trellis channel wait T --as main --from check,check-cx --kind done --all --timeout 15m
149
+ trellis channel wait T --from check --kind done --timeout 15m
150
+ trellis channel wait T --from check,check-cx --kind done --all --timeout 15m
151
151
  trellis channel wait T --as worker --kind message --timeout 1h
152
- trellis channel wait T --as main --thread release-note --action status --timeout 10m
152
+ trellis channel wait T --thread release-note --action status --timeout 10m
153
153
  ```
154
154
 
155
155
  Exit codes: `0` matched, `124` timeout, `1`/`2` errors. On `wait --all`
@@ -20,7 +20,26 @@ dependencies, stop conditions, deadline, and `channel_ref`. Set `retry_of`
20
20
  only for an explicit manual retry and `counter_of` only for intentional
21
21
  counterwork. A retry names an existing, different subnode in the same task and
22
22
  `work_id`; counterwork may be initialized independently. The helper supplies
23
- the immutable task identity and report path.
23
+ the immutable task identity and report path. New units also require `unit_plan`:
24
+
25
+ ```json
26
+ {
27
+ "unit_plan": {
28
+ "plan_ref": ".trellis/tasks/09-07-example/design.md#evidence-units",
29
+ "sizing_rationale": "One bounded dependency inspection with a separately reviewable result."
30
+ }
31
+ }
32
+ ```
33
+
34
+ The reference must identify an existing regular Markdown document inside this
35
+ task. For multiple scope items, add `grouping_rationale` explaining why every
36
+ item is quick/simple, obviously related, and uses shared context while retaining
37
+ separate conclusions. Record the actual scope mapping and evidence in the task
38
+ plan before initializing briefs; owner domains and slot counts do not determine
39
+ unit counts. Complex or lengthy points need separate units or further splitting.
40
+ The helper checks structure, not the truth of the sizing judgment. Historical
41
+ brief/report readers remain compatible; new init and queue admission require
42
+ the unit plan.
24
43
 
25
44
  ```bash
26
45
  TASK=.trellis/tasks/09-07-example
@@ -117,19 +136,20 @@ the worker can emit a terminal event. The CLI waits once for a worker lifecycle
117
136
  transition after that barrier, including supervisor-authored terminal events:
118
137
 
119
138
  ```bash
120
- trellis channel create subnode-example --by main --cwd "$PWD"
139
+ trellis channel create subnode-example
121
140
  BARRIER="$(trellis channel barrier subnode-example)"
122
- trellis channel spawn subnode-example --agent subnode --provider codex \
123
- --as "$SUBNODE_ID" --cwd "$PWD"
141
+ trellis channel spawn subnode-example --agent subnode --as "$SUBNODE_ID"
124
142
 
125
143
  printf '%s\n' "Read $TASK/subnodes/$WORK_ID/$SUBNODE_ID/brief.json and perform only that bounded work." \
126
- | trellis channel send subnode-example --as main --to "$SUBNODE_ID" \
144
+ | trellis channel send subnode-example --to "$SUBNODE_ID" \
127
145
  --stdin --delivery-mode requireRunningWorker
128
146
 
129
- trellis channel wait subnode-example --as main --workers "$SUBNODE_ID" \
147
+ trellis channel wait subnode-example --workers "$SUBNODE_ID" \
130
148
  --after-seq "$BARRIER" --timeout 30m
131
149
  ```
132
150
 
151
+ When selecting a configured model profile, use `--profile <id>` in place of `--agent subnode`; it implies the subnode role and reads its Codex provider from role frontmatter. Keep the unique worker `--as` for dispatch identity. Omit author `--as` on `send` and `wait` to use `TRELLIS_CHANNEL_AS` or `main`.
152
+
133
153
  `channel.subnode` in `.trellis/config.yaml` supplies the role defaults for
134
154
  `max_live_workers` (generated default `8`), `idle_timeout`, `timeout`, and
135
155
  `warn_before`. Change that section before a dispatch group when its resource
@@ -137,7 +157,12 @@ or lifetime needs differ; pass the corresponding `spawn` flag only for a
137
157
  one-off override. The generic `channel.worker_guard` remains the fallback for
138
158
  ordinary workers and for a subnode key omitted from the project config.
139
159
 
140
- For a group, use `--workers a,b --all` with the barrier captured before dispatch.
160
+ For rolling FIFO dispatch, follow `references/multi-target-dispatch.md`: initially
161
+ fill available native capacity, wait for the first terminal worker, review and
162
+ accept it, then refill while other workers continue. Do not use `--all` as an
163
+ ordinary refill prerequisite. Use `--workers a,b --all` only when the intent
164
+ requires draining all already dispatched workers, with the barrier captured
165
+ before dispatch.
141
166
  Worker mode emits one terminal worker projection per satisfied target. Ordinary
142
167
  adapter errors and peer turn completion do not end the wait. `--from` remains
143
168
  an exact event-author filter; it is not a worker lifecycle selector.
@@ -106,8 +106,7 @@ trellis channel spawn cr-example --agent check --provider codex --as check-cx \
106
106
  --file "$TASK/prd.md" \
107
107
  --file "$TASK/design.md" \
108
108
  --file "$TASK/implement.md" \
109
- --jsonl "$TASK/check.jsonl" \
110
- --cwd "$PWD" --timeout 30m
109
+ --jsonl "$TASK/check.jsonl" --timeout 30m
111
110
  ```
112
111
 
113
112
  The `spawned` event records both the literal `files` array and any `manifests`
@@ -128,7 +127,7 @@ channel:
128
127
  trellis channel spawn cr-feature --agent check --as check-claude
129
128
  trellis channel spawn cr-feature --agent check --provider codex --as check-cx
130
129
 
131
- trellis channel wait cr-feature --as main \
130
+ trellis channel wait cr-feature \
132
131
  --from check-claude,check-cx --kind done --all --timeout 15m
133
132
  ```
134
133
 
@@ -9,7 +9,7 @@ Use when the user says "和 codex/claude 讨论一下", "brainstorm", or "拉一
9
9
  进来一起看".
10
10
 
11
11
  ```bash
12
- trellis channel create brainstorm-storage-layer --by main \
12
+ trellis channel create brainstorm-storage-layer \
13
13
  --task .trellis/tasks/05-XX-storage-adapter
14
14
  BARRIER="$(trellis channel barrier brainstorm-storage-layer)"
15
15
 
@@ -20,10 +20,10 @@ trellis channel spawn brainstorm-storage-layer \
20
20
  --as cx-arch --timeout 30m
21
21
 
22
22
  trellis channel send brainstorm-storage-layer \
23
- --as main --to cx-arch --text-file /tmp/brainstorm-r1.md
23
+ --to cx-arch --text-file /tmp/brainstorm-r1.md
24
24
 
25
25
  trellis channel wait brainstorm-storage-layer \
26
- --as main --kind done --from cx-arch --after-seq "$BARRIER" --timeout 10m
26
+ --kind done --from cx-arch --after-seq "$BARRIER" --timeout 10m
27
27
  ```
28
28
 
29
29
  Do not stop after one answer. Read the answer, identify vague areas, send a
@@ -53,7 +53,7 @@ Use when the user asks to dispatch implementation or review work.
53
53
 
54
54
  ```bash
55
55
  TASK=.trellis/tasks/05-12-foo
56
- trellis channel create cr-foo --task "$TASK" --by main
56
+ trellis channel create cr-foo --task "$TASK"
57
57
  BARRIER="$(trellis channel barrier cr-foo)"
58
58
 
59
59
  trellis channel spawn cr-foo \
@@ -61,11 +61,10 @@ trellis channel spawn cr-foo \
61
61
  --jsonl "$TASK/check.jsonl" \
62
62
  --file "$TASK/prd.md" \
63
63
  --file "$TASK/design.md" \
64
- --file "$TASK/implement.md" \
65
- --cwd "$PWD" --timeout 15m
64
+ --file "$TASK/implement.md" --timeout 15m
66
65
 
67
- trellis channel send cr-foo --as main --to check --text-file /tmp/cr-brief.md
68
- trellis channel wait cr-foo --as main --kind done --from check --after-seq "$BARRIER" --timeout 15m
66
+ trellis channel send cr-foo --to check --text-file /tmp/cr-brief.md
67
+ trellis channel wait cr-foo --kind done --from check --after-seq "$BARRIER" --timeout 15m
69
68
  trellis channel messages cr-foo --kind message --from check --tag final_answer
70
69
  ```
71
70
 
@@ -78,7 +77,7 @@ already run.
78
77
  Use one channel and distinct worker names.
79
78
 
80
79
  ```bash
81
- trellis channel create cr-feature --by main --ephemeral
80
+ trellis channel create cr-feature --ephemeral
82
81
  BARRIER="$(trellis channel barrier cr-feature)"
83
82
 
84
83
  trellis channel spawn cr-feature --agent check \
@@ -89,9 +88,9 @@ trellis channel spawn cr-feature --agent check --provider codex --as check-cx \
89
88
  --jsonl "$TASK/check.jsonl" --file "$TASK/prd.md" --file "$TASK/design.md" \
90
89
  --timeout 15m
91
90
 
92
- trellis channel send cr-feature --as main --to check --text-file /tmp/cr-brief.md
93
- trellis channel send cr-feature --as main --to check-cx --text-file /tmp/cr-brief.md
94
- trellis channel wait cr-feature --as main --kind done --from check,check-cx --all --after-seq "$BARRIER" --timeout 15m
91
+ trellis channel send cr-feature --to check --text-file /tmp/cr-brief.md
92
+ trellis channel send cr-feature --to check-cx --text-file /tmp/cr-brief.md
93
+ trellis channel wait cr-feature --kind done --from check,check-cx --all --after-seq "$BARRIER" --timeout 15m
95
94
  ```
96
95
 
97
96
  `--all` means every listed worker must emit a matching event.
@@ -10,6 +10,7 @@ Task lifecycle includes creation, start, context configuration, finish, archive,
10
10
  4. `.trellis/scripts/common/task_store.py`
11
11
  5. `.trellis/scripts/common/task_utils.py`
12
12
  6. The current task's `.trellis/tasks/<task>/task.json`
13
+ 7. `.trellis/scripts/common/task_planning.py` for material revisions and start admission
13
14
 
14
15
  ## Common Needs And Edit Points
15
16
 
@@ -23,6 +24,8 @@ Task lifecycle includes creation, start, context configuration, finish, archive,
23
24
  | Change default task fields | `.trellis/scripts/common/task_store.py`. |
24
25
  | Change task parsing/search | `.trellis/scripts/common/task_utils.py`. |
25
26
  | Change active task behavior | `.trellis/scripts/common/active_task.py`. |
27
+ | Select context without starting | Native `task.py select`; preserve phase/branch and drain live Channel work first. |
28
+ | Seal and record later approval of a material plan | Native `task.py plan seal/approve`; reserved `meta.planning`, owned by `common/task_planning.py`. |
26
29
 
27
30
  ## lifecycle hooks
28
31
 
@@ -44,7 +47,7 @@ Hook commands receive the `TASK_JSON_PATH` environment variable, pointing to the
44
47
 
45
48
  ## Change Task Fields
46
49
 
47
- If the user wants to add project-local fields, prefer putting them under `meta` in `task.json` to avoid breaking existing scripts' assumptions about standard fields.
50
+ If the user wants to add project-local fields, prefer putting them under `meta` in `task.json` to avoid breaking existing scripts' assumptions about standard fields. `meta.planning` is reserved for native seal/approve; do not prefill or overwrite it through generic metadata. Classification uses `execution_class=direct|planned` and `delivery_mode=change_bearing|analysis_only`.
48
51
 
49
52
  Example:
50
53
 
@@ -70,7 +73,8 @@ Active task is session-level state stored in `.trellis/.runtime/sessions/`. Do n
70
73
  `cmd_create` in `.trellis/scripts/common/task_store.py` calls `set_active_task` best-effort right after writing the new task directory. The behavior:
71
74
 
72
75
  - When the calling shell carries session identity (`TRELLIS_CONTEXT_ID` env var, or any platform-specific session env that `resolve_context_key` recognizes — see `active_task.py:_ENV_SESSION_KEYS`), the per-session pointer at `.trellis/.runtime/sessions/<context_key>.json` is rewritten to point at the new task. The task's `status=planning` and `[workflow-state:planning]` fires on the very next `UserPromptSubmit`.
73
- - When session identity is unavailable (raw CLI invocation outside an AI session, or a platform that doesn't propagate identity to shell), the task directory is still created and `status=planning` is still written, but the active pointer is left untouched. The user can attach the task later with `task.py start <dir>` once they're back in an AI session.
76
+ - When session identity is unavailable (raw CLI invocation outside an AI session, or a platform that doesn't propagate identity to shell), the task directory is still created and `status=planning` is still written, but the active pointer is left untouched. Attach planning context later with `task.py select <dir>` once identity is available; start requires its own phase/approval gates.
77
+ - `create --no-start` deliberately preserves the prior pointer; use select to switch context after saving the checkpoint and draining already dispatched Channel work. Selecting does not change phase/branch, run after_start, or grant implementation authority.
74
78
 
75
79
  This makes `[workflow-state:planning]` the live breadcrumb during the brainstorm and JSONL curation work that follows `task.py create`. The pre-R7 behavior left the breadcrumb stuck on `no_task` until `task.py start`, so the planning block was effectively dead text.
76
80
 
@@ -43,6 +43,8 @@ The Trellis task system is stored entirely under `.trellis/tasks/` in the user p
43
43
  | `children` / `parent` | Parent/child task relationships. |
44
44
  | `commit` / `pr_url` | Commit and PR information after completion. |
45
45
  | `meta` | Extension fields. |
46
+ | `meta.execution_class` / `meta.delivery_mode` | Explicit task classification; planned/change-bearing start needs current material-plan approval. |
47
+ | `meta.planning` | Reserved native material revision, seal, and later approval; use plan seal/approve, never generic metadata. |
46
48
 
47
49
  ## Parent / Child Task Trees
48
50
 
@@ -81,7 +83,7 @@ The user sees a "current task," but Trellis stores active task state per session
81
83
  .trellis/.runtime/sessions/<context-key>.json
82
84
  ```
83
85
 
84
- `task.py start` writes the task path into the runtime session file for the current session. `task.py current --source` shows the current task and where it came from. Different AI windows can point to different tasks without overwriting each other.
86
+ `task.py select` writes only the current session's task context; status/branch and implementation authority are unchanged. `task.py start` also enters execution after its admission gates. `task.py current --source` shows the current task and where it came from. Different AI windows can point to different tasks without overwriting each other. Before switching with live Channel work, pause refills and drain already dispatched units/reservations while preserving pending work and the old phase.
85
87
 
86
88
  If the platform or shell environment has no stable session identity, `task.py start` may be unable to set the active task. The AI should read the error, inspect the platform hook/session environment, and not fall back to a shared global pointer.
87
89
 
@@ -107,6 +109,9 @@ Rules:
107
109
 
108
110
  ```bash
109
111
  python3 ./.trellis/scripts/task.py create "<title>" --description "<one-line summary>" --slug <slug>
112
+ python3 ./.trellis/scripts/task.py select <task>
113
+ python3 ./.trellis/scripts/task.py plan seal <task>
114
+ python3 ./.trellis/scripts/task.py plan approve <task> --revision <n> --basis "<actual later approval>"
110
115
  python3 ./.trellis/scripts/task.py start <task>
111
116
  python3 ./.trellis/scripts/task.py current --source
112
117
  python3 ./.trellis/scripts/task.py add-context <task> implement <file> <reason>
@@ -33,7 +33,8 @@ a direct task binding. For `unbound` / `unbound_ambiguous`, review existing task
33
33
  artifacts and select by the user's explicit intent. Exit code 1 for ambiguity
34
34
  does not mean identity is absent. Do not guess, duplicate tasks, invent identity,
35
35
  or edit runtime pointers. Return a planning candidate to the planning gates below;
36
- use native `task.py start <task>` only when its activation contract permits it.
36
+ use native `task.py select <task>` to bind planning context after any required
37
+ Channel drain; use `task.py start` only when its activation contract permits it.
37
38
  An eligible `analysis_only` candidate remains in planning without start.
38
39
  If `session_source` is null, report unavailable identity separately.
39
40
 
@@ -55,7 +56,7 @@ Run only when the phase or routing rule is missing; otherwise reuse it.
55
56
  - `status=in_progress` + a material unresolved decision → record the reason and run `task.py replan <task> "<reason>"`; do not ask a native question during implementation.
56
57
  - `status=planning` + `prd.md` only → decide whether the task is lightweight or complex. Lightweight can move to **1.4** review; complex returns to **1.1** to add `design.md` + `implement.md`.
57
58
  - `status=planning` + complex artifacts complete + sub-agent jsonl not curated (empty, or only a legacy `_example` placeholder row) → **1.3**
58
- - `status=planning` + required artifacts complete + required jsonl curated or inline mode → run the Planning Seal closure pass, then **1.4**; honor existing implementation authorization and ask for start approval only if it is missing.
59
+ - `status=planning` + required artifacts complete + required jsonl curated or inline mode → run the Planning Seal closure pass, then **1.4**. Existing authorization must be a later explicit implementation approval for this task's current sealed material revision. Initial requests, design answers, and parent-task approval do not qualify. Use native plan seal/approve/start; ask only when that approval is missing. A replan invalidates it; minor progress edits do not.
59
60
  - `status=in_progress` + implementation not started → **2.1**
60
61
  - `status=in_progress` + implementation done, not yet checked → **2.2**
61
62
  - `status=in_progress` + check passed → **3.3** (spec update) → **3.4** (commit)
@@ -45,6 +45,7 @@ From Step 1 you know the current task and status. Check the task directory:
45
45
  - **Active task with `task.json.meta.delivery_mode = "analysis_only"`** → keep `planning`, complete the PRD's bounded evidence work, then verify the no-change boundary, commit task artifacts, and archive directly. Do not run `task.py start`; any protected-target change needs a separate change-bearing task.
46
46
  - **Active task status `planning` + no `prd.md`** → Phase 1.1. Load the `trellis-brainstorm` skill.
47
47
  - **Active task status `planning` + `prd.md` exists** → stay in Phase 1. Lightweight tasks can be PRD-only; complex tasks need `design.md` + `implement.md`. Load the relevant Phase 1 step detail before `task.py start`.
48
+ - **Existing task selected by explicit intent but not bound** → use native `task.py select` for context only. Drain already dispatched Channel units before a real task switch. Planned/change-bearing start requires native plan seal and matching later approval for this task's current material revision; selecting or recovering context does not approve implementation.
48
49
  - **Active task status `in_progress`** → Phase 2 step 2.1. Load the step detail:
49
50
  ```bash
50
51
  {{PYTHON_CMD}} ./.trellis/scripts/get_context.py --mode phase --step 2.1 --platform {{CLI_FLAG}}
@@ -30,6 +30,15 @@ Repository evidence establishes current behavior and technical constraints. The
30
30
 
31
31
  When research, audit, review, or investigation is too large to leave one independently useful conclusion in the current bounded session, split it into evidence units. Each unit must have one question or scope, a minimal evidence range, a destination artifact, and a stop condition; write its facts, conclusion or blocker, unknowns, and recovery point before starting another unit. Size units so one normal context window can finish and persist one useful result; do not promise an exact token or time limit. Routine navigation and transient tool output do not need an artifact. Create a child task only when the unit has an independent owner, lifecycle, and acceptance contract.
32
32
 
33
+ Persist the unit-to-point mapping in this task's existing plan/matrix before
34
+ dispatch. Include workload rationale, dependencies, minimal evidence, shared
35
+ context, and per-point delivery. Combine points only when each is quick/simple
36
+ and they are obviously related; explain the grouping and bounded total workload.
37
+ Complex or lengthy points need separate units or further splitting. Slots and
38
+ owner domains do not determine unit count. Explicit independent subnodes use
39
+ `trellis-channel`'s unit-plan and multi-target procedure; planning itself does
40
+ not authorize dispatch.
41
+
33
42
  ---
34
43
 
35
44
  Use this skill during Phase 1 planning to turn the user's request into clear requirements and planning artifacts.
@@ -65,7 +74,11 @@ Use a concise title from the user's request. Both the title and `--description`
65
74
  6. When no user-owned decision remains, create or update `design.md` and `implement.md` for complex tasks.
66
75
  7. Run the requirement convergence gate, then the PRD convergence pass. Finish with one Planning Seal closure pass.
67
76
  8. Present the final planning summary and stop. Do not run `task.py start` or edit product code in the same turn.
68
- 9. Only a subsequent user message that explicitly approves the latest planning summary authorizes `task.py start` and implementation. If implementation reveals a material unresolved decision, record `decision-needed`, run `task.py replan <task> "<reason>"`, and return through this planning flow; do not open a popup during implementation.
77
+ 9. For planned/change-bearing tasks, classify `execution_class=planned` and `delivery_mode=change_bearing` in native task meta, then run `task.py plan seal <task>` after closure. Only a subsequent user message explicitly approving this task's current material plan authorizes `task.py plan approve <task> --revision <n> --basis "<short non-sensitive actual approval basis>"`, followed by `task.py start` and implementation. Initial delivery requests, parent-task approval, and design answers are insufficient. If scope, owner, risk, public behavior, or acceptance materially changes, run `task.py replan <task> "<reason>"`; it invalidates seal/approval. Return through planning, seal the new revision, present it, and obtain later approval. Minor wording, formatting, and progress records do not require resealing. The native record enforces structure, not authenticity of chat approval.
78
+
79
+ When changing the active task only for planning, use native `task.py select`,
80
+ not start. `create --no-start` intentionally preserves the old pointer. Follow
81
+ the Channel drain procedure before switching with live evidence workers.
69
82
 
70
83
  Do not invent a project-specific product/spec hierarchy. If the repository already has product, domain, or spec docs, use them. If it does not, proceed with the evidence that exists.
71
84
 
@@ -363,7 +363,8 @@ def _codex_mode_banner(config: dict) -> str:
363
363
  else:
364
364
  meaning = (
365
365
  "inline: the main session implements/checks directly; "
366
- "do not dispatch implement/check sub-agents."
366
+ "do not dispatch implement/check sub-agents. Explicit Channel independent-evidence "
367
+ "subnodes follow the selected project workflow and remain available in inline mode."
367
368
  )
368
369
  return f"<codex-mode>{meaning}</codex-mode>"
369
370
 
@@ -36,6 +36,7 @@ export declare const commonTasks: string;
36
36
  export declare const commonTaskContext: string;
37
37
  export declare const commonContextProjection: string;
38
38
  export declare const commonTaskStore: string;
39
+ export declare const commonTaskPlanning: string;
39
40
  export declare const commonSessionContext: string;
40
41
  export declare const commonContinuationRecord: string;
41
42
  export declare const commonOwnershipRecord: string;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/templates/trellis/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAcH,eAAO,MAAM,WAAW,QAAsC,CAAC;AAG/D,eAAO,MAAM,UAAU,QAA6C,CAAC;AACrE,eAAO,MAAM,WAAW,QAA0C,CAAC;AACnE,eAAO,MAAM,eAAe,QAA8C,CAAC;AAC3E,eAAO,MAAM,gBAAgB,QAAgD,CAAC;AAC9E,eAAO,MAAM,eAAe,QAA+C,CAAC;AAC5E,eAAO,MAAM,eAAe,QAA+C,CAAC;AAC5E,eAAO,MAAM,gBAAgB,QAAgD,CAAC;AAC9E,eAAO,MAAM,gBAAgB,QAAgD,CAAC;AAC9E,eAAO,MAAM,YAAY,QAA2C,CAAC;AACrE,eAAO,MAAM,QAAQ,QAAuC,CAAC;AAC7D,eAAO,MAAM,SAAS,QAAwC,CAAC;AAC/D,eAAO,MAAM,SAAS,QAAwC,CAAC;AAC/D,eAAO,MAAM,WAAW,QAA0C,CAAC;AACnE,eAAO,MAAM,WAAW,QAA0C,CAAC;AACnE,eAAO,MAAM,iBAAiB,QAAiD,CAAC;AAChF,eAAO,MAAM,uBAAuB,QAEnC,CAAC;AACF,eAAO,MAAM,eAAe,QAA+C,CAAC;AAC5E,eAAO,MAAM,oBAAoB,QAEhC,CAAC;AACF,eAAO,MAAM,wBAAwB,QAEpC,CAAC;AACF,eAAO,MAAM,qBAAqB,QAEjC,CAAC;AACF,eAAO,MAAM,qBAAqB,QAEjC,CAAC;AACF,eAAO,MAAM,mBAAmB,QAE/B,CAAC;AACF,eAAO,MAAM,uBAAuB,QAEnC,CAAC;AACF,eAAO,MAAM,mBAAmB,QAE/B,CAAC;AACF,eAAO,MAAM,eAAe,QAA+C,CAAC;AAC5E,eAAO,MAAM,gBAAgB,QAAgD,CAAC;AAC9E,eAAO,MAAM,gBAAgB,QAAgD,CAAC;AAG9E,eAAO,MAAM,kBAAkB,QAA2C,CAAC;AAC3E,eAAO,MAAM,mBAAmB,QAA4C,CAAC;AAC7E,eAAO,MAAM,UAAU,QAAkC,CAAC;AAC1D,eAAO,MAAM,gBAAgB,QAAyC,CAAC;AACvE,eAAO,MAAM,gBAAgB,QAAyC,CAAC;AACvE,eAAO,MAAM,qBAAqB,QAEjC,CAAC;AACF,eAAO,MAAM,mBAAmB,QAA4C,CAAC;AAG7E,eAAO,MAAM,kBAAkB,QAA8B,CAAC;AAC9D,eAAO,MAAM,kBAAkB,QAA8B,CAAC;AAC9D,eAAO,MAAM,iBAAiB,QAAgC,CAAC;AAC/D,eAAO,MAAM,qBAAqB,QAAoC,CAAC;AAMvE,eAAO,MAAM,sBAAsB,QAAsC,CAAC;AAC1E,eAAO,MAAM,kBAAkB,QAAkC,CAAC;AAClE,eAAO,MAAM,oBAAoB,QAAoC,CAAC;AACtE,eAAO,MAAM,uBAAuB,QAEnC,CAAC;AAEF;;GAEG;AACH,wBAAgB,aAAa,IAAI,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CA6CnD;AAED;;;;;;;GAOG;AACH,wBAAgB,YAAY,IAAI,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAOlD"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/templates/trellis/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAcH,eAAO,MAAM,WAAW,QAAsC,CAAC;AAG/D,eAAO,MAAM,UAAU,QAA6C,CAAC;AACrE,eAAO,MAAM,WAAW,QAA0C,CAAC;AACnE,eAAO,MAAM,eAAe,QAA8C,CAAC;AAC3E,eAAO,MAAM,gBAAgB,QAAgD,CAAC;AAC9E,eAAO,MAAM,eAAe,QAA+C,CAAC;AAC5E,eAAO,MAAM,eAAe,QAA+C,CAAC;AAC5E,eAAO,MAAM,gBAAgB,QAAgD,CAAC;AAC9E,eAAO,MAAM,gBAAgB,QAAgD,CAAC;AAC9E,eAAO,MAAM,YAAY,QAA2C,CAAC;AACrE,eAAO,MAAM,QAAQ,QAAuC,CAAC;AAC7D,eAAO,MAAM,SAAS,QAAwC,CAAC;AAC/D,eAAO,MAAM,SAAS,QAAwC,CAAC;AAC/D,eAAO,MAAM,WAAW,QAA0C,CAAC;AACnE,eAAO,MAAM,WAAW,QAA0C,CAAC;AACnE,eAAO,MAAM,iBAAiB,QAAiD,CAAC;AAChF,eAAO,MAAM,uBAAuB,QAEnC,CAAC;AACF,eAAO,MAAM,eAAe,QAA+C,CAAC;AAC5E,eAAO,MAAM,kBAAkB,QAE9B,CAAC;AACF,eAAO,MAAM,oBAAoB,QAEhC,CAAC;AACF,eAAO,MAAM,wBAAwB,QAEpC,CAAC;AACF,eAAO,MAAM,qBAAqB,QAEjC,CAAC;AACF,eAAO,MAAM,qBAAqB,QAEjC,CAAC;AACF,eAAO,MAAM,mBAAmB,QAE/B,CAAC;AACF,eAAO,MAAM,uBAAuB,QAEnC,CAAC;AACF,eAAO,MAAM,mBAAmB,QAE/B,CAAC;AACF,eAAO,MAAM,eAAe,QAA+C,CAAC;AAC5E,eAAO,MAAM,gBAAgB,QAAgD,CAAC;AAC9E,eAAO,MAAM,gBAAgB,QAAgD,CAAC;AAG9E,eAAO,MAAM,kBAAkB,QAA2C,CAAC;AAC3E,eAAO,MAAM,mBAAmB,QAA4C,CAAC;AAC7E,eAAO,MAAM,UAAU,QAAkC,CAAC;AAC1D,eAAO,MAAM,gBAAgB,QAAyC,CAAC;AACvE,eAAO,MAAM,gBAAgB,QAAyC,CAAC;AACvE,eAAO,MAAM,qBAAqB,QAEjC,CAAC;AACF,eAAO,MAAM,mBAAmB,QAA4C,CAAC;AAG7E,eAAO,MAAM,kBAAkB,QAA8B,CAAC;AAC9D,eAAO,MAAM,kBAAkB,QAA8B,CAAC;AAC9D,eAAO,MAAM,iBAAiB,QAAgC,CAAC;AAC/D,eAAO,MAAM,qBAAqB,QAAoC,CAAC;AAMvE,eAAO,MAAM,sBAAsB,QAAsC,CAAC;AAC1E,eAAO,MAAM,kBAAkB,QAAkC,CAAC;AAClE,eAAO,MAAM,oBAAoB,QAAoC,CAAC;AACtE,eAAO,MAAM,uBAAuB,QAEnC,CAAC;AAEF;;GAEG;AACH,wBAAgB,aAAa,IAAI,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CA8CnD;AAED;;;;;;;GAOG;AACH,wBAAgB,YAAY,IAAI,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAOlD"}
@@ -46,6 +46,7 @@ export const commonTasks = readTemplate("scripts/common/tasks.py");
46
46
  export const commonTaskContext = readTemplate("scripts/common/task_context.py");
47
47
  export const commonContextProjection = readTemplate("scripts/common/context_projection.py");
48
48
  export const commonTaskStore = readTemplate("scripts/common/task_store.py");
49
+ export const commonTaskPlanning = readTemplate("scripts/common/task_planning.py");
49
50
  export const commonSessionContext = readTemplate("scripts/common/session_context.py");
50
51
  export const commonContinuationRecord = readTemplate("scripts/common/continuation_record.py");
51
52
  export const commonOwnershipRecord = readTemplate("scripts/common/ownership_record.py");
@@ -102,6 +103,7 @@ export function getAllScripts() {
102
103
  scripts.set("common/task_context.py", commonTaskContext);
103
104
  scripts.set("common/context_projection.py", commonContextProjection);
104
105
  scripts.set("common/task_store.py", commonTaskStore);
106
+ scripts.set("common/task_planning.py", commonTaskPlanning);
105
107
  scripts.set("common/session_context.py", commonSessionContext);
106
108
  scripts.set("common/continuation_record.py", commonContinuationRecord);
107
109
  scripts.set("common/ownership_record.py", commonOwnershipRecord);
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/templates/trellis/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/templates/trellis/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,133 @@
1
+ """Task-local material plan revisions; chat approval remains coordinator-owned."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from datetime import datetime, timezone
6
+ from pathlib import Path
7
+ from typing import Any
8
+
9
+
10
+ class PlanningError(ValueError):
11
+ """A planning contract needs correction before a task can start."""
12
+
13
+
14
+ def validate_meta_value(key: str, value: str) -> None:
15
+ if key == "planning" or key.startswith("planning."):
16
+ raise PlanningError("meta.planning is reserved; use task.py plan seal/approve")
17
+ choices = {
18
+ "execution_class": {"direct", "planned"},
19
+ "delivery_mode": {"change_bearing", "analysis_only"},
20
+ }
21
+ if key in choices and value not in choices[key]:
22
+ raise PlanningError(f"{key} must be one of: {', '.join(sorted(choices[key]))}")
23
+
24
+
25
+ def classification(data: dict[str, Any]) -> tuple[str, str]:
26
+ meta = data.get("meta", {})
27
+ if not isinstance(meta, dict):
28
+ raise PlanningError("task meta must be an object")
29
+ execution = meta.get("execution_class")
30
+ delivery = meta.get("delivery_mode")
31
+ if execution not in ("direct", "planned") or delivery not in ("change_bearing", "analysis_only"):
32
+ raise PlanningError("classify this task with execution_class=direct|planned and delivery_mode=change_bearing|analysis_only before start")
33
+ return execution, delivery
34
+
35
+
36
+ def planning_record(data: dict[str, Any]) -> dict[str, Any]:
37
+ meta = data.get("meta", {})
38
+ if not isinstance(meta, dict):
39
+ raise PlanningError("task meta must be an object")
40
+ record = meta.get("planning", {})
41
+ if not isinstance(record, dict):
42
+ raise PlanningError("meta.planning must be an object")
43
+ revision = record.get("revision", 1)
44
+ if isinstance(revision, bool) or not isinstance(revision, int) or revision < 1:
45
+ raise PlanningError("planning revision must be a positive integer")
46
+ return {**record, "revision": revision}
47
+
48
+
49
+ def invalidate_plan(data: dict[str, Any]) -> None:
50
+ record = planning_record(data)
51
+ data.setdefault("meta", {})["planning"] = {"revision": record["revision"] + 1}
52
+
53
+
54
+ def _plan_documents(task_dir: Path, execution: str, delivery: str) -> list[str]:
55
+ names = ["prd.md"]
56
+ if execution == "planned":
57
+ names.append("design.md")
58
+ if delivery == "change_bearing":
59
+ names.append("implement.md")
60
+ for name in names:
61
+ document = task_dir / name
62
+ if document.is_symlink() or not document.is_file():
63
+ raise PlanningError(f"plan requires a regular task document: {name}")
64
+ if document.stat().st_size > 256 * 1024 or not document.read_text(encoding="utf-8").strip():
65
+ raise PlanningError(f"plan document must be bounded, non-empty UTF-8: {name}")
66
+ return names
67
+
68
+
69
+ def seal_plan(data: dict[str, Any], task_dir: Path) -> int:
70
+ execution, delivery = classification(data)
71
+ documents = _plan_documents(task_dir, execution, delivery)
72
+ record = planning_record(data)
73
+ # Resealing an already sealed plan declares a material new version. A replan
74
+ # already advanced the revision; its first seal keeps that revision.
75
+ revision = record["revision"] + (1 if record.get("seal") else 0)
76
+ data.setdefault("meta", {})["planning"] = {
77
+ "revision": revision,
78
+ "seal": {
79
+ "revision": revision,
80
+ "task_id": data.get("id") or task_dir.name,
81
+ "task_name": task_dir.name,
82
+ "documents": documents,
83
+ "execution_class": execution,
84
+ "delivery_mode": delivery,
85
+ "sealed_at": datetime.now(timezone.utc).isoformat(),
86
+ },
87
+ }
88
+ return revision
89
+
90
+
91
+ def _require_seal(data: dict[str, Any], task_dir: Path) -> dict[str, Any]:
92
+ execution, delivery = classification(data)
93
+ record = planning_record(data)
94
+ seal = record.get("seal")
95
+ if not isinstance(seal, dict) or type(seal.get("revision")) is not int or seal.get("revision") != record["revision"]:
96
+ raise PlanningError("current material plan is not sealed; use task.py plan seal")
97
+ if seal.get("task_id") != (data.get("id") or task_dir.name) or seal.get("task_name") != task_dir.name:
98
+ raise PlanningError("sealed plan belongs to another task")
99
+ if seal.get("execution_class") != execution or seal.get("delivery_mode") != delivery:
100
+ raise PlanningError("plan classification changed; reseal the material plan")
101
+ if seal.get("documents") != _plan_documents(task_dir, execution, delivery):
102
+ raise PlanningError("sealed plan documents do not match this task")
103
+ return record
104
+
105
+
106
+ def approve_plan(data: dict[str, Any], task_dir: Path, revision: int, basis: str) -> None:
107
+ record = _require_seal(data, task_dir)
108
+ if revision != record["revision"]:
109
+ raise PlanningError(f"approval revision must match current revision {record['revision']}")
110
+ if not basis.strip() or len(basis) > 1024 or "\x00" in basis:
111
+ raise PlanningError("approval basis must be non-empty bounded text without credentials")
112
+ record.update({
113
+ "approved_revision": revision,
114
+ "approval_basis": basis.strip(),
115
+ "approved_at": datetime.now(timezone.utc).isoformat(),
116
+ })
117
+ data["meta"]["planning"] = record
118
+
119
+
120
+ def require_start_approval(data: dict[str, Any], task_dir: Path) -> None:
121
+ if data.get("status") not in {"planning", "in_progress"}:
122
+ raise PlanningError("start requires an active planning or in_progress task")
123
+ # Existing running tasks retain their authorization; only crossing the
124
+ # planning boundary is gated. Selecting a task never crosses that boundary.
125
+ if data.get("status") == "in_progress":
126
+ return
127
+ execution, delivery = classification(data)
128
+ if delivery == "analysis_only":
129
+ raise PlanningError("analysis_only tasks remain in planning and cannot be started")
130
+ if execution == "planned" and delivery == "change_bearing":
131
+ record = _require_seal(data, task_dir)
132
+ if type(record.get("approved_revision")) is not int or record.get("approved_revision") != record["revision"] or not record.get("approval_basis"):
133
+ raise PlanningError("current sealed plan has no matching later implementation approval; use task.py plan approve only after the user's approval")