axstack 0.14.1 → 0.15.0

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "axstack",
3
- "version": "0.14.1",
3
+ "version": "0.15.0",
4
4
  "description": "Axstack installer and setup CLI: installs owned chat skills and role data, configures supported harness settings, and checks Orca capabilities.",
5
5
  "keywords": [
6
6
  "claude-code",
@@ -2,7 +2,7 @@
2
2
 
3
3
  Read this when the current session is the native Orca PR **driver** or its
4
4
  **watchdog**. The approved contract is
5
- `docs/specs/pr-automations.md` revision 5; this reference restates the parts an
5
+ `docs/specs/pr-automations.md` revision 6; this reference restates the parts an
6
6
  automation session must execute and does not widen them.
7
7
 
8
8
  Pair A/B is retired for this contract; its artefacts remain untouched.
@@ -11,7 +11,7 @@ Pair A/B is retired for this contract; its artefacts remain untouched.
11
11
 
12
12
  - **driver** — every 15 minutes, fresh Opus session in the host's `root`
13
13
  folder workspace, which is not a git repository and belongs to no project. It discovers GitHub work, binds the persistent Orca
14
- Run, checks each selected PR's head out into a free project-local slot, dispatches the
14
+ Run, creates one worktree per selected PR and checks its head out there, dispatches the
15
15
  matching Axstack agent, reconciles completions and decisions, then exits. The
16
16
  driver is the automation session itself, with no `axstack-monitor` or
17
17
  `axstack-owner` role row. It never performs review or repair in its own
@@ -97,7 +97,7 @@ The driver performs this order and exits:
97
97
  inbox. For a `worker_done` matching a live marker, verify the review id at
98
98
  the bound head, push range, or opened token. Release the worker; once its
99
99
  release receipt is settled and the process has exited, run the cleanup
100
- under "Run directory" below, which proves the slot disposable before
100
+ under "Run directory" below, which proves the worktree disposable before
101
101
  resetting it; then clear the marker. Unverifiable delivery stays in
102
102
  `pending_settlement[]` and blocks only that PR.
103
103
  3. Consume decisions as their sole consumer under "Decision tokens" below.
@@ -126,34 +126,38 @@ The driver performs this order and exits:
126
126
 
127
127
  Claude Code trusts a folder per git toplevel and stops at its "Quick safety
128
128
  check" dialog otherwise, and the driver never answers that dialog for a
129
- worker. So workers run in a fixed pool: every allowlisted project has
130
- exactly five slot worktrees, `slot-1` through `slot-5`, its Orca child
131
- worktrees created once, parented to the project's primary worktree, and trusted once
132
- by the user through that dialog. The driver never creates or removes a
133
- worktree and never writes `~/.claude.json`. A slot is free when no live
134
- dispatch marker names it, it is not in `retained_slots[]`, no terminal is
135
- listed in it, and its tree is clean; no free slot in the project defers the
136
- PR to `deferred[]` like a budget, not a hold. Taking a slot fetches the head into the project clone,
137
- checks the slot out detached at the pinned head, and verifies HEAD equals
138
- it; the marker's worktree is the slot path. The worker is launched by Orca
139
- itself — `worker-start --agent claude --model claude-opus-5 --effort medium`
140
- on that slot — so the runtime owns the process: `worker-release` ends it and
141
- `worker-show` proves it exited, which is what returns the slot to the pool.
142
- Never pre-create the worker's terminal or hand a terminal handle to
129
+ worker. Trust inherits from the project's primary clone, which the user
130
+ trusted once (a fresh child worktree launched with no dialog — canary
131
+ 2026-09-18). There is no fixed pool: fetch the head into the project clone first (a
132
+ failed fetch is a health line and no dispatch; no worktree exists yet), then
133
+ create one Orca worktree per dispatch, `orca worktree create --repo id:<clone
134
+ id> --name <repo short>-<num>-<head7> --base-branch <default branch>
135
+ --parent-worktree id:<clone id>::<clone path> --setup skip` (a name collision
136
+ with a retained worktree at the same head appends the tick's
137
+ `tick_started_at` stamp); close the creation terminal Orca opens in it with
138
+ `orca terminal close --worktree <selector> --all`; check the worktree out
139
+ detached at the pinned head and verify HEAD equals it; the marker's worktree
140
+ is that path. Never write
141
+ `~/.claude.json`. The worker is launched by Orca itself — `worker-start
142
+ --agent claude --model claude-opus-5 --effort medium` in that worktree — so
143
+ the runtime owns the process: `worker-release` ends it and `worker-show`
144
+ proves it exited, which is what allows the worktree to be removed. Never
145
+ pre-create the worker's terminal or hand a terminal handle to
143
146
  `worker-start`: a reused handle is a resource Orca labels `external`, one it
144
- can neither stop nor prove exited, so every such slot ends retained. After
145
- `worker-start` run `worker-show` on the receipt's dispatch id and require
146
- `projection.resource.state == owned`; anything else is a launch Orca does not
147
- own: apply the runtime-refusal recovery rules under "Safety holds" (the
148
- `worker-list` row's `nextAction` argv verbatim; `none` means inspect and
149
- retain), append a `worker not owned` health line and a `retained_slots[]`
150
- entry for the slot, defer the PR, and record no marker. Orca's per-agent default arguments supply
151
- `--dangerously-skip-permissions`; the brief loads the skill files it needs by
152
- path. If `worker-start` reports a failed stage or a visible hold (the "Quick
153
- safety check" trust dialog) the slot is not trusted: name the slot in a health
154
- line, defer the PR, dispatch nothing, never answer the dialog. Project
155
- customizations load as they would for the user; the allowlist is defi-com
156
- only and the user accepted that surface on 2026-09-18.
147
+ can neither stop nor prove exited, so every such worktree ends retained.
148
+ After `worker-start` run `worker-show` on the receipt's dispatch id and
149
+ require `projection.resource.state == owned`; anything else is a launch Orca
150
+ does not own: apply the runtime-refusal recovery rules under "Safety holds"
151
+ (the `worker-list` row's `nextAction` argv verbatim; `none` means inspect
152
+ and retain), append a `worker not owned` health line and a `retained_slots[]`
153
+ entry for the worktree, defer the PR, and record no marker. Orca's per-agent
154
+ default arguments supply `--dangerously-skip-permissions`; the brief loads
155
+ the skill files it needs by path. If `worker-start` reports a failed stage
156
+ or a visible hold (the "Quick safety check" trust dialog) the worktree is not
157
+ trusted: name it in a health line, defer the PR, dispatch nothing, never
158
+ answer the dialog, and remove the worktree through the no-worker branch.
159
+ Project customizations load as they would for the user; the allowlist is
160
+ defi-com only and the user accepted that surface on 2026-09-18.
157
161
 
158
162
  Every selected PR receives one dispatch marker with task id, dispatch id,
159
163
  worktree, head, `started_at`, reservation (`verdict` or `repair`), and trigger:
@@ -175,16 +179,22 @@ An own PR needs repair when either trigger applies:
175
179
  digest not recorded for that PR and head. Both keys are required: the same
176
180
  finding under a new review id must not re-trigger repair. Record review id
177
181
  and body digest when dispatching. A superseded head with a new review
178
- triggers again subject to the 24 h cap.
179
-
180
- Repair also requires no deploy-on-push head branch, no live repair cap, and
181
- selection of the lowest own PR in its stack that needs repair. Take a free
182
- slot of that project (its slots are parented to that project's primary
183
- worktree, so the work appears under the project it serves) at the exact
184
- head, and dispatch one `axstack-watch` agent in authored repair mode. Its
182
+ triggers again at the new head.
183
+
184
+ Repair also requires no deploy-on-push head branch, a head not already in
185
+ `repaired_heads[]`, and selection of the lowest own PR in its stack that
186
+ needs repair. Create the
187
+ dispatch worktree (parented to that project's primary worktree, so the work
188
+ appears under the project it serves) at the exact head, and dispatch one
189
+ `axstack-watch` agent in authored repair mode. Its
185
190
  brief contains only the triggering checks or review findings. Each open
186
191
  descendant records one user-owned `pending restack` hold until it stops needing
187
- repair. The 24 h cap starts at dispatch and an abandon does not refund it.
192
+ repair. At dispatch record the head in `repaired_heads[]` (`pr`, `head`,
193
+ `dispatched_at`): one repair per head, no time cap. A repair pushes a new
194
+ head; a still-not-merge-ready new head shows a new failing check or review
195
+ and is repaired again; a repair that pushes nothing is not retried at that
196
+ head until a human or a new commit moves it. A confirmed abandon removes the
197
+ record (retry once).
188
198
 
189
199
  A debounced peer PR is eligible when self has not reviewed its head. Read
190
200
  `gh pr view --json reviews` before dispatch. Whenever any self review with
@@ -196,14 +206,15 @@ human-placed block is never overwritten. A dismissed block and a self-approved
196
206
  PR are skipped. Dispatch one `axstack-review` agent in peer mode and link the
197
207
  prior review in its brief.
198
208
 
199
- Budgets are one `verdict` dispatch per tick, oldest first; at most six `repair`
200
- markers live across all repositories; and one repair per PR per 24 h. Put every
201
- eligible PR not dispatched because of a budget in `deferred[]` with repo, PR,
202
- and head. Budget exhaustion records the count and is not a hold.
209
+ The only concurrency limit is the host-wide cap: at most eight live dispatch
210
+ markers across all repositories and both reservations, oldest eligible
211
+ first; plus one repair per head. Put every eligible PR not dispatched
212
+ because the cap is reached in `deferred[]` with repo, PR, and head. Reaching
213
+ the cap records the count and is not a hold.
203
214
 
204
215
  ## Agents and verdicts
205
216
 
206
- Every agent works in a project-local slot worktree checked out detached at
217
+ Every agent works in its own project-local worktree checked out detached at
207
218
  the exact head and reports only through the Orca worker protocol.
208
219
 
209
220
  Peer review runs the two isolated configured reviewers on the identical brief,
@@ -343,12 +354,12 @@ is no gate for health findings.
343
354
  ## Run directory
344
355
 
345
356
  The driver and watchdog run from the host's `root` folder workspace, not a
346
- project worktree: no project owns the automation, and every slot worktree
347
- belongs to the project it serves. That workspace is not a git repository, so
357
+ project worktree: no project owns the automation, and every dispatch
358
+ worktree belongs to the project it serves. That workspace is not a git repository, so
348
359
  the run directory is private host state, one
349
360
  `~/.local/share/axstack/runs/<run id>/` directory. Settlement leaves nothing
350
361
  behind, but never destroys work. Before any destructive step the driver
351
- proves the slot is disposable: the worker is settled — on the release path
362
+ proves the worktree is disposable: the worker is settled — on the release path
352
363
  a settled release receipt, on the abandon path an accepted abandon receipt,
353
364
  either with proven process exit; pending or unknown stops here — the
354
365
  worktree's HEAD is either the pinned head or a candidate that is durably
@@ -358,20 +369,21 @@ targeted fetch of that exact remote branch into a per-dispatch ref, never
358
369
  shared clone can fake durability, a failed fetch retaining the worktree — or held by a
359
370
  `refs/axstack/decisions/<token>` ref in the project clone; and, on the
360
371
  abandon path, the worktree has no uncommitted changes.
361
- Only then it closes any terminal tab still listed, resets the slot to the
362
- pinned head, clears untracked artefacts, and verifies the slot is clean, so
363
- it is back in the pool. On the settled path
364
- the worker has finished, so untracked files are artefacts by definition and
365
- are cleared; a candidate there is already pushed or token-held. A slot
366
- whose release is settled but whose HEAD cannot be proven disposable, and an
367
- abandoned slot that is dirty or holds an unproven candidate, are both
368
- **retained**: named in one `health[]` line with path and SHA, and blocking
369
- only that PR with the user as owner. Retention is mechanical on both paths:
370
- the driver appends `retained_slots[]` `{slot, pr, head, reason}`, which the
371
- free predicate excludes for every PR — a clean, terminal-less slot holding
372
- an unpushed candidate would otherwise look free — and an entry is cleared
373
- only by the user after reconciling the candidate. A dirty slot or a terminal that
374
- outlives its dispatch without such a retention record is a health finding. The run directory contains:
372
+ Only then it closes any terminal tab still listed and removes the worktree
373
+ with `orca worktree rm --worktree <selector> --force` (the proof is the
374
+ gate; a finished worker's untracked artefacts are not), so the dispatch
375
+ leaves nothing behind. On the settled path the worker has finished, so untracked
376
+ files are artefacts by definition; a candidate there is already pushed or
377
+ token-held. A worktree whose release is settled but whose HEAD cannot be
378
+ proven disposable, and an abandoned worktree that is dirty or holds an
379
+ unproven candidate, are both **retained** — retained in place: named in one `health[]`
380
+ line with path and SHA, and blocking only that PR with the user as owner.
381
+ Retention is mechanical on both paths: the driver appends `retained_slots[]`
382
+ `{slot, pr, head, reason}` (`slot` is the worktree path); a retained worktree
383
+ is never removed by the driver, and the entry is cleared only by the user
384
+ after reconciling the candidate, who also removes the worktree. A leftover
385
+ worktree or terminal that outlives its dispatch without such a retention
386
+ record is a health finding. The run directory contains:
375
387
 
376
388
  - `cursor.json` — driver only, with these exact keys: `fingerprint`,
377
389
  `tick_started_at`, `tick_done_at`, `tick_outcome`, `prs{url: {head, base,
@@ -379,7 +391,10 @@ outlives its dispatch without such a retention record is a health finding. The r
379
391
  `task_id`, `dispatch_id`, `worktree`, `head`, `started_at`, `reservation`,
380
392
  `trigger`), `deferred[]`, `pending_settlement[]`,
381
393
  `retained_slots[]` (`slot`, `pr`, `head`, `reason`),
382
- `repair_caps{url: {expires_at}}`, `abandon_count{head: n}`,
394
+ `repaired_heads[]` (`pr`, `head`, `dispatched_at`),
395
+ `repair_caps{url: {expires_at}}` (legacy: the first rev-6 tick clears it to
396
+ `{}` with one health line; never written again),
397
+ `abandon_count{head: n}`,
383
398
  `processed_reviews[]` (`review_id`, `pr`, `head`, `digest`),
384
399
  `deploy_on_push{repo: [branches]}`,
385
400
  `legacy_automation_reviews[]`, `health[]`,
@@ -420,12 +435,12 @@ delivery uses [axstack-relay](../../axstack-relay/SKILL.md).
420
435
  `runtime_refusal {code, first_seen, last_seen}`; the same code keeps the
421
436
  hold and updates `last_seen` without a new health line, a different code is
422
437
  a new finding. Prose is never the key. When `worker-start` itself is
423
- refused after the slot was checked out, there is no worker, so the
438
+ refused after the worktree was created, there is no worker, so the
424
439
  settlement proof does not apply; the driver reads the receipt's `failedStage`
425
440
  and `residualResources` first. With no Dispatch and no residual resources
426
441
  the no-worker branch applies: the worktree's HEAD must equal the pinned
427
- head and `git status --porcelain` must be empty, and then the slot is simply
428
- free again in the same tick; there is nothing to remove.
442
+ head and `git status --porcelain` must be empty, and then the worktree is
443
+ simply removed in the same tick.
429
444
  With a Dispatch or any residual resource the failed start owns runtime
430
445
  state, and retaining alone is not recovery: the driver follows the
431
446
  runtime's recovery guide. With a Dispatch: `worker-list` for that run, and