axstack 0.11.6 → 0.12.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.11.6",
3
+ "version": "0.12.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",
@@ -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, creates one project-local child worktree per selected PR, dispatches the
14
+ Run, checks each selected PR's head out into a free project-local slot, 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,8 +97,8 @@ 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 worktree disposable before
101
- removing it; then clear the marker. Unverifiable delivery stays in
100
+ under "Run directory" below, which proves the slot disposable before
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.
104
104
  4. Reconcile every marker older than 3 h. A live worker gets `worker-stop`; an
@@ -124,6 +124,36 @@ The driver performs this order and exits:
124
124
 
125
125
  ## Dispatch and repair selection
126
126
 
127
+ Claude Code trusts a folder per git toplevel and stops at its "Quick safety
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 two slot worktrees, `slot-1` and `slot-2`, its Orca child worktrees
131
+ 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. Trusting a folder activates the
139
+ full project surface: its `.claude/settings.json` and the hooks it defines,
140
+ its `.mcp.json` servers, marketplace plugin auto-install, and `CLAUDE.md`;
141
+ a hostile branch's hooks or MCP servers would run the moment the folder
142
+ opens. So the worker is launched in Claude Code's own isolation mode,
143
+ `--safe-mode`, through `terminal create` and `worker-start --terminal`,
144
+ since `worker-start` cannot pass argv. Safe mode is the binary's sanctioned
145
+ "all customizations disabled" path: no `CLAUDE.md`, skills, plugins, hooks,
146
+ MCP servers, custom commands or agents load from anywhere, project or user;
147
+ built-in tools and authentication are untouched, and the brief loads the
148
+ skill files it needs by path. The driver confirms readiness from the
149
+ rendered frame — `wait.satisfied`, the prompt marker present, the dialog
150
+ absent — before dispatching; a dialog on a slot means the slot is not
151
+ trusted: the slot is named in a health line, the PR is deferred, nothing is
152
+ dispatched. What remains live is the repository's files as data the worker
153
+ reads and the commands the worker itself chooses to run, which it already
154
+ runs today; nothing from the branch loads, executes, or is offered for
155
+ invocation on its own.
156
+
127
157
  Every selected PR receives one dispatch marker with task id, dispatch id,
128
158
  worktree, head, `started_at`, reservation (`verdict` or `repair`), and trigger:
129
159
  `{kind: check, name, app_id}` or `{kind: review, review_id, digest}`. There is at
@@ -147,10 +177,10 @@ An own PR needs repair when either trigger applies:
147
177
  triggers again subject to the 24 h cap.
148
178
 
149
179
  Repair also requires no deploy-on-push head branch, no live repair cap, and
150
- selection of the lowest own PR in its stack that needs repair. Create a child
151
- worktree in that project's clone at the exact head, parented to that
152
- project's primary worktree so it appears under the project it serves, and
153
- dispatch one `axstack-watch` agent in authored repair mode. Its
180
+ selection of the lowest own PR in its stack that needs repair. Take a free
181
+ slot of that project (its slots are parented to that project's primary
182
+ worktree, so the work appears under the project it serves) at the exact
183
+ head, and dispatch one `axstack-watch` agent in authored repair mode. Its
154
184
  brief contains only the triggering checks or review findings. Each open
155
185
  descendant records one user-owned `pending restack` hold until it stops needing
156
186
  repair. The 24 h cap starts at dispatch and an abandon does not refund it.
@@ -172,8 +202,8 @@ and head. Budget exhaustion records the count and is not a hold.
172
202
 
173
203
  ## Agents and verdicts
174
204
 
175
- Every agent works in its own project-local Orca child worktree at the exact
176
- head and reports only through the Orca worker protocol.
205
+ Every agent works in a project-local slot worktree checked out detached at
206
+ the exact head and reports only through the Orca worker protocol.
177
207
 
178
208
  Peer review runs the two isolated configured reviewers on the identical brief,
179
209
  then the Luna gate. `APPROVE` requires complete exact-head/base reviews, gate
@@ -312,12 +342,12 @@ is no gate for health findings.
312
342
  ## Run directory
313
343
 
314
344
  The driver and watchdog run from the host's `root` folder workspace, not a
315
- project worktree: no project owns the automation, and every child worktree
345
+ project worktree: no project owns the automation, and every slot worktree
316
346
  belongs to the project it serves. That workspace is not a git repository, so
317
347
  the run directory is private host state, one
318
348
  `~/.local/share/axstack/runs/<run id>/` directory. Settlement leaves nothing
319
349
  behind, but never destroys work. Before any destructive step the driver
320
- proves the child is disposable: the worker is settled — on the release path
350
+ proves the slot is disposable: the worker is settled — on the release path
321
351
  a settled release receipt, on the abandon path an accepted abandon receipt,
322
352
  either with proven process exit; pending or unknown stops here — the
323
353
  worktree's HEAD is either the pinned head or a candidate that is durably
@@ -327,21 +357,27 @@ targeted fetch of that exact remote branch into a per-dispatch ref, never
327
357
  shared clone can fake durability, a failed fetch retaining the worktree — or held by a
328
358
  `refs/axstack/decisions/<token>` ref in the project clone; and, on the
329
359
  abandon path, the worktree has no uncommitted changes.
330
- Only then it closes any terminal tab still listed, clears untracked
331
- artefacts, removes the child worktree and its directory, deletes the branch
332
- the worktree created, and verifies the directory is gone. On the settled path
360
+ Only then it closes any terminal tab still listed, resets the slot to the
361
+ pinned head, clears untracked artefacts, and verifies the slot is clean, so
362
+ it is back in the pool. On the settled path
333
363
  the worker has finished, so untracked files are artefacts by definition and
334
- are cleared; a candidate there is already pushed or token-held. An abandoned
335
- worktree that is dirty or holds an unproven candidate is **retained**, named
336
- in one `health[]` line with its path and SHA, and blocks only that PR with
337
- the user as owner. A worktree, directory, branch, or terminal that outlives
338
- its dispatch without such a retention record is a health finding. The run directory contains:
364
+ are cleared; a candidate there is already pushed or token-held. A slot
365
+ whose release is settled but whose HEAD cannot be proven disposable, and an
366
+ abandoned slot that is dirty or holds an unproven candidate, are both
367
+ **retained**: named in one `health[]` line with path and SHA, and blocking
368
+ only that PR with the user as owner. Retention is mechanical on both paths:
369
+ the driver appends `retained_slots[]` `{slot, pr, head, reason}`, which the
370
+ free predicate excludes for every PR — a clean, terminal-less slot holding
371
+ an unpushed candidate would otherwise look free — and an entry is cleared
372
+ only by the user after reconciling the candidate. A dirty slot or a terminal that
373
+ outlives its dispatch without such a retention record is a health finding. The run directory contains:
339
374
 
340
375
  - `cursor.json` — driver only, with these exact keys: `fingerprint`,
341
376
  `tick_started_at`, `tick_done_at`, `tick_outcome`, `prs{url: {head, base,
342
377
  draft, checks, reviews, last_self_review}}`, `dispatch_markers[]` (`pr`,
343
378
  `task_id`, `dispatch_id`, `worktree`, `head`, `started_at`, `reservation`,
344
379
  `trigger`), `deferred[]`, `pending_settlement[]`,
380
+ `retained_slots[]` (`slot`, `pr`, `head`, `reason`),
345
381
  `repair_caps{url: {expires_at}}`, `abandon_count{head: n}`,
346
382
  `processed_reviews[]` (`review_id`, `pr`, `head`, `digest`),
347
383
  `deploy_on_push{repo: [branches]}`,
@@ -383,12 +419,12 @@ delivery uses [axstack-relay](../../axstack-relay/SKILL.md).
383
419
  `runtime_refusal {code, first_seen, last_seen}`; the same code keeps the
384
420
  hold and updates `last_seen` without a new health line, a different code is
385
421
  a new finding. Prose is never the key. When `worker-start` itself is
386
- refused after the child worktree was created, there is no worker, so the
422
+ refused after the slot was checked out, there is no worker, so the
387
423
  settlement proof does not apply; the driver reads the receipt's `failedStage`
388
424
  and `residualResources` first. With no Dispatch and no residual resources
389
425
  the no-worker branch applies: the worktree's HEAD must equal the pinned
390
- head and `git status --porcelain` must be empty, and only then does the
391
- driver remove the worktree, its directory and branch in the same tick.
426
+ head and `git status --porcelain` must be empty, and then the slot is simply
427
+ free again in the same tick; there is nothing to remove.
392
428
  With a Dispatch or any residual resource the failed start owns runtime
393
429
  state, and retaining alone is not recovery: the driver follows the
394
430
  runtime's recovery guide. With a Dispatch: `worker-list` for that run, and