axstack 0.49.1 → 0.50.1

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 (42) hide show
  1. package/README.md +5 -7
  2. package/docs/concepts.md +11 -51
  3. package/docs/host-operations.md +24 -99
  4. package/docs/installation.md +27 -52
  5. package/docs/workflows.md +48 -35
  6. package/package.json +1 -1
  7. package/profiles/presets/claude-only.json +0 -37
  8. package/profiles/presets/codex-only.json +0 -36
  9. package/profiles/presets/mixed.json +4 -41
  10. package/skills/axstack/references/automations.md +33 -5
  11. package/skills/axstack/references/autopilot.md +7 -5
  12. package/skills/axstack/references/candidate-publication.md +1 -0
  13. package/skills/axstack/references/contracts.md +55 -7
  14. package/skills/axstack/references/lifecycle.md +20 -5
  15. package/skills/axstack/references/pr-shape.md +15 -0
  16. package/skills/axstack/references/pr-triage-nightly.md +14 -2
  17. package/skills/axstack/references/review-manager-prompt.md +18 -11
  18. package/skills/axstack/references/role-roster.md +4 -9
  19. package/skills/axstack/references/routing.md +3 -7
  20. package/skills/axstack/references/t3-runtime.md +122 -103
  21. package/skills/axstack/references/test-audit-weekly.md +14 -2
  22. package/skills/axstack/references/workspace-hygiene.md +14 -2
  23. package/skills/axstack/scripts/dispatch-plan.js +10 -27
  24. package/skills/axstack/scripts/resolve-models.js +9 -18
  25. package/skills/axstack-brainstorm/references/arena.md +2 -2
  26. package/skills/axstack-cleanup/SKILL.md +6 -3
  27. package/skills/axstack-implement/SKILL.md +5 -4
  28. package/skills/axstack-research/SKILL.md +3 -5
  29. package/skills/axstack-review/SKILL.md +7 -3
  30. package/skills/axstack-scout/SKILL.md +2 -12
  31. package/skills/axstack-watch/SKILL.md +43 -8
  32. package/skills/axstack-watch/references/escalation.md +1 -1
  33. package/skills/axstack-watch/references/proven-verification.md +1 -1
  34. package/skills/axstack-watch/references/repair-publication.md +1 -1
  35. package/skills/axstack-watch/references/watch-runtime.md +46 -33
  36. package/src/instructions.js +4 -3
  37. package/src/roles.js +3 -6
  38. package/skills/axstack/scripts/account-usage.js +0 -79
  39. package/skills/axstack/scripts/pick-instance.js +0 -57
  40. package/skills/axstack/scripts/sync-default.js +0 -191
  41. package/skills/axstack/systemd/axstack-default-sync.service +0 -8
  42. package/skills/axstack/systemd/axstack-default-sync.timer +0 -11
@@ -12,8 +12,7 @@ or use an explicit user selection in the run record. The legacy manifest
12
12
  manifest value does not create a contradiction. Missing or contradictory installed
13
13
  preset / explicit user selection: setup gap, hold. Never infer from live profiles, harness,
14
14
  tools, credentials, quota, subscription, or default to `mixed`.
15
- Only same-provider, same-model account selection among instances of one driver
16
- may use headroom under [Provider bindings](t3-runtime.md#preflight-and-binding);
15
+ Follow [Provider bindings](t3-runtime.md#preflight-and-binding);
17
16
  provider/model substitution still requires the user's decision.
18
17
 
19
18
  At start, snapshot all role IDs from installed `skills/axstack/roles.json`,
@@ -30,9 +29,6 @@ using saved T3 capabilities JSON; missing or malformed capabilities holds.
30
29
  Claude exact IDs come from capabilities, replacing transcript read-back.
31
30
  Use an explicit model as given; for `model:null` without a class, grok uses the
32
31
  provider's first listed model from saved capabilities and records its exact ID.
33
- For `model:null` without a class, Antigravity must select the first listed model
34
- whose ID ends with `-<effort>` from saved capabilities and record its exact ID.
35
- Missing effort-suffix matches hold resolution for Antigravity.
36
32
  A Codex or Claude role with neither model nor class is an intentional absence
37
33
  and holds.
38
34
  Resume must reuse the saved capabilities and role snapshot with no re-resolution; changes require the user’s explicit decision.
@@ -40,8 +36,7 @@ An unavailable provider, model, role, mode or effort holds that role with no sub
40
36
  Preset changes apply to new runs only; an active run keeps its snapshot.
41
37
  Replacing a session needs an explicit user decision and revalidation.
42
38
  Timeout, quota, auth and rejection hold affected work.
43
- An exhausted account with no eligible sibling still holds; dispatched roles never fail over mid-thread.
44
- Follow [Provider bindings](t3-runtime.md#preflight-and-binding) for driver account re-selection at turn boundaries.
39
+ Follow [Provider bindings](t3-runtime.md#preflight-and-binding).
45
40
  [Model discipline](contracts.md#model-discipline) governs optional seats,
46
41
  auditor preflight, and required holds; [Role roster](role-roster.md) governs
47
42
  single-provider absence, mixed research with at least two different providers,
@@ -148,4 +143,5 @@ not alone a formal spec trigger. Hold affected unsafe work while reassessing.
148
143
  author provenance — then use `axstack-review` and `axstack-watch` without
149
144
  repeated approval or new spec ceremony. Never infer the author from the
150
145
  orchestrator or assume an imported own PR's author.
146
+ Before pushing a stale or external PR, follow [adoption dispositions](../../axstack-watch/SKILL.md#stale-or-external-prs).
151
147
  - Direct later phase: start there and pass that phase's identity check.
@@ -29,73 +29,14 @@ preset and stable role IDs, requested provider/model/class/mode/effort, resolved
29
29
  ID, source and time once. Resume preserves that snapshot with no re-resolution;
30
30
  changes require the user's explicit decision. Bundled presets are setup inputs.
31
31
 
32
- Provider bindings must map grok→`grok` and antigravity→`antigravity`, with
33
- canonical error-exit fallbacks codex→`codex` and claude→`claudeAgent`.
34
- At each dispatch or launch, claude and codex must bind to the instanceId printed
35
- by `scripts/pick-instance.js --provider <provider>`.
36
- For dispatched roles, only error exit 1 permits fallback to the canonical instance after validating availability.
37
- Exit 2 (no eligible provider instances) must hold the work without fallback.
38
- Record the chosen instanceId and a pointer to saved `--json` output in the dispatch record.
39
- Only same-provider, same-model account selection among instances of one driver
40
- is permitted, with provider, model, class and effort rules required to remain unchanged.
41
- An exhausted account with no eligible sibling must hold.
42
- Dispatched roles never fail over mid-thread.
43
-
44
- When the driver starts or resumes a run and at the start of every run-watch wake,
45
- it runs `scripts/pick-instance.js --provider <its own provider> --json`.
46
- Read its current binding with `t3_thread_configuration` and save picker JSON in private run evidence.
47
- If the driver's own current instance is `excluded` for a usage limit and an eligible
48
- same-provider sibling exists, it must switch itself via `t3_thread_configure` to the
49
- chosen sibling instance, keeping the same provider, model and effort/options, then continue.
50
- The driver must record from/to instance, a pointer to saved picker JSON and UTC time in `progress.md`.
51
- If the driver's own current instance is eligible, it must stay despite headroom differences.
52
- On exit 2 (no eligible sibling), the driver must hold under the existing rule.
53
- On error exit 1, the driver must keep its current instance.
54
- Driver account re-selection must configure only the calling thread and only at a turn boundary.
55
- A turn already paused by a usage limit cannot self-recover.
56
- The next wake or user message runs this check.
57
-
58
- Driver self-switching is required from v0.25.1.
59
- T3 scheduled tasks retain the creation-time instanceId for wakes and fresh-thread
60
- passes regardless of the calling thread's current binding.
61
- The driver must arm a run watch only after picking its account: `pick-instance.js` before `schedule_task`.
62
- On a driver self-switch, delete and recreate its armed bound run watch with the
63
- same prompt, cadence and binding on the new instance.
64
-
65
- Every scheduled automation pass runs `scripts/pick-instance.js --provider <its own provider> --json`
66
- at pass start, including fresh-thread review-manager passes.
67
- Scheduled passes follow the driver's eligibility and stay rules: an eligible own instance stays,
68
- exit 1 keeps the current instance and exit 2 holds.
69
- If a scheduled pass's own current instance is `excluded` and an eligible same-provider sibling exists,
70
- it must switch itself via `t3_thread_configure` to the chosen sibling instance,
71
- keeping the same provider, model and effort/options.
72
- On a scheduled pass self-switch in a review-manager lane, only the owner-of-record, after lane reconciliation
73
- and the duplicate check, must delete and recreate its own schedule with the same
74
- prompt, cadence and binding on the chosen instance.
75
- On any other scheduled pass self-switch, delete and recreate its own schedule with
76
- the same prompt, cadence and binding on the chosen instance only after `list_scheduled_tasks`
77
- confirms no replacement for that schedule on the chosen instance already exists.
78
- If a replacement for that schedule on the chosen instance already exists, any other scheduled pass must skip recreation.
79
- For a review-manager self-switch, only the owner-of-record must update the recorded
80
- `axstack-owner` binding's instanceId to the chosen instance after verifying unchanged
81
- provider/model/effort/options with `t3_thread_configuration` and attaching the picker
82
- switch receipt, before the admission binding comparison.
83
- For each schedule replacement, read back old absence and new presence using `list_scheduled_tasks`.
84
- For each schedule replacement, record old/new scheduledTaskId, from/to instance,
85
- picker JSON pointer and UTC time in the `progress.md` or durable activation/continuity record.
86
- Retain the recorded schedule's title and enabled state and use a fresh stable creation `clientRequestId`.
87
- An uncertain replacement holds affected work: preserve its native receipts for reconciliation.
88
- A scheduled pass already running on an exhausted account cannot recover.
89
- Account switches must happen before exhaustion at the picker's near-limit cutoff.
32
+ Provider bindings must map codex→`codex`, claude→`claudeAgent` and grok→`grok`.
33
+ For every dispatch or launch, claude must bind to `claudeAgent` and codex must bind to `codex`.
34
+ A usage-limited instance must hold the work without failover.
90
35
 
91
36
  For plan generation, run
92
- `scripts/dispatch-plan.js --role <id> --roles <roles.json> --capabilities <saved.json> --picker <picker.json> --kind task|launch`
37
+ `scripts/dispatch-plan.js --role <id> --roles <roles.json> --capabilities <saved.json> --kind task|launch`
93
38
  using the recorded role snapshot and saved capabilities.
94
- Plan JSON carries `inputs`, which callers omit when copying `target`/`modelSelection` and `runtimeMode` into `delegate_task`/`t3_thread_launch`; large plan output requires `--out`.
95
- For claude/codex, the `--picker` JSON must come from saved
96
- `scripts/pick-instance.js --provider <role provider> --json` output.
97
- For grok/antigravity, or after a claude/codex picker exit-1 canonical fallback,
98
- pass `{"chosenInstanceId":"<canonical instance>"}`.
39
+ Plan JSON carries `inputs`, which callers omit when copying `target`/`modelSelection` and `runtimeMode` plus `isolation` when present into `delegate_task`/`t3_thread_launch`; large plan output requires `--out`.
99
40
  For configuration verification, run `scripts/dispatch-plan.js --verify <configuration.json>`
100
41
  with the same plan inputs and saved `t3_thread_configuration` read-back.
101
42
 
@@ -105,17 +46,13 @@ A preset model must be used as given.
105
46
 
106
47
  A missing or malformed catalog holds resolution.
107
48
 
108
- For a null-model grok or antigravity role, record the exact model ID from the plan,
49
+ For a null-model grok role, record the exact model ID from the plan,
109
50
  rather than an unresolved provider default.
110
- Antigravity must hold when saved capabilities advertise zero models.
111
- No matching effort suffix holds resolution for Antigravity.
112
51
  For codex or claude, a role lacking both model and class is an intentional
113
52
  absence and must hold; never use a provider default for that role.
114
53
 
115
54
  An unavailable provider, model, role, mode or effort must hold that role with
116
55
  no substitution. Auth, quota, timeout and rejection do not select an alternative.
117
- Here alternative means a provider or model substitution, excluding the bounded
118
- same-provider, same-model account selection above.
119
56
  Intentional absent seats remain recorded absences; availability is runtime proof.
120
57
 
121
58
  Grok's CLI requires ≥1.0.13.
@@ -138,9 +75,9 @@ configuration; unrelated configurations remain eligible.
138
75
 
139
76
  | Roles | Mechanism and permitted workspace | Completion |
140
77
  |---|---|---|
141
- | Advisers, research, read-only explorers, explainers, diligence, checker, auditor, monitor, arena prose candidates and judges, escalation | Must use async `delegate_task` in the driver worktree, title = dispatch key; tracked and untracked files stay untouched; writes only `<run>/evidence/<key>/` | Native notification followed by persisted `task_status` |
78
+ | Advisers, research, read-only explorers, explainers, diligence, checker, auditor, arena prose candidates and judges, escalation | Must use async `delegate_task` in the driver worktree, title = dispatch key; tracked and untracked files stay untouched; writes only `<run>/evidence/<key>/` | Native notification followed by persisted `task_status` |
142
79
  | Reviewers (peer/authored), release checks, debug investigators, execution investigators (`axstack-explore-execution`), UI verifier candidate checks (`axstack-ui-verifier`) | Must use async `delegate_task`, title = dispatch key; driver makes a disposable detached checkout of candidate SHA and pinned base with `git worktree add --detach <run>/checkouts/<key> <sha>` (plus pinned debug patch); brief requires `cd` into it; only disposable probes write there, outputs go to `<run>/evidence/<key>/` | Same delegated terminal checks |
143
- | Author and repairs | Must use `t3_thread_launch` with `{type:worktree, baseRef:<SHA>, branch:<encoded branch>, startFromOrigin:false}` in their own worktree, kept until PR merges or closes | Writer sends a receipt to the driver; driver verifies terminal run and candidate |
80
+ | Author and repairs | Fresh authors must use async `delegate_task` with `isolation:"worktree"`, title = dispatch key, stable `clientRequestId` in their own worktree, kept until PR merges or closes; repairs use `t3_thread_send` to the same child | Delegated terminal checks plus verified candidate |
144
81
  | Owner | Driver thread in Driver worktree; never writes tracked candidate source or tests; planning artifacts allowed only for repository Markdown; scope, integration, forge mutations and record | No worker launch |
145
82
 
146
83
  The UI verifier checkout row applies to candidate checks, while a page without
@@ -152,6 +89,13 @@ The driver may write planning artifacts (spec, ticket map) in its own worktree w
152
89
  Repairs return to that author. Missing or idle sessions grant no ownership transfer.
153
90
  The current chat/driver has no role row in any preset.
154
91
 
92
+ At launch and rename, visible driver thread titles express a plain outcome of
93
+ at most 30 characters.
94
+ Visible driver thread titles use no repo, issue or size prefix.
95
+ Hidden children keep dispatch-key titles.
96
+ D9 applies to driver threads only, while flagged unbound pass threads retain the
97
+ `Needs you: <kind> <repo>#<n>` (or `<lane>`) rename under Automations.
98
+
155
99
  The dispatch key must be `<run>:<role>:<task>:a<n>`, recorded before launch and
156
100
  used as the exact whole T3 title. Substring matches do not establish identity.
157
101
  Each dispatch binds the approved spec or small-change intent, brief, authority, role snapshot, base and candidate to its dispatch key.
@@ -162,12 +106,37 @@ The branch must be `axstack/<run>/<role>/<task>-a<n>`; lowercase each segment
162
106
  and replace every `[^a-z0-9-]` character with `-`. Keep the dispatch key in its
163
107
  original form and record both; normalization is never an identity substitute.
164
108
 
109
+ Before dispatch, the driver must name its resolved worktree absolute path in the author brief.
110
+ Before `git switch -c`, the delegated fresh author must verify `git rev-parse --show-toplevel` differs from the driver worktree named in the brief.
111
+ The isolation proof also requires `git rev-parse --git-dir` differs from `git rev-parse --git-common-dir` (a linked worktree) and `git status --porcelain` is empty.
112
+ The isolation proof must never depend on the starting branch name.
113
+ T3 can rename the starting branch after start.
114
+ On failed isolation proof, stop with `AXSTACK-FAILED` and change nothing.
115
+ After dispatch, the driver must read back the child's `worktreePath` and hold if it is missing or equals the driver worktree.
116
+ The delegated fresh author brief step 1 must verify the branch is absent before
117
+ `git switch -c <encoded branch> <pinned base SHA>`, then verify HEAD equals the pinned base SHA.
118
+ Immediately before `git switch -c`, record the current starting branch with `git symbolic-ref --short HEAD` and starting HEAD with `git rev-parse HEAD`.
119
+ Never use `git switch -C`.
120
+ Delete the T3-created starting branch under its current name only after the switch succeeds and HEAD is verified.
121
+ If T3 renamed the recorded name between capture and switch, follow the worktree reflog rename to the final name.
122
+ Delete only if no worktree has it checked out and its tip equals the recorded starting HEAD.
123
+ If it cannot be identified safely, leave it and name it in the receipt for driver cleanup.
124
+ At dispatch, record taskId, childThreadId, worktreePath and encoded branch.
125
+ T3 worktree isolation starts from the parent HEAD and ignores workspaceStrategy,
126
+ so the delegated fresh child must perform step 1 in its own checkout before writing.
127
+
128
+ Keep `t3_thread_launch` for top-level drivers; use `t3_thread_launch` as a rare
129
+ author fallback only when worktree isolation is unavailable and record each use in the run record.
130
+ For a recorded author launch, use `{type:worktree, baseRef:<SHA>, branch:<encoded branch>, startFromOrigin:false}`.
131
+ A launched fallback author starts on its encoded branch and skips step 1 and the isolation proof.
132
+ The launch-only recovery and completion rules below cover that fallback.
133
+
165
134
  `baseRef` must always be a commit SHA, never a branch name; T3 renames its
166
135
  `t3code/*` branches. Pin base and candidate before dispatch.
167
- Fetch the pinned base commit into the launch repository before a writer launch.
168
- Before a writer launch, verify locally that the pinned base SHA resolves to a
136
+ Fetch the pinned base commit into the dispatch repository before an author dispatch.
137
+ Before an author dispatch, verify locally that the pinned base SHA resolves to a
169
138
  commit with that exact SHA.
170
- If fetch or verification fails, hold that launch.
139
+ If fetch or verification fails, hold that dispatch.
171
140
 
172
141
  Workers must finish with exactly one final marker: `AXSTACK-DONE key=… head=…
173
142
  report=…`, `AXSTACK-FAILED key=… head=… report=…`, or `AXSTACK-QUESTION key=… q=…`.
@@ -185,6 +154,9 @@ Delegated completion must require terminal `completed`, `result_available`,
185
154
  `hasPendingChildRuns:false`, and final `AXSTACK-DONE`; a question stays
186
155
  incomplete even when native status says completed.
187
156
 
157
+ Delegated author completion requires delegated terminal checks plus candidate checks:
158
+ non-empty diff, clean tree and named red/green logs.
159
+
188
160
  Launched writer completion must require terminal `t3_thread_wait` on that run,
189
161
  then candidate checks: non-empty diff, clean tree and named red/green logs.
190
162
  A receipt message alone counts only as progress; it can precede terminal state.
@@ -207,7 +179,10 @@ including untracked entries. Any change is a hold before advancing that work.
207
179
 
208
180
  ## Launch recovery, repairs and questions
209
181
 
210
- For a lost launch response the driver must use fully paginated `t3_thread_list`
182
+ For a lost delegated dispatch or repair response, retry with the same stable
183
+ `clientRequestId` to recover task identity. Never start a second writer while the outcome is unknown.
184
+
185
+ For a lost launch response on the recorded fallback route the driver must use fully paginated `t3_thread_list`
211
186
  with `titleContains=<key>`, filtered to exact whole-title equality, plus
212
187
  `git worktree list`. Keep the reserved branch through recovery. A branch or
213
188
  worktree without a reconciled thread prevents proof of absence.
@@ -222,16 +197,31 @@ failed is launch failure; timed-out with `t3_thread_read` showing both
222
197
  `activeRunId` and `worktreePath` is started; still preparing is a hold and
223
198
  re-read at the next wake. An unresolved state preserves the attempt.
224
199
 
225
- For `AXSTACK-QUESTION` the driver must answer once using `t3_thread_send` to
226
- the `childThreadId`, record the returned resumed runId, then
200
+ For a delegated child, detect questions with `t3_pending_request_list(childThreadId)`.
201
+ Never rely on `hasPendingQuestion` alone.
202
+ Codex `request_user_input_async` does not set it.
203
+ Use `t3_pending_request_read`, then confirm the request is still pending with
204
+ `t3_pending_request_list(childThreadId)`, then answer once within existing authority
205
+ using `t3_pending_request_respond`; a second ask holds.
206
+ Independent review rounds require fresh `delegate_task` calls.
207
+ Only author continuation and an answer to a child's own question use the same child.
208
+ Providers without a question tool (grok) and launched writers keep
209
+ the `AXSTACK-QUESTION` marker route.
210
+
211
+ For a delegated marker question, answer once with `t3_thread_send(childThreadId, mode:queue)`,
212
+ record the returned `taskId`, and consume the follow-up under delegated terminal checks.
213
+ For a launched-writer `AXSTACK-QUESTION` marker the driver must answer once using
214
+ `t3_thread_send` to the `childThreadId`, record the returned resumed runId, then
227
215
  `t3_thread_wait(childThreadId, runId, timeoutMs:600000)`, re-armed by the run
228
216
  watch. Persist status again and accept only `latestTerminal*` with
229
217
  `latestTerminalRunId` newer than the question run (recorded run ordering, not
230
218
  lexical ID order), terminal success and matching receipt key/SHA. The original
231
- summary stays stable; no notification is assumed for a resumed result.
219
+ summary stays stable; no notification is assumed for a launched-writer resumed result.
232
220
 
233
- A repair must use `t3_thread_send(writerThreadId, mode:queue)` to the same
234
- author in the same attempt and worktree; pin the new candidate revision.
221
+ A delegated repair must use a stable clientRequestId with `t3_thread_send(childThreadId, mode:queue, clientRequestId)` to the same author
222
+ in the same attempt, worktree and branch, record the returned taskId and verify the existing candidate head.
223
+ Repairs never repeat fresh checkout step 1. Pin the new candidate revision.
224
+ For a launched fallback, retain the same author thread and use launched-run completion checks.
235
225
 
236
226
  A replacement after terminal failure must use `a<n+1>`, a new branch and title;
237
227
  the failed attempt's branch is kept until salvage. Unknown liveness holds
@@ -239,7 +229,7 @@ replacement; reconcile the old writer before admitting another.
239
229
 
240
230
  With an unsettled launched thread, the driver turn must end only while a bound
241
231
  `schedule_task` with `bindToCurrentThread:true` is armed at the default
242
- `everyMs:1800000` or for its 5-minute recovery cases in
232
+ `everyMs:3600000` or for its 5-minute recovery cases in
243
233
  [Chat-run watch runtime](../../axstack-watch/references/watch-runtime.md#chat-run-watch),
244
234
  with its ID recorded. Each wake must reconcile all unsettled runs, including a
245
235
  writer that died without sending; failed runs hold incomplete work. The watch
@@ -269,17 +259,19 @@ Before finishing PR work, including watch end or Close-out, the driver calls
269
259
  `list_thread_pull_requests` and links every missing run PR.
270
260
  Never link unrelated PRs.
271
261
 
272
- After verified publication readback of an own PR, for every layer of an ordinary-chain or legacy `gh stack`,
273
- the driver also calls `t3_thread_update` with `action: link_pull_request`,
274
- `pullRequest` containing its number, repository and full PR URL, and `threadId`
275
- set to the author thread, then reads back the PR link with
276
- `list_thread_pull_requests` for that same author thread.
277
- A missing or failed author-link readback never triggers author repair: it holds
278
- only that PR's merge-ready and requires retrying the link.
262
+ Authors are never PR-linked: the driver alone links and watches the PR.
263
+ For delegated authors after accepted completion, in the same driver turn settle with
264
+ `t3_thread_organize` using `action: settle`, read back `settled: true` with `t3_thread_read`
265
+ and record `settle: manual` under the [Settlement](workspace-hygiene.md#settlement) guards.
266
+ For delegated authors, archive and guarded manual worktree removal wait for PR merge or close.
267
+ Never rely on automatic child cleanup.
279
268
 
280
269
  When the forge confirms a run PR merged or closed, in the same driver turn the
281
- driver settles its author thread with `t3_thread_organize` using `action: settle`
282
- and reads back `settled: true` with `t3_thread_read` for that thread.
270
+ driver first reads its author thread with `t3_thread_read`.
271
+ If the readback already shows `settled: true`, record `settle: native` only when
272
+ no driver settle was issued for that thread; otherwise retain `settle: manual`.
273
+ Otherwise settle with `t3_thread_organize` using `action: settle`, then read back
274
+ `settled: true` with `t3_thread_read` before recording `settle: manual`.
283
275
  Apply the existing [Settlement](workspace-hygiene.md#settlement) guards:
284
276
  terminal run evidence is required and user-taken-over threads stay untouched.
285
277
  A missing or failed settle readback holds watch end and Close-out only for
@@ -288,22 +280,44 @@ that author thread until resolved.
288
280
  For every watched own PR in chat-run or standalone adopted maintenance, when
289
281
  available the driver calls `watch_pull_request` for T3 wakes on check completion,
290
282
  new comments from others, or branch conflicts, then ends the turn.
283
+ Only the PR-owning driver calls `watch_pull_request`.
284
+ Delegated children never call `watch_pull_request`.
285
+ Before arming, handle existing checks and comments because only later comments wake the thread.
291
286
  Never poll or keep a model active between native PR wake events.
292
- A T3 "stopped watching" notice is itself a driver wake: in that same turn,
293
- re-check the PR and call `watch_pull_request` again.
294
- This includes a stop after T3 could not read the PR for 15 minutes.
287
+ Native watch ends after 8 failed reads, or on settle, archive, user Stop, or PR merge/close.
288
+ For parked holds, follow [Parked user-reply holds](contracts.md#parked-user-reply-holds).
289
+ A parking unwatch never triggers native re-arm or the 5-minute recovery cadence.
290
+ A non-user T3 "stopped watching" notice is itself a driver wake: in that same turn,
291
+ re-check the PR.
292
+ After a non-user stop while the PR stays open, the driver must re-arm in that
293
+ same turn when GraphQL quota permits, using the recovery steps below.
294
+ Record the stop reason T3 gives.
295
+ Re-arm only after a stop not caused by the user.
296
+ For a "could not read" stop, run `gh api rate_limit --jq .resources.graphql` as a diagnostic only.
297
+ When GraphQL remaining is near 0, defer re-arming until reset: set the bound
298
+ schedule to 5 minutes and re-arm on the next wake after reset.
299
+ Record the GraphQL reset time in the run record.
300
+ Never wait for a GraphQL reset inside a turn.
301
+ Before re-arming, first unsettle the driver thread with `t3_thread_organize`
302
+ using `action: unsettle`, then call `watch_pull_request` again.
303
+ Never re-arm in a loop.
295
304
  Route native PR wake events through watch §4 and the unchanged §5 readiness predicate.
296
305
 
297
306
  If `watch_pull_request` is unavailable, fall back to the bound 5-minute schedule
298
307
  and `scripts/pr-digest.js` without a hold.
299
308
  If re-arming fails, restore the bound 5-minute schedule.
300
- When the run waits only on a user decision or a human-only step, including a
301
- user merge, with no unsettled worker and no PR needing watch events, change
302
- the run watch cadence to 60 minutes at once.
303
- When work restarts, restore the normal 30-minute cadence.
304
- Keep native PR watches.
309
+ For forge-resolved human waits, including user merge, npm stage approval and
310
+ human review, with no unsettled worker and no PR needing watch events, set the run watch cadence to 60 minutes
311
+ at once.
312
+ When work restarts, re-evaluate cadence against the recovery conditions in
313
+ [Chat-run watch runtime](../../axstack-watch/references/watch-runtime.md#chat-run-watch).
314
+ Keep native PR watches for forge-resolved waits.
305
315
  For chat-run cadence changes, follow [Chat-run watch runtime](../../axstack-watch/references/watch-runtime.md#chat-run-watch)
306
- for the normal 30-minute cadence, 5-minute recovery, and schedule update read-back.
316
+ for the 60-minute backstop, 5-minute recovery, and schedule update read-back.
317
+ An open PR left unwatched by a user Stop never triggers the 5-minute recovery cadence.
318
+ After T3 auto-settles a multi-PR driver on one PR merge, it re-arms remaining
319
+ open members through the recovery steps before ending the turn.
320
+ If rate-limited, use the 5-minute schedule and next-wake recovery above.
307
321
  The schedule still reconciles author and review tasks, readiness, and release.
308
322
  When a PR merges or closes, or its watch is torn down, call `unwatch_pull_request`
309
323
  and keep its link.
@@ -358,13 +372,18 @@ The driver must retain a user-taken-over T3 thread; never send cleanup commands
358
372
  to it, including `t3_thread_organize` settle or archive.
359
373
  Require T3 terminal run evidence before `t3_thread_organize` settle or archive;
360
374
  these metadata actions are not worktree removal.
375
+ Self-settle is the one exception to terminal-before-settle: T3 returns
376
+ `settlesWhenTurnEnds:true` and the next pass verifies `settled: true`.
377
+ Apply the guarded unbound pass-end action in
378
+ [Finite-session teardown](automations.md#finite-session-teardown).
361
379
 
362
380
  ## Project preflight and run record
363
381
 
364
- `worktreeCleanup` must be `off` for every Axstack project. Preflight reads it
365
- with `t3_project_read` where exposed; otherwise record a limitation pointing
366
- to the documented installation setup step. Automatic worktree deletion cannot
367
- replace evidence readback and salvage.
382
+ Hosts can delete author worktrees at merge through `storageCleanup.worktreeOnMerge`.
383
+ `t3_project_read` cannot read `storageCleanup.worktreeOnMerge`.
384
+ Evidence never lives in a worktree and belongs in private `<run>/evidence/<key>/`.
385
+ A missing merged or closed author worktree is expected, not a hold.
386
+ Automatic worktree deletion cannot replace evidence readback and salvage.
368
387
 
369
388
  The run record must contain driver threadId, projectId, host, T3 version,
370
389
  installed Axstack SHA, capabilities JSON path and scheduledTaskIds for every
@@ -1,6 +1,6 @@
1
1
  # Weekly test-audit prompt
2
2
 
3
- At pass start, follow [Provider bindings](t3-runtime.md#preflight-and-binding) for account selection and schedule recreation.
3
+ At pass start, follow [Provider bindings](t3-runtime.md#preflight-and-binding) for provider binding.
4
4
 
5
5
  You are a fresh finite weekly test-audit session in this repository's dedicated
6
6
  T3 project worktree. Before admission, read the activation record: repository,
@@ -65,5 +65,17 @@ The recorded owning watch thread merges under the same watch predicate.
65
65
  Workers never merge.
66
66
 
67
67
  Raise decision and serious-risk holds in the T3 driver thread; end the turn
68
- parked on the decision. Keep routine reports there, including skipped or empty passes.
68
+ waiting on the decision. Keep routine reports there, including skipped or empty passes.
69
69
  Settle owned workers and preserve evidence under the shared lifecycle.
70
+
71
+ At pass start, read the recorded prior pass thread with `t3_thread_read` and
72
+ apply [Finite-session teardown](automations.md#finite-session-teardown)'s guarded
73
+ verification or hold/report before replacing its identity.
74
+ Record own pass threadId in the existing activation record and read back the save.
75
+
76
+ At pass end, an unbound pass calls `t3_thread_organize` with `action: settle` on its
77
+ own thread only, only when it owns no PR watch, has zero unsettled descendants,
78
+ has no pending receipt and is not held, wedged or a stalled owner.
79
+ Follow [Finite-session teardown](automations.md#finite-session-teardown) for
80
+ deferred self-settle and next-pass verification; this applies to quiet, skipped
81
+ and empty passes too.
@@ -24,8 +24,10 @@ still appears is a hold; agents do not answer it.
24
24
 
25
25
  ## Project preflight
26
26
 
27
- `worktreeCleanup` must be `off` for every Axstack project.
28
- Preflight reads back `worktreeCleanup` via `t3_project_read` where exposed; otherwise record a limitation pointing to the documented installation setup step.
27
+ Hosts can delete author worktrees at merge through `storageCleanup.worktreeOnMerge`.
28
+ `t3_project_read` cannot read `storageCleanup.worktreeOnMerge`.
29
+ Evidence never lives in a worktree and belongs in private `<run>/evidence/<key>/`.
30
+ A missing merged or closed author worktree is expected, not a hold.
29
31
  Automatic deletion cannot replace evidence readback or salvage. Do not change
30
32
  project settings without recorded host-mutation authority.
31
33
 
@@ -33,10 +35,20 @@ project settings without recorded host-mutation authority.
33
35
 
34
36
  Cleanup order is: settled descendants -> evidence readback -> salvage dirty or ignored non-cache content -> t3_thread_organize archive -> exact git worktree remove without force -> git branch -d for local-only branches.
35
37
  Require terminal run evidence before `t3_thread_organize` settle or archive.
38
+ Self-settle is the one exception to terminal-before-settle: T3 returns
39
+ `settlesWhenTurnEnds:true` and the next pass verifies `settled: true`.
40
+ Apply the guarded unbound pass-end action in
41
+ [Finite-session teardown](automations.md#finite-session-teardown).
42
+ Record `settle: native` only when no driver settle was issued for that thread;
43
+ otherwise retain `settle: manual` even when a later read already shows settled.
36
44
  These metadata actions do not remove worktrees. Accept matching delegated task
37
45
  or launched run completion under the runtime contract before settlement.
38
46
  After the driver accepts a launched writer's (author or repair) or delegated task's completion from terminal run evidence plus a verified receipt or candidate check, in the same driver turn it settles the matching thread with `t3_thread_organize` using `action: settle` as metadata only.
39
47
  The driver reads back `settled: true` with `t3_thread_read` on the writer thread for launched writers and on the `childThreadId` for delegated tasks.
48
+ For delegated authors after accepted completion, in the same driver turn settle with `t3_thread_organize` using `action: settle`, read back `settled: true` with `t3_thread_read` and record `settle: manual`.
49
+ For delegated authors, archive and guarded manual worktree removal wait for PR merge or close.
50
+ Never rely on automatic child cleanup.
51
+ Delegated author threads stay hidden in the sidebar regardless of settlement; visibility statements below apply to launched writers.
40
52
  This extends the existing same-turn settle rule: a pinned run-owned child is still settled.
41
53
  T3's settle clears the pin, including one inherited from the parent at creation. There is no separate unpin step.
42
54
  Native T3 tools do not show pins, so the read-back stays `settled: true`.
@@ -1,17 +1,16 @@
1
1
  import { readFileSync, writeFileSync } from 'node:fs';
2
2
 
3
- const flags = ['--role', '--roles', '--capabilities', '--picker', '--kind', '--verify', '--out'];
3
+ const flags = ['--role', '--roles', '--capabilities', '--kind', '--verify', '--out'];
4
4
  const nonempty = (value) => typeof value === 'string' && value.trim().length > 0;
5
5
  const help = `Usage: bun dispatch-plan.js --role <id> --roles <roles.json>
6
- --capabilities <saved.json> --picker <picker.json> --kind task|launch
6
+ --capabilities <saved.json> --kind task|launch
7
7
  [--verify <configuration.json>] [--out <report.json>]
8
- Example: bun dispatch-plan.js --role axstack-author --roles roles.json --capabilities capabilities.json --picker picker.json --kind launch
8
+ Example: bun dispatch-plan.js --role axstack-author --roles roles.json --capabilities capabilities.json --kind task
9
9
 
10
10
  --role Role ID from the supplied snapshot
11
11
  --roles Installed-style roles.json (version 1, roles array)
12
12
  --capabilities Saved orchestrator_capabilities JSON; reuse the run's saved snapshot
13
- --picker Saved picker JSON; uses chosenInstanceId
14
- --kind task emits target; launch emits modelSelection
13
+ --kind task emits target and, for axstack-author, isolation:"worktree"; launch emits modelSelection
15
14
  --verify Compare t3_thread_configuration JSON; print evidence then MATCH or each mismatch
16
15
  --out Save the payload as full JSON here; stdout is an input/path/omitted-count summary
17
16
  --help Show all flags and exit codes
@@ -61,7 +60,7 @@ function normalizedOptions(options) {
61
60
  return JSON.stringify(entries.sort(([left], [right]) => left.localeCompare(right)));
62
61
  }
63
62
 
64
- function verify(configuration, instanceId, provider, model, options) {
63
+ function verify(configuration, provider, model, options) {
65
64
  const mismatches = [];
66
65
  const selection = configuration?.modelSelection;
67
66
  const compare = (field, expected, observed, equal = expected === observed) => {
@@ -73,7 +72,7 @@ function verify(configuration, instanceId, provider, model, options) {
73
72
  compare('provider', provider, selection.provider,
74
73
  (selection.provider === 'claude' ? 'claudeAgent' : selection.provider) === provider);
75
74
  }
76
- compare('instanceId', instanceId, selection?.instanceId);
75
+ compare('instanceId', provider, selection?.instanceId);
77
76
  compare('model', model, selection?.model);
78
77
  compare('options', options, selection?.options,
79
78
  normalizedOptions(options) === normalizedOptions(selection?.options));
@@ -130,8 +129,6 @@ function plan(argv, io) {
130
129
  if (!nonempty(role.model) && !nonempty(role.modelClass) && role.model !== null) {
131
130
  hold(`model unavailable for role ${role.id}`);
132
131
  }
133
- const picker = readJSON(args['--picker']);
134
- if (!nonempty(picker?.chosenInstanceId)) hold('picker chosen instance unavailable');
135
132
  const modelArgs = typeof role.model === 'string' ? ['--model', role.model]
136
133
  : role.modelClass ? ['--class', role.modelClass] : ['--model', String(role.model)];
137
134
  const resolved = Bun.spawnSync([process.execPath, `${import.meta.dir}/resolve-models.js`,
@@ -140,30 +137,16 @@ function plan(argv, io) {
140
137
  if (resolved.stderr.length) io.stderr(resolved.stderr.toString());
141
138
  if (resolved.exitCode !== 0) return resolved.exitCode === 1 ? 2 : 1;
142
139
  const { model, effortOption, providerInstanceId } = JSON.parse(resolved.stdout.toString());
143
- const chosen = readJSON(args['--capabilities']).providers
144
- .filter((provider) => provider.providerInstanceId === picker.chosenInstanceId);
145
- if (chosen.length !== 1 || chosen[0].driverKind !== providerInstanceId
146
- || (['grok', 'antigravity'].includes(role.provider) && picker.chosenInstanceId !== providerInstanceId)) {
147
- hold(`picker instance ${picker.chosenInstanceId} does not bind provider ${role.provider}`);
148
- }
149
- if (!Array.isArray(chosen[0].models)) {
150
- hold(`malformed models on instance ${picker.chosenInstanceId}; expected an array; observed ${JSON.stringify(chosen[0].models) ?? 'missing'}`);
151
- }
152
- const selectedModel = chosen[0].models.find((entry) => entry.id === model);
153
- if (!selectedModel) hold(`model ${model} unavailable on instance ${picker.chosenInstanceId}`);
154
- if (effortOption && !selectedModel.options?.some((option) => option.id === effortOption.id
155
- && option.options?.some((value) => value.id === effortOption.value))) {
156
- hold(`effort ${effortOption.value} unavailable on instance ${picker.chosenInstanceId}`);
157
- }
158
140
  const options = effortOption ? [effortOption] : [];
159
141
  if (args['--verify']) {
160
- const verification = verify(readJSON(args['--verify']), picker.chosenInstanceId, providerInstanceId, model, options);
142
+ const verification = verify(readJSON(args['--verify']), providerInstanceId, model, options);
161
143
  emit(verification);
162
144
  return verification.mismatches.length ? 2 : 0;
163
145
  }
164
- const selection = { [args['--kind'] === 'launch' ? 'instanceId' : 'providerInstanceId']: picker.chosenInstanceId,
146
+ const selection = { [args['--kind'] === 'launch' ? 'instanceId' : 'providerInstanceId']: providerInstanceId,
165
147
  model, options };
166
- emit({ [args['--kind'] === 'launch' ? 'modelSelection' : 'target']: selection, runtimeMode: 'full-access' });
148
+ emit({ [args['--kind'] === 'launch' ? 'modelSelection' : 'target']: selection, runtimeMode: 'full-access',
149
+ ...(args['--kind'] === 'task' && role.id === 'axstack-author' ? { isolation: 'worktree' } : {}) });
167
150
  return 0;
168
151
  }
169
152
 
@@ -1,6 +1,6 @@
1
1
  import { readFileSync } from 'node:fs';
2
2
 
3
- const bindings = { codex: 'codex', claude: 'claudeAgent', grok: 'grok', antigravity: 'antigravity' };
3
+ const bindings = { codex: 'codex', claude: 'claudeAgent', grok: 'grok' };
4
4
  const effortIds = { codex: 'reasoningEffort', claude: 'effort', grok: 'reasoningEffort' };
5
5
  const nonempty = (value) => typeof value === 'string' && value.trim().length > 0;
6
6
 
@@ -21,7 +21,7 @@ function argumentsFrom(args) {
21
21
  }
22
22
  }
23
23
  if (!options.provider || !options.capabilities || !options.effort) {
24
- throw new Error('expected --provider codex|claude|grok|antigravity --capabilities path --effort level');
24
+ throw new Error('expected --provider codex|claude|grok --capabilities path --effort level');
25
25
  }
26
26
  return options;
27
27
  }
@@ -45,7 +45,7 @@ function providerFrom(catalog, provider) {
45
45
  return instance;
46
46
  }
47
47
 
48
- function modelFrom(models, { provider, model: pin, class: modelClass, excluded, effort }) {
48
+ function modelFrom(models, { provider, model: pin, class: modelClass, excluded }) {
49
49
  if (pin && pin !== 'null') {
50
50
  const model = models.find((model) => model.id === pin && !excluded.includes(model.id));
51
51
  if (!model) throw new Error(`missing requested model ${pin}`);
@@ -56,9 +56,7 @@ function modelFrom(models, { provider, model: pin, class: modelClass, excluded,
56
56
  if (['codex', 'claude'].includes(provider)) {
57
57
  throw new Error(`intentional absence for ${provider}: missing model and class`);
58
58
  }
59
- // Antigravity encodes effort in its ID; exclusions never select a substitute.
60
- const model = provider === 'antigravity'
61
- ? models.find((model) => model.id.endsWith(`-${effort}`)) : models[0];
59
+ const model = models[0];
62
60
  if (!model || excluded.includes(model.id)) throw new Error('missing first listed model');
63
61
  return model;
64
62
  }
@@ -89,19 +87,12 @@ try {
89
87
  const catalog = JSON.parse(readFileSync(path, 'utf8'));
90
88
  const instance = providerFrom(catalog, provider);
91
89
  const model = modelFrom(instance.models, options);
92
- let effortOption = null;
93
- if (provider === 'antigravity') {
94
- if (!model.id.endsWith(`-${effort}`)) {
95
- throw new Error(`unsupported effort ${effort} for ${provider}/${model.id}`);
96
- }
97
- } else {
98
- const effortOptions = model.options.filter((option) => option.id === effortIds[provider]);
99
- if (effortOptions.length !== 1 || !effortOptions[0].options?.some((value) => value.id === effort)
100
- || (provider === 'grok' && effort === 'max')) {
101
- throw new Error(`unsupported effort ${effort} for ${provider}/${model.id}`);
102
- }
103
- effortOption = { id: effortOptions[0].id, value: effort };
90
+ const effortOptions = model.options.filter((option) => option.id === effortIds[provider]);
91
+ if (effortOptions.length !== 1 || !effortOptions[0].options?.some((value) => value.id === effort)
92
+ || (provider === 'grok' && effort === 'max')) {
93
+ throw new Error(`unsupported effort ${effort} for ${provider}/${model.id}`);
104
94
  }
95
+ const effortOption = { id: effortOptions[0].id, value: effort };
105
96
  console.log(JSON.stringify({ provider, providerInstanceId: instance.providerInstanceId,
106
97
  model: model.id, effortOption, source: 'capabilities', path }));
107
98
  } catch (error) {
@@ -12,7 +12,7 @@ hard-to-reverse choices; they replace the critique round for that question.
12
12
  example, taking the shortest path that compiles. Treat them as prompts, not defects. Candidates receive only the brief; the rubric is for judging.
13
13
  2. **Fan out.** Produce one candidate per configured family independently from the same brief,
14
14
  without cross-reading: `axstack-advisor-astra`, `axstack-advisor-opus`,
15
- `axstack-arena-candidate-grok`, and `axstack-arena-candidate-antigravity`.
15
+ and `axstack-arena-candidate-grok`.
16
16
  Each gives a design, rationale, and rejected alternatives. The driver authors no candidate.
17
17
  The driver drafts no recommendation until every candidate returns.
18
18
  3. **Cross-judge (Rung 2 only).** After every candidate completes, give round 1 judge
@@ -45,7 +45,7 @@ verdicts per round) as `Decisions` rows in the
45
45
  [caller's run record](../../axstack/references/run-record.md) when one exists,
46
46
  otherwise include it in the returned verdict. Load
47
47
  [T3 runtime](../../axstack/references/t3-runtime.md) immediately before the
48
- first candidate or judge dispatch. If an optional Grok or Antigravity candidate
48
+ first candidate or judge dispatch. If an optional Grok candidate
49
49
  malfunctions (launch failure, trust/login prompt, or prompt block), fence it,
50
50
  record `absent (<reason>)`, name it once in the next
51
51
  read-back, and continue with available candidates without relay or substitution.
@@ -20,9 +20,12 @@ Before any runtime action, load and follow:
20
20
  evidence is the last removable-worktree blocker
21
21
 
22
22
  Use project-scoped T3 thread inventory, `git worktree list --porcelain` and run
23
- records. Preflight requires `worktreeCleanup` off via `t3_project_read` where
24
- exposed, or a recorded setup limitation. Follow the runtime schema, never invent
25
- an alternate command protocol.
23
+ records.
24
+ Hosts can delete author worktrees at merge through `storageCleanup.worktreeOnMerge`.
25
+ `t3_project_read` cannot read `storageCleanup.worktreeOnMerge`.
26
+ Evidence never lives in a worktree and belongs in private `<run>/evidence/<key>/`.
27
+ A missing merged or closed author worktree is expected, not a hold.
28
+ Follow the runtime schema, never invent an alternate command protocol.
26
29
 
27
30
  ## Authority and scope
28
31