@staix/agent-hub 0.12.21 → 0.12.23
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/CHANGELOG.md +29 -0
- package/README.md +27 -12
- package/docs/agent-notes/adapters.md +15 -7
- package/docs/agent-notes/benchmarks.md +4 -1
- package/docs/agent-notes/budget.md +4 -0
- package/docs/agent-notes/bus.md +2 -1
- package/docs/agent-notes/daemon.md +12 -1
- package/docs/agent-notes/local-worker.md +4 -1
- package/docs/agent-notes/tasks.md +2 -1
- package/docs/agent-notes/tests.md +4 -0
- package/docs/events.md +17 -4
- package/docs/operations.md +478 -41
- package/docs/quickstart.md +14 -6
- package/docs/security.md +23 -11
- package/docs/smoke.md +133 -7
- package/docs/specs/2026-09-19-agent-hub-design.md +115 -15
- package/docs/specs/2026-09-20-upgrade-recovery-design.md +84 -8
- package/docs/verification/2026-10-10-cli-output-phase1.md +309 -0
- package/docs/verification/2026-10-10-cli-output-phase2.md +672 -0
- package/docs/verification/2026-10-11-0.12.23.md +90 -0
- package/docs/verified.json +32 -17
- package/package.json +1 -1
- package/plugins/agent-hub/.claude-plugin/plugin.json +1 -1
- package/plugins/agent-hub/server.js +14 -3
- package/src/adapters/acp-quota.ts +13 -0
- package/src/adapters/acp.ts +105 -17
- package/src/adapters/codex-appserver.ts +70 -35
- package/src/adapters/local-worker.ts +44 -10
- package/src/adapters/pi.ts +158 -19
- package/src/cli/bench.ts +2 -1
- package/src/cli/console-state.ts +28 -22
- package/src/cli/console.ts +20 -10
- package/src/cli/help.ts +25 -19
- package/src/cli/identity.ts +3 -3
- package/src/cli/init.ts +1 -1
- package/src/cli/launch.ts +182 -7
- package/src/cli/main.ts +409 -177
- package/src/cli/output.ts +363 -0
- package/src/cli/preview.ts +2 -1
- package/src/cli/recovery-package.ts +17 -0
- package/src/cli/reset.ts +3 -0
- package/src/cli/status-lines.ts +0 -28
- package/src/cli/terminal-recovery.ts +27 -1
- package/src/cli/upgrade-interactive.ts +297 -0
- package/src/cli/upgrade-runtime.ts +80 -9
- package/src/cli/upgrade.ts +50 -15
- package/src/hub/board.ts +2 -0
- package/src/hub/budget.ts +39 -7
- package/src/hub/bus.ts +15 -14
- package/src/hub/child-process.ts +11 -0
- package/src/hub/conductor.ts +23 -11
- package/src/hub/config-trust.ts +16 -5
- package/src/hub/conflicts.ts +2 -0
- package/src/hub/context-window.ts +8 -1
- package/src/hub/crash.ts +2 -1
- package/src/hub/daemon.ts +483 -83
- package/src/hub/db-timeout.ts +3 -0
- package/src/hub/delivery-journal.ts +2 -1
- package/src/hub/envelope.ts +1 -1
- package/src/hub/events.ts +4 -1
- package/src/hub/execution-budget.ts +2 -0
- package/src/hub/facts.ts +5 -4
- package/src/hub/git.ts +32 -0
- package/src/hub/hub-tools.ts +1 -1
- package/src/hub/lifecycle.ts +10 -4
- package/src/hub/manager.ts +18 -5
- package/src/hub/peers.ts +7 -5
- package/src/hub/permission-mode.ts +14 -0
- package/src/hub/project.ts +2 -1
- package/src/hub/recovery-error.ts +31 -0
- package/src/hub/recovery-store.ts +43 -4
- package/src/hub/registry.ts +2 -1
- package/src/hub/routing.ts +114 -13
- package/src/hub/settings.ts +392 -0
- package/src/hub/snapshots.ts +4 -2
- package/src/hub/start-mode.ts +48 -0
- package/src/hub/tasks.ts +158 -43
- package/src/hub/terminal-open.ts +64 -0
- package/src/hub/ui.ts +25 -13
- package/src/local/deny.ts +71 -2
- package/src/local/sandbox.ts +47 -6
- package/src/local/tools.ts +25 -6
- package/src/memory/recall.ts +2 -2
- package/src/models/mlx.ts +2 -1
- package/src/pi/extension.ts +43 -20
- package/src/pi/tool-receipts.ts +19 -2
- package/src/ui/index.html +172 -21
package/docs/operations.md
CHANGED
|
@@ -1,8 +1,25 @@
|
|
|
1
1
|
# Operations guide
|
|
2
2
|
|
|
3
|
-
This guide describes ahub 0.12.
|
|
3
|
+
This guide describes ahub 0.12.23 and control protocol 16. Live verification
|
|
4
4
|
results and remaining prerequisites are recorded separately in [the smoke ledger](smoke.md).
|
|
5
5
|
|
|
6
|
+
## Command output
|
|
7
|
+
|
|
8
|
+
`ahub status`, `board`, `budget`, `doctor`, `projects`, `queue list`, `turns` and `report` print shared console tables and labelled details.
|
|
9
|
+
`status --all` uses the projects table. `queue show`, `models status` and `budget execution status` show labelled fields; add `--json` for the raw fetched document.
|
|
10
|
+
`report --by task` keeps the attribution and coverage sentences with section headings and aligned counters.
|
|
11
|
+
Use `--json` for scripts; it returns the fetched data without color, and `status --json` keeps its existing document.
|
|
12
|
+
In `projects --json` and `status --all --json`, an unavailable hub that explicitly refuses an inspection for SQLite contention also carries `failure: { "code": "database_busy" }`; it is additive metadata alongside the neutral `error` sentence.
|
|
13
|
+
Text columns are a human interface, not a scripting contract. An identifier accepted as a command argument is whole wherever its available column can hold its own length:
|
|
14
|
+
turn ids, queue ids, project ids, execution budget ids and ids in labelled views. Only status's informational settlement and hold ids are shortened;
|
|
15
|
+
`status --full` keeps those whole too. Identifiers in suggested commands are always whole.
|
|
16
|
+
|
|
17
|
+
`--color=auto|always|never` uses the console palette. Auto colors only a TTY with `TERM` other than `dumb`
|
|
18
|
+
and empty `NO_COLOR`; pipes and redirects stay plain. Color never replaces a state or level word.
|
|
19
|
+
TTY width is its columns (at least 80). A pipe uses a positive integer `COLUMNS` when supplied, otherwise rows
|
|
20
|
+
are complete and unwrapped. Long fields wrap within their column; when whole metadata words and the readable flexible-column minimum do not fit, table bands retain every field. Each band carries the row id; when it cannot share a line with the metadata, a per-row id banner links them. Labelled two-column views keep each label beside its value, wrapping the value instead of separating labels and values into bands. In `turns`, the time and state cells wrap at word boundaries only when the file list needs the room and the listing gets shorter for it. When `projects` bands, the task list stays with the state columns in the first band and the second band is always PROJECT and ROOT. Console children receive the console's width
|
|
21
|
+
minus its four-column indent and remain uncolored.
|
|
22
|
+
|
|
6
23
|
## Command help
|
|
7
24
|
|
|
8
25
|
`ahub help`, `ahub --help` and `ahub -h` print the commands grouped by section;
|
|
@@ -46,6 +63,15 @@ a three-line footer, separated by ASCII `-` rules; the stream has one rule above
|
|
|
46
63
|
its footer. The active tab is bracketed, as in `[2 Approvals]`, so it reads
|
|
47
64
|
without color. The Approvals tab counts pending requests and the Queue tab
|
|
48
65
|
counts `needs_review` deliveries, in the attention and failure tones.
|
|
66
|
+
Tabs change with the digits 1 to 5 or with Left and Right (wrapping at both
|
|
67
|
+
ends), never while a command is being edited or a choice is open; under a
|
|
68
|
+
confirmation an arrow dismisses it like any key but y, without moving a tab. A pasted
|
|
69
|
+
chunk can only edit the command line, but a read that holds nothing but arrow
|
|
70
|
+
sequences is that many key presses, so a held key repeats its tab move. In the Events
|
|
71
|
+
tab a row's header line is tokenized and coloured exactly as the same event in
|
|
72
|
+
the stream; only the header is tab-flattened before tokenizing. Body lines retain
|
|
73
|
+
the previous rendering and stay plain, as does command output; colour never changes
|
|
74
|
+
what the panel's text says.
|
|
49
75
|
|
|
50
76
|
Peers, Approvals, Tasks and Queue are tables with a header row. A column is as
|
|
51
77
|
wide as its widest cell, up to a third of the terminal; the last column takes
|
|
@@ -78,7 +104,7 @@ prompts, are quoted unless they are a single word starting with a letter, so
|
|
|
78
104
|
punctuation, a newline or a bare number in them cannot imitate the console's own
|
|
79
105
|
structure. Under the `?` key table only `?`, Escape and `q` act.
|
|
80
106
|
|
|
81
|
-
|
|
107
|
+
Up/Down arrows or j/k move, Enter opens a detail of labeled fields (relative times,
|
|
82
108
|
never JSON), Escape returns, and `?` shows the keys grouped by panel; in the
|
|
83
109
|
stream, `?` prints that table and `v` prints the selected request as its push
|
|
84
110
|
showed it. The footer's last line lists only the keys that act in the current
|
|
@@ -199,10 +225,12 @@ Launch that peer with `ahub claude` for channel pushes, or select `codex` in
|
|
|
199
225
|
`roles` and launch `ahub codex`. The conductor splits work into owned tasks,
|
|
200
226
|
observes `hub_status`, moves stalled work and obtains review before reporting
|
|
201
227
|
results and open decisions. It does not implement the tasks it handed out.
|
|
202
|
-
`hub_peer_start` starts
|
|
203
|
-
|
|
204
|
-
the
|
|
205
|
-
|
|
228
|
+
`hub_peer_start` starts a peer in the start mode a person set for it (see
|
|
229
|
+
"Start modes"): local, Kimi and a headless Pi or Codex start at once; for a
|
|
230
|
+
TUI peer the hub opens a terminal running the fixed `ahub <peer>` command,
|
|
231
|
+
after validating it through the shared launcher planner, and when it cannot
|
|
232
|
+
open one the call fails with that command for the person to run. The
|
|
233
|
+
conductor cannot choose the mode. `hub_peer_hold` and `hub_peer_release`
|
|
206
234
|
manage only holds placed by that conductor. Assignment also requires `assign`
|
|
207
235
|
when the conductor has an explicit capabilities list.
|
|
208
236
|
|
|
@@ -213,7 +241,8 @@ final response in the native TUI. Broadcasting implementation instructions can
|
|
|
213
241
|
cause an otherwise unassigned owner to claim duplicate work.
|
|
214
242
|
|
|
215
243
|
The person answers approvals in the console, resolves `needs_review` deliveries
|
|
216
|
-
with `ahub queue resolve`,
|
|
244
|
+
with `ahub queue resolve`, stops a headless peer with `ahub stop`, and handles
|
|
245
|
+
budget overrides and hub lifecycle.
|
|
217
246
|
Running these commands from an agent shell is refused; the CLI retains the
|
|
218
247
|
agent's identity even when invoked through a shell tool.
|
|
219
248
|
|
|
@@ -286,6 +315,19 @@ project and a temp dir of their own (`TMPDIR`, made for each command and
|
|
|
286
315
|
removed when it ends; one left by a hub crash, named `ahub-cmd-*`, goes with
|
|
287
316
|
the OS temp cleanup), and nothing else; the shared temp dirs are closed.
|
|
288
317
|
|
|
318
|
+
Some names stay closed to those commands, and to Pi's, wherever they may
|
|
319
|
+
otherwise write: anything named `.git` at any depth, the `config` and `hooks`
|
|
320
|
+
directly under a `.git`, `commondir` below it, and `.agenthub` anywhere in the
|
|
321
|
+
project. A submodule's git directory under `.git/modules/` is not covered yet
|
|
322
|
+
(#281). A command can therefore not create, rename or remove a `.git`:
|
|
323
|
+
`git init`, `git clone` and `git worktree add` do not run inside the sandbox,
|
|
324
|
+
and neither do `git worktree remove`, `git worktree prune` of a stale record,
|
|
325
|
+
`git clean -ffd` over a nested repository or `rm -rf` of a directory that
|
|
326
|
+
holds a `.git`. `git add`, `commit`, `stash`, `checkout` and `gc` work, and
|
|
327
|
+
`.gitignore` and `.github/` stay writable; a commit that your git configuration
|
|
328
|
+
signs with a key under `~/.ssh` or `~/.gnupg` fails, because the sandbox cannot
|
|
329
|
+
read those directories. Run a refused command yourself, in a terminal.
|
|
330
|
+
|
|
289
331
|
Network is off unless `local.bash_network` says otherwise. With `true` it goes
|
|
290
332
|
only through the hub's egress proxy on a loopback port (0.11): commands get
|
|
291
333
|
`HTTPS_PROXY` and the other proxy variables, the proxy opens HTTPS (`CONNECT`,
|
|
@@ -337,7 +379,7 @@ Managed launchers attach native peers to the project daemon:
|
|
|
337
379
|
ahub claude
|
|
338
380
|
ahub codex
|
|
339
381
|
ahub kimi
|
|
340
|
-
ahub pi
|
|
382
|
+
ahub pi # its TUI; --headless for the background peer
|
|
341
383
|
ahub local
|
|
342
384
|
ahub local --model <served-model-id>
|
|
343
385
|
```
|
|
@@ -366,7 +408,19 @@ A delivery in `needs_review` holds later deliveries to that peer. The console an
|
|
|
366
408
|
the hold once, and status, task assignment and route explanations name its delivery id.
|
|
367
409
|
Inspect it with `ahub queue show <id>` and explicitly choose `completed`, `retry` or
|
|
368
410
|
`discard` through `ahub queue resolve`. Reassignment or approval of its task never
|
|
369
|
-
resolves an uncertain delivery automatically.
|
|
411
|
+
resolves an uncertain delivery automatically. The same rule holds on every path that
|
|
412
|
+
assigns a task (#297): once the move is saved on the board, a failed delivery prints
|
|
413
|
+
exactly one console notice ("the move is saved... delivery is not confirmed"), printed
|
|
414
|
+
where the error is thrown, and the caller (a peer in its turn, or the CLI) still gets
|
|
415
|
+
its error. Two exceptions, by construction: a move superseded while the assignment was being prepared, meaning a later history entry that moves or settles the task (another assignment, an unassign, the owner's accept, done, approval, close; the hub's quiet bookkeeping such as a late check result or a reviewer change does not supersede), is
|
|
416
|
+
the caller's error as before, with no notice naming either owner; and a claim is its own hand-over, so its
|
|
417
|
+
accepted write and line stay outside the delivery rule (its overlap and routing announcements to earlier
|
|
418
|
+
owners are deliveries and share it). The repair is always
|
|
419
|
+
to look for a queued or needs_review delivery with
|
|
420
|
+
`ahub queue list --peer <owner>` (then `ahub queue show <id>`, or the accepted entry in
|
|
421
|
+
`ahub task show <id>` if the journal itself is down) and then send the assignment again
|
|
422
|
+
with `ahub task assign <id> <owner>`. Nothing resends automatically: a blind resend can
|
|
423
|
+
duplicate a delivery that actually left.
|
|
370
424
|
|
|
371
425
|
Reviewer candidates follow `[classes.review].peers`, then attached peers with a
|
|
372
426
|
`reviewer` role in `roles`. The owner cannot review its own task. If none is available,
|
|
@@ -630,7 +684,7 @@ ahub undo <turn> --yes --context # Codex's latest turn: also drop it from Codex
|
|
|
630
684
|
has not removed yet included, and a PII file left in the project is
|
|
631
685
|
snapshotted by later turns like any other file. Keep PII files in an ignored
|
|
632
686
|
directory.
|
|
633
|
-
- A turn the hub stopped in the middle of shows
|
|
687
|
+
- A turn the hub stopped in the middle of shows the state `no end snapshot` and
|
|
634
688
|
cannot be undone.
|
|
635
689
|
- Claude's turns are not recorded: its channel shows the hub no turn boundary.
|
|
636
690
|
Claude Code's own checkpoints cover its edits, though not its shell commands.
|
|
@@ -881,12 +935,36 @@ Other tools retain native decisions, which may already allow a harmless shell.
|
|
|
881
935
|
Permission-only PreToolUse never marks Claude busy; former observation hooks
|
|
882
936
|
retain their native-turn role. Settings are passed as a 0600 state file retained
|
|
883
937
|
until that native launch exits. Live/unknown previous launchers keep their files;
|
|
884
|
-
verified dead wrapper and native identities permit crash cleanup.
|
|
938
|
+
verified dead wrapper and native identities permit crash cleanup. Managed direct
|
|
939
|
+
binary launches record their native PID while running; crash cleanup also requires
|
|
940
|
+
that PID to be absent from the process table. Scripts/interpreters and unavailable
|
|
941
|
+
process evidence retain the settings file. Every launch atomically replaces
|
|
942
|
+
`claude-launch.json` with its current managed hook/session identity. Native PID
|
|
943
|
+
proof is separate in a private `claude-native-<binding-hash>.json` file, so an old
|
|
944
|
+
callback cannot overwrite a newer launch record. Only that native proof uses
|
|
945
|
+
`claude-launch.lock`, published with its signed owner already written. It waits
|
|
946
|
+
up to 250 ms for a verified live owner. An empty, unsigned or unverifiable lock
|
|
947
|
+
is retained and disables native identity/crash cleanup for this launch; the
|
|
948
|
+
warning names the path and what is off. Managed hooks and session observations
|
|
949
|
+
still use the newly published launch record. Inspect the named lock and verify
|
|
950
|
+
its owner has ended before removing it; a signed dead lock is recovered. Without
|
|
885
951
|
separate native identity proof, old settings remain for manual inspection. Settings carry
|
|
886
952
|
no inline caller values in argv. Status reports an unverified Claude hook as
|
|
887
953
|
unverified. Unattended native sessions cannot take a runtime mode; restart
|
|
888
954
|
without that native flag. Codex must be behind the hub proxy, and returning to
|
|
889
|
-
ask requires a known native approval baseline.
|
|
955
|
+
ask while attached requires a known native approval baseline. If unavailable,
|
|
956
|
+
close the TUI, then run `ahub permission codex ask` before starting `ahub codex`.
|
|
957
|
+
For a known baseline, a detached proxy keeps restoration owed per thread and sends
|
|
958
|
+
that policy once on the resumed thread's next accepted turn. Visiting another thread
|
|
959
|
+
does not clear the debt. The restoring turn uses that kept baseline even if the
|
|
960
|
+
TUI echoes the resume response's sticky override, whether ask was selected before
|
|
961
|
+
or after that resume. Rejected turns retain it. The protection covers that one
|
|
962
|
+
restoring turn. A later TUI turn that repeats the policy looks exactly like a
|
|
963
|
+
person's explicit native policy choice and is passed through; the proxy cannot
|
|
964
|
+
resolve that ambiguity. An explicit choice on the restoring turn is delayed
|
|
965
|
+
until the following turn. A baseline that was never reported
|
|
966
|
+
is explained in the CLI reply, and that old thread keeps its last policy.
|
|
967
|
+
An offline or absent peer accepts
|
|
890
968
|
`ahub permission <peer> ask` to clear its hub choice. Codex --unattended launch
|
|
891
969
|
is refused under a non-ask choice; clear it with `ahub permission codex ask`
|
|
892
970
|
first. A pending never-ask default cannot be confirmed for an unattended launch.
|
|
@@ -918,6 +996,130 @@ permission_mode (peer/from/to) with no tool arguments under events schema 1.
|
|
|
918
996
|
The optional control requests preserve PROTOCOL; an older hub answers unknown
|
|
919
997
|
and the CLI advises upgrading.
|
|
920
998
|
|
|
999
|
+
## Settings from the dashboard and the terminal
|
|
1000
|
+
|
|
1001
|
+
The dashboard's Settings section and `ahub settings` show and change the same
|
|
1002
|
+
closed list of settings (issue #269). Run them from a plain terminal:
|
|
1003
|
+
|
|
1004
|
+
```bash
|
|
1005
|
+
ahub settings # every setting: value, source file, when it applies
|
|
1006
|
+
ahub settings get permission.kimi
|
|
1007
|
+
ahub settings set routing.classes.implement.peers codex,kimi,pi --preview
|
|
1008
|
+
ahub settings set routing.classes.implement.peers codex,kimi,pi
|
|
1009
|
+
ahub settings set permission_modes.kimi ask-when-needed
|
|
1010
|
+
ahub settings set research.enabled inherit # remove the machine-local value
|
|
1011
|
+
ahub settings undo # put back the file the last write changed
|
|
1012
|
+
ahub ui --settings # dashboard with a 15-minute settings session
|
|
1013
|
+
```
|
|
1014
|
+
|
|
1015
|
+
| Group | Keys | Stored in | Applies |
|
|
1016
|
+
| --- | --- | --- | --- |
|
|
1017
|
+
| Permissions | `permission.<peer>` (the mode now) | the running hub only | at once |
|
|
1018
|
+
| Permissions | `permission_modes.<peer>` (the mode at hub start) | `config.local.json` | next hub start |
|
|
1019
|
+
| Start | `peers.pi.start_mode`, `peers.codex.start_mode` (`tui` or `headless`) | `config.local.json` | that peer's next start |
|
|
1020
|
+
| Start | `pi.auto_start` | `config.local.json` | next hub start |
|
|
1021
|
+
| Routing | `routing.stay_switch`, `routing.classes.<class>.peers`, `.escalate_to`, `.route`, `.pi_backend` | `routing.local.toml` | at once |
|
|
1022
|
+
| Switches | `research.enabled`, `approvals.notify`, `snapshots.enabled`, `coordination` | `config.local.json` | next hub start |
|
|
1023
|
+
|
|
1024
|
+
- Writes go only to `.agenthub/config.local.json` and `.agenthub/routing.local.toml`,
|
|
1025
|
+
the machine-local files (`ahub init` ignores both in git). The shared
|
|
1026
|
+
`config.json` and the hand-written `routing.toml` are never rewritten, and a
|
|
1027
|
+
machine-local file that is committed to git is refused. Each write is read by
|
|
1028
|
+
the hub's own loader first and replaces the file atomically.
|
|
1029
|
+
- `routing.local.toml` overrides `routing.toml` key by key and may hold only the
|
|
1030
|
+
routing keys in the table. `ahub route explain` and the Settings rows name the
|
|
1031
|
+
file each value comes from. `--preview`, and the dashboard's Preview button,
|
|
1032
|
+
show `ahub route explain` for the open tasks before and after, or what a
|
|
1033
|
+
permission mode grants, and save nothing.
|
|
1034
|
+
- A row shows the value in force, its source file, when it applies, and for a
|
|
1035
|
+
value read at hub start what the next start will read (`Pending restart`).
|
|
1036
|
+
- `ahub settings undo` (the dashboard's "Undo last write") puts back the one
|
|
1037
|
+
previous version of the file the last write changed. It refuses when that
|
|
1038
|
+
file was edited since, and when it would put a stored never-ask back (set it
|
|
1039
|
+
again with its confirmation instead). A mode changed for the running hub is
|
|
1040
|
+
not a file: set it again instead. Setting a value it already has, or
|
|
1041
|
+
removing one that is not set, writes nothing. A project with no
|
|
1042
|
+
`.agenthub/config.json` gets no first config file from a settings write
|
|
1043
|
+
(any config file turns the project defaults on): run `ahub init` first.
|
|
1044
|
+
- A project initialised before 0.12.23 has no `.gitignore` line for
|
|
1045
|
+
`.agenthub/routing.local.toml`: run `ahub init` again, or add it. A
|
|
1046
|
+
`permission_modes` value is read only from a file git confirms nobody
|
|
1047
|
+
committed (config trust); where the hub will not read what was written, the
|
|
1048
|
+
reply and the Settings row say so.
|
|
1049
|
+
- Authority: a dashboard opened with `ahub ui` reads settings, lowers a mode to
|
|
1050
|
+
`ask`, turns `pi.auto_start` off, sets a start mode back to `tui` and changes
|
|
1051
|
+
the Switches group. Everything
|
|
1052
|
+
else needs `ahub ui --settings`, whose session may raise for 15 minutes, or
|
|
1053
|
+
`ahub settings` in a terminal. `never-ask` needs the peer id typed in the
|
|
1054
|
+
dashboard, or `--yes` in the terminal, and a stored never-ask default still
|
|
1055
|
+
waits for `y` in `ahub console` at each hub start. Tool approvals stay
|
|
1056
|
+
deny-only for Pi and local in every session.
|
|
1057
|
+
- Commands and binaries, credential files, gateway URLs and the local worker's
|
|
1058
|
+
reach are never editable here: edit `.agenthub/config.local.json` yourself.
|
|
1059
|
+
- Every change is announced in `hub.log` and open consoles with its source and
|
|
1060
|
+
recorded as a `settings` event. `ahub settings` needs a running hub; an older
|
|
1061
|
+
hub answers the request as unknown and the CLI advises upgrading. The unified
|
|
1062
|
+
dashboard (`ahub ui --all`) acts as an ordinary session.
|
|
1063
|
+
|
|
1064
|
+
## Start modes: TUI by default, headless as opt-in
|
|
1065
|
+
|
|
1066
|
+
A peer that has a TUI the hub attaches to starts in it by default (issue #269).
|
|
1067
|
+
|
|
1068
|
+
| Peer | Default | Headless |
|
|
1069
|
+
| --- | --- | --- |
|
|
1070
|
+
| pi | `tui` | `ahub pi --headless` (or `--mode headless`), or `peers.pi.start_mode: headless` |
|
|
1071
|
+
| codex | `tui` (`ahub codex`) | `peers.codex.start_mode: headless`: a hub-made start runs the app-server only |
|
|
1072
|
+
| claude | `tui` (`ahub claude`) | none |
|
|
1073
|
+
| kimi | headless (ACP) | it has no TUI the hub attaches to |
|
|
1074
|
+
| local | headless (hub-native) | not applicable |
|
|
1075
|
+
|
|
1076
|
+
- **You type the command:** `ahub pi` opens Pi's TUI in that terminal.
|
|
1077
|
+
`--headless` and the start mode setting are the two ways to ask for the
|
|
1078
|
+
background peer. `ahub settings set peers.pi.start_mode headless` writes the
|
|
1079
|
+
setting; it applies at Pi's next start.
|
|
1080
|
+
- **The hub starts the peer** (the dashboard's Start control, `pi` typed in
|
|
1081
|
+
`ahub console`, the conductor's `hub_peer_start`, `pi.auto_start`): it
|
|
1082
|
+
follows the peer's start mode. For `tui` it opens a terminal running the
|
|
1083
|
+
fixed command `ahub <peer>`, through a terminal provider:
|
|
1084
|
+
1. `terminal.open` in `.agenthub/config.local.json`, an argv in which one
|
|
1085
|
+
element holds `{command}` (the quoted command line to run); `{title}` and
|
|
1086
|
+
`{cwd}` are replaced too. Examples:
|
|
1087
|
+
`["tmux", "new-window", "-n", "{title}", "{command}"]`,
|
|
1088
|
+
`["wezterm", "start", "--cwd", "{cwd}", "--", "sh", "-c", "{command}"]`.
|
|
1089
|
+
Only a config file nobody committed may set it, and it is not a setting
|
|
1090
|
+
the dashboard or `ahub settings` can write. It is read at hub start.
|
|
1091
|
+
`{command}` is quoted for a POSIX shell; `{title}` and `{cwd}` are raw,
|
|
1092
|
+
so give each an argv element of its own.
|
|
1093
|
+
2. Orca, when the hub runs in an Orca worktree or an earlier `ahub <peer>`
|
|
1094
|
+
launch of this project recorded one (the path recovery uses).
|
|
1095
|
+
- **No provider:** the start is refused with the command to run by hand. It is
|
|
1096
|
+
never downgraded to headless. `ahub settings` lists each start mode, and the
|
|
1097
|
+
dashboard's Start control says which mode a start will use and where its
|
|
1098
|
+
terminal comes from.
|
|
1099
|
+
- **Dashboard Start:** the control is locked while its request is in flight. A confirmed answer unlocks it immediately, so a retry reaches the hub's own 30-second terminal reopen guard and shows any known refusal. The unified dashboard waits 35 seconds, covering a terminal provider's 30-second cap plus a 5-second response margin; a slower headless start can still end unconfirmed while the hub continues. Check the Peers panel before retrying. An unconfirmed unified-dashboard start holds that peer's control for the shared 30-second reopen bound, or until its `starts` snapshot confirms attachment, across redraws and project switches within the same hub instance; the row states the retry bound. The project-local dashboard keeps its usual confirmed-answer behavior. Other forwarded actions keep their 10-second wait; the manager opens no settings session.
|
|
1100
|
+
- The conductor cannot choose the mode: `hub_peer_start` takes the peer's own.
|
|
1101
|
+
- Recovery restores each peer in the mode its recorded session had. After an
|
|
1102
|
+
unplanned stop, a Pi that ran in a terminal is reported with its command and
|
|
1103
|
+
is not replaced by a headless one unless headless is its start mode.
|
|
1104
|
+
|
|
1105
|
+
### Migration from 0.12.22 and earlier
|
|
1106
|
+
|
|
1107
|
+
Pi's default changes from headless to its TUI.
|
|
1108
|
+
|
|
1109
|
+
- `ahub pi` in a terminal now opens the TUI. For the background peer run
|
|
1110
|
+
`ahub pi --headless`.
|
|
1111
|
+
- A project with `"pi": { "auto_start": true }` used to get a headless Pi at
|
|
1112
|
+
every hub start. To keep that, set the start mode once:
|
|
1113
|
+
`ahub settings set peers.pi.start_mode headless` (or add
|
|
1114
|
+
`"peers": { "pi": { "start_mode": "headless" } }` to
|
|
1115
|
+
`.agenthub/config.local.json`). Without it the hub opens Pi's TUI in a
|
|
1116
|
+
terminal at start, or, with no terminal provider, says
|
|
1117
|
+
`pi.auto_start did not start Pi` with the command to run.
|
|
1118
|
+
- Scripts and the console's `pi` command: without a terminal, `ahub pi` asks
|
|
1119
|
+
the hub to open one. Add `--headless` where a headless Pi is meant.
|
|
1120
|
+
- A conductor's `hub_peer_start` no longer takes a mode. A call that passes one
|
|
1121
|
+
is refused unless it repeats the peer's start mode.
|
|
1122
|
+
|
|
921
1123
|
## Approvals and pauses
|
|
922
1124
|
|
|
923
1125
|
Inspect permission requests in the terminal:
|
|
@@ -936,9 +1138,11 @@ ahub permit <request-id> allow
|
|
|
936
1138
|
|
|
937
1139
|
Use the exact option shown by `ahub tail`; do not approve an unresolved or
|
|
938
1140
|
unexpected request. On macOS a waiting request also raises a desktop
|
|
939
|
-
notification that names the peer and, for Kimi and the local worker, the tool,
|
|
1141
|
+
notification that names the peer and, for Kimi, Pi and the local worker, the tool,
|
|
940
1142
|
never what it would run. An unanswered request is cancelled after `approvals.timeout_s` (default
|
|
941
1143
|
120, 30 to 3600) in `.agenthub/config.json`, and the console and log say so.
|
|
1144
|
+
Pi and the local worker are told that nobody answered, and two such requests in
|
|
1145
|
+
a row end their turn ([Pi/local unanswered approvals](#pilocal-unanswered-approvals)).
|
|
942
1146
|
Set `approvals.notify` to `false` to turn notifications off; a hub started
|
|
943
1147
|
without a project config file raises none. While Kimi waits for an answer its
|
|
944
1148
|
turn is kept alive, so a timeout longer than the inactivity watchdog does not
|
|
@@ -955,6 +1159,13 @@ A budget pause remains authoritative until the budget command explicitly
|
|
|
955
1159
|
overrides it or the window resets. Check `ahub status` and `ahub board` after
|
|
956
1160
|
a pause or handoff.
|
|
957
1161
|
|
|
1162
|
+
Kimi Code CLI 2.1.1's observed 5-hour usage-limit refusal creates a hard budget reading (`kimi ACP usage-limit refusal`). `ahub status` shows a budget pause and `ahub budget` shows its source and reset estimate. The refusal gives no reset timestamp, so the hub estimates the reset at five hours after it was observed and resumes on the next budget tick after the existing one-minute grace. With `budget.wait_max_min` below that estimate, the existing budget relay automatically hands open tasks to an attached eligible peer; routing skips Kimi while paused. No checkpoint is requested from an exhausted agent.
|
|
1163
|
+
`ahub budget resume kimi` overrides the reading so the provider can be tried early. A new provider refusal ends that override and pauses it again; a pending soft checkpoint cannot postpone this hard pause.
|
|
1164
|
+
During one hub run, an early override followed by the same window's refusal keeps its earlier future reset bound; a provider's explicit reset remains authoritative. A restored pause without a per-window reading cannot identify that earlier window, so its next refusal starts a new estimate.
|
|
1165
|
+
Unread quota resume notices are coalesced without losing their public task moves; the next notice lists moves accumulated across those pauses. An older notice without structured move metadata is kept as public text inside that notice.
|
|
1166
|
+
|
|
1167
|
+
A refused prompt with no acceptance or activity is requeued without a review hold. At the estimated reset it is tried again; another quota refusal pauses it again without consuming the poison-envelope retry count. Work that already started remains held for review even while its open tasks move to other peers. After the quota reset its queue stays held: inspect `ahub queue show <delivery-id>` and the associated task, then choose `ahub queue resolve <delivery-id> --action completed|retry|discard --reason "<text>"`. Do not retry work that another owner already took over without inspecting it. If the hub cannot confirm the pause, the refusal is also held instead of spending retries. Other errors keep their ordinary review behavior. Only the observed Kimi 5-hour text is recognised; weekly/monthly limits and other ACP vendors, including Qwen, remain unverified. The recognised text and its provenance live in `src/adapters/acp-quota.ts`.
|
|
1168
|
+
|
|
958
1169
|
Quota also shapes routing and handoffs:
|
|
959
1170
|
|
|
960
1171
|
- Among peers a task could go to, those with quota readings are ordered by
|
|
@@ -1012,8 +1223,8 @@ Only `ahub claude` starts Claude Code with the development-channel flag. A
|
|
|
1012
1223
|
Claude session started another way (plain `claude`, an IDE) keeps the hub tools
|
|
1013
1224
|
but cannot show pushes, so it attaches tools-only (protocol 16, issue #205):
|
|
1014
1225
|
|
|
1015
|
-
- Its messages stay queued. `ahub status` shows
|
|
1016
|
-
messages wait for hub_inbox; for pushes restart Claude with ahub claude`; the
|
|
1226
|
+
- Its messages stay queued. `ahub status` shows the queue count in `Q` and a `tools-only` detail:
|
|
1227
|
+
`messages wait for hub_inbox; for pushes restart Claude with ahub claude`; the
|
|
1017
1228
|
console footer shows `tools-only: ahub claude` and the dashboard shows the
|
|
1018
1229
|
status line.
|
|
1019
1230
|
- The session reads them with `hub_inbox`, at most ten messages at a time plus
|
|
@@ -1044,11 +1255,15 @@ The daemon waits for shutdown work that must survive termination. Afterward,
|
|
|
1044
1255
|
run `ahub status` or `ahub up` and read the project state before restarting
|
|
1045
1256
|
peers. A stopped daemon does not delete task records or the durable journal.
|
|
1046
1257
|
Do not kill a native terminal by PID or start a replacement while ownership is
|
|
1047
|
-
uncertain.
|
|
1258
|
+
uncertain. To stop one headless peer and keep the hub running, use
|
|
1259
|
+
`ahub stop <peer>` ([Stop one headless peer](#stop-one-headless-peer)).
|
|
1048
1260
|
|
|
1049
1261
|
Shutdown is bounded: once it begins, a daemon that cannot finish within
|
|
1050
1262
|
15 seconds exits anyway, and a peer that refuses to stop is logged rather than
|
|
1051
|
-
allowed to block state cleanup. A
|
|
1263
|
+
allowed to block state cleanup. A managed Pi tool that does not settle within
|
|
1264
|
+
the stop grace does not block the teardown either: the stop goes on
|
|
1265
|
+
(shutdown, owner teardown, process stop) and reports the failure at the end.
|
|
1266
|
+
A native Pi TUI owner that does not exit
|
|
1052
1267
|
gracefully is terminated by its verified process identity (never a bare PID),
|
|
1053
1268
|
so a restarted hub never launches beside a survivor. A hub whose project root
|
|
1054
1269
|
or state directory was deleted stops itself within about 10 seconds; the
|
|
@@ -1169,23 +1384,38 @@ Rows without a live process are stale registrations; forget them with
|
|
|
1169
1384
|
|
|
1170
1385
|
## Upgrade and crash recovery
|
|
1171
1386
|
|
|
1387
|
+
On a terminal, one command reviews, applies and follows an upgrade:
|
|
1388
|
+
|
|
1389
|
+
```bash
|
|
1390
|
+
ahub upgrade
|
|
1391
|
+
```
|
|
1392
|
+
|
|
1393
|
+
Without `--to` the target is the registry's latest release. When that release is
|
|
1394
|
+
newer than the installed CLI, the CLI names the release's own coordinator
|
|
1395
|
+
(`bun x --package @staix/agent-hub@<version> ahub upgrade --to <version>`), asks,
|
|
1396
|
+
and hands over to it, so the version is never typed twice and an older CLI never
|
|
1397
|
+
coordinates. From an installed CLI older than 0.12.22, start it once by hand:
|
|
1398
|
+
`bunx --package @staix/agent-hub@<version> ahub upgrade`. The screens are
|
|
1399
|
+
described under [Interactive upgrade](#interactive-upgrade); the rest of this
|
|
1400
|
+
section is what they run.
|
|
1401
|
+
|
|
1172
1402
|
Upgrade running projects with the target release's own coordinator. It accepts
|
|
1173
1403
|
a running source on control protocol 9 (0.6.x), 10 (0.7.0 through 0.12.0),
|
|
1174
|
-
11 (0.12.1 and 0.12.2), 12 (0.12.3), 13 (0.12.4 through 0.12.15), 14 (0.12.16), 15 (0.12.17 through 0.12.19) or 16 (0.12.20
|
|
1404
|
+
11 (0.12.1 and 0.12.2), 12 (0.12.3), 13 (0.12.4 through 0.12.15), 14 (0.12.16), 15 (0.12.17 through 0.12.19) or 16 (0.12.20 through 0.12.23), and only
|
|
1175
1405
|
a target on its own protocol, so the target's coordinator fits every supported
|
|
1176
1406
|
source and carries every recovery fix released up to it. Protocol 8 and older
|
|
1177
1407
|
(0.5.x and earlier) are refused as `manual-bootstrap-required`. Run from the
|
|
1178
1408
|
project directory, without replacing the global CLI first:
|
|
1179
1409
|
|
|
1180
1410
|
```bash
|
|
1181
|
-
bunx --package @staix/agent-hub@0.12.
|
|
1182
|
-
bunx --package @staix/agent-hub@0.12.
|
|
1411
|
+
bunx --package @staix/agent-hub@0.12.23 ahub upgrade --to 0.12.23 --dry-run
|
|
1412
|
+
bunx --package @staix/agent-hub@0.12.23 ahub upgrade --to 0.12.23 --yes
|
|
1183
1413
|
```
|
|
1184
1414
|
|
|
1185
1415
|
| Running now | Coordinator to use |
|
|
1186
1416
|
| --- | --- |
|
|
1187
1417
|
| 0.6.x (protocol 9) | the target's, through `bunx` as above |
|
|
1188
|
-
| 0.7.0 through 0.12.0 (protocol 10), 0.12.1 and 0.12.2 (protocol 11), 0.12.3 (protocol 12), 0.12.4 through 0.12.15 (protocol 13), 0.12.16 (protocol 14), 0.12.17 through 0.12.19 (protocol 15), 0.12.20
|
|
1418
|
+
| 0.7.0 through 0.12.0 (protocol 10), 0.12.1 and 0.12.2 (protocol 11), 0.12.3 (protocol 12), 0.12.4 through 0.12.15 (protocol 13), 0.12.16 (protocol 14), 0.12.17 through 0.12.19 (protocol 15), 0.12.20 through 0.12.23 (protocol 16) | the target's, through `bunx` as above |
|
|
1189
1419
|
| any supported source, with the installed CLI already at the target | `ahub upgrade` below, which is the same coordinator |
|
|
1190
1420
|
| 0.5.x or earlier (protocol 8 and older) | not supported: bootstrap by hand with the matching CLI |
|
|
1191
1421
|
|
|
@@ -1217,21 +1447,27 @@ projects first:
|
|
|
1217
1447
|
|
|
1218
1448
|
```bash
|
|
1219
1449
|
ahub restart --dry-run
|
|
1220
|
-
ahub upgrade --to 0.12.
|
|
1450
|
+
ahub upgrade --to 0.12.23 --dry-run
|
|
1221
1451
|
```
|
|
1222
1452
|
|
|
1223
1453
|
Apply only after reviewing the plan:
|
|
1224
1454
|
|
|
1225
1455
|
```bash
|
|
1226
1456
|
ahub restart --yes
|
|
1227
|
-
ahub upgrade --to 0.12.
|
|
1228
|
-
ahub recovery status <operation-id>
|
|
1229
|
-
ahub recovery resume <operation-id>
|
|
1230
|
-
ahub recovery abort <operation-id>
|
|
1231
|
-
ahub recovery dispose <operation-id> --fresh-session <peer> --reason <text>
|
|
1232
|
-
ahub recovery dispose <operation-id> --stop-and-archive --reason <text>
|
|
1457
|
+
ahub upgrade --to 0.12.23 --yes
|
|
1458
|
+
ahub recovery status [<operation-id>]
|
|
1459
|
+
ahub recovery resume [<operation-id>]
|
|
1460
|
+
ahub recovery abort [<operation-id>]
|
|
1461
|
+
ahub recovery dispose [<operation-id>] --fresh-session <peer> --reason <text>
|
|
1462
|
+
ahub recovery dispose [<operation-id>] --stop-and-archive --reason <text>
|
|
1233
1463
|
```
|
|
1234
1464
|
|
|
1465
|
+
`--yes` needs `--to`; a dry run without `--to` plans the latest release. A target
|
|
1466
|
+
newer than the CLI is handed to that release's coordinator with the same flags,
|
|
1467
|
+
and the command is printed on stderr first. The `recovery` commands take the
|
|
1468
|
+
operation that holds the machine's lock when the id is left out, and say `no
|
|
1469
|
+
recovery operation holds the lock` when none does.
|
|
1470
|
+
|
|
1235
1471
|
The coordinator commits only once the source is quiet: no turn running, no
|
|
1236
1472
|
approval pending, no completion check queued or running. It waits up to 10
|
|
1237
1473
|
minutes and then aborts, leaving the source running; upgrade between long
|
|
@@ -1271,6 +1507,10 @@ runs under the deny-default sandbox, and `hub.log` and `ahub doctor` say so.
|
|
|
1271
1507
|
`local.bash_network: "direct"` still works until 0.13.0, and both name it while
|
|
1272
1508
|
it is set.
|
|
1273
1509
|
|
|
1510
|
+
0.12.22 closes the name `.git` to the local worker's and Pi's commands at any
|
|
1511
|
+
depth: `git init`, `git clone` and `git worktree add` no longer run inside the
|
|
1512
|
+
sandbox (the full list is under Install and start).
|
|
1513
|
+
|
|
1274
1514
|
The 0.7.0 transition stages the verified package and runs a retained
|
|
1275
1515
|
coordinator from the source tree. It accepts a verified protocol-9 source and
|
|
1276
1516
|
moves to a protocol-10 target. The source journal, queued envelopes, tasks,
|
|
@@ -1306,6 +1546,93 @@ Do not run an upgrade with an incompatible active protocol, an unverified
|
|
|
1306
1546
|
terminal binding, or an unresolved operation lock. Dry-run performs no package,
|
|
1307
1547
|
plugin, daemon, or terminal mutation.
|
|
1308
1548
|
|
|
1549
|
+
### Interactive upgrade
|
|
1550
|
+
|
|
1551
|
+
`ahub upgrade` and `ahub restart` are interactive when standard input and output
|
|
1552
|
+
are a terminal and neither `--dry-run` nor `--yes` is given. With either flag, or
|
|
1553
|
+
through a pipe, the JSON plan, the `ahub: blocker:` lines and the exit codes are
|
|
1554
|
+
unchanged. The screens add no way to change an operation: every choice runs one
|
|
1555
|
+
of the commands in this section for you, so that command's refusals decide.
|
|
1556
|
+
|
|
1557
|
+
The plan screen lists each project with its hub version and, per attached peer,
|
|
1558
|
+
its state, how it runs (`TUI` in a terminal the plan bound to its session,
|
|
1559
|
+
`headless` as the hub's own process, `own` for a session the hub did not
|
|
1560
|
+
launch or whose terminal the plan could not bind) and what happens to it: resumed in a new terminal (the old one is
|
|
1561
|
+
named), reconnecting by itself, restarted as a new session, restarted headless,
|
|
1562
|
+
or left offline. `in progress:` repeats what the running hub says keeps it from
|
|
1563
|
+
being quiet (busy peers, pending approvals, a peer starting, a budget
|
|
1564
|
+
transition; a hub of 0.12.22 or newer also names a task command, completion
|
|
1565
|
+
checks or Pi tool calls in flight, ready tasks being released and a Pi that has
|
|
1566
|
+
not settled); apply waits up to 10 minutes for it. Blockers follow, each with its
|
|
1567
|
+
next action. The choices are `[a] apply` (absent while a blocker stands), `[r]
|
|
1568
|
+
refresh`, `[k] end agents` (shown when an attached agent can be ended), `[j]`
|
|
1569
|
+
the plan as JSON, `[x] reset a project's hub` (shown when the plan has a running
|
|
1570
|
+
project) and `[q] quit`.
|
|
1571
|
+
|
|
1572
|
+
`[k] end agents` ends attached agents before the upgrade, so they are neither
|
|
1573
|
+
waited for nor restored: `t` for the TUI agents, `h` for the headless ones
|
|
1574
|
+
(Kimi, Pi in headless mode, the local worker), or their names, written
|
|
1575
|
+
`<project id>/<name>` when the plan covers more than one project. After a
|
|
1576
|
+
confirmation a TUI agent's terminal is closed, which cuts a turn in progress,
|
|
1577
|
+
and a headless agent is stopped by its hub through the `peer_stop` request
|
|
1578
|
+
(#278). A delivery that a busy agent had not settled is then held as
|
|
1579
|
+
`needs_review`, and its queue stays held until `ahub queue resolve` settles it. Each agent is ended only
|
|
1580
|
+
if the lock is free and its hub, its session and its terminal are still the
|
|
1581
|
+
ones the plan read; otherwise the screen says why it was left. A hub that does
|
|
1582
|
+
not know `peer_stop` (0.12.21 and older) cannot end a headless agent: the
|
|
1583
|
+
screen says so, the agent stops with the old hub at the upgrade, and the new
|
|
1584
|
+
hub starts it again. A session marked `own` is ended where it runs. The next
|
|
1585
|
+
plan shows the ended agents as offline.
|
|
1586
|
+
|
|
1587
|
+
After apply the command stays attached and prints each step as the receipt
|
|
1588
|
+
records it, and while a source is being prepared, what it still waits for.
|
|
1589
|
+
Enter opens the operation's screen while the runner works on. Ctrl+C leaves the
|
|
1590
|
+
command, at any prompt and while following, and never stops the runner: the
|
|
1591
|
+
`left:` line names the command that comes back to the screen, with the
|
|
1592
|
+
operation's own coordinator, because the installed `ahub` is the older release
|
|
1593
|
+
until the upgrade ends. A Ctrl+C between `a` and the start of the operation
|
|
1594
|
+
starts nothing. A prompt for a reason that is answered with
|
|
1595
|
+
Ctrl+C or the end of input ends nothing.
|
|
1596
|
+
|
|
1597
|
+
The operation's screen also opens first whenever an operation holds the lock,
|
|
1598
|
+
and for bare `ahub recovery`. It shows the phase and step, each project's phase
|
|
1599
|
+
and effect receipts and the error, then the choices that `status` lists under
|
|
1600
|
+
`next` for the same receipt and live state:
|
|
1601
|
+
|
|
1602
|
+
| Key | Runs | Offered when |
|
|
1603
|
+
| --- | --- | --- |
|
|
1604
|
+
| `r` | `recovery resume`, then follows | resume can get past what is live |
|
|
1605
|
+
| `c` | `recovery abort` | no runtime was stopped and no terminal effect or commit request is recorded |
|
|
1606
|
+
| `f` | `recovery dispose --fresh-session <peer>`, after a reason | a Codex or Claude restoration failed |
|
|
1607
|
+
| `e` | `recovery dispose --stop-and-archive`, after a confirmation and a reason | every unverified project reads as running, stopped or missing |
|
|
1608
|
+
| `x` | `e`, then the reset below | as `e` |
|
|
1609
|
+
| `w` | follows the runner | a runner holds the operation |
|
|
1610
|
+
|
|
1611
|
+
When more than one restoration failed, the second and later peers get
|
|
1612
|
+
`f-<peer>`. `s` refreshes the screen, `j` prints the receipt as JSON and `q`
|
|
1613
|
+
leaves the operation as it is.
|
|
1614
|
+
|
|
1615
|
+
While a runner is only waiting for its source to get quiet (step `prepare`, no
|
|
1616
|
+
effect recorded), `c` stops that runner and then aborts. It is offered only for
|
|
1617
|
+
a runner whose claim carries a process signature that still matches; a claim
|
|
1618
|
+
from a coordinator of 0.12.20 or older has none, so its pid is never signalled,
|
|
1619
|
+
and such a runner gives up its wait after 10 minutes. The receipt is read again
|
|
1620
|
+
when the key is pressed, and a runner that has moved on is left alone. If it
|
|
1621
|
+
records an effect in the instant between that read and the signal, the abort is
|
|
1622
|
+
refused and resume is offered instead. Past that step a running operation
|
|
1623
|
+
offers only `w`.
|
|
1624
|
+
|
|
1625
|
+
A reset is offered from the plan screen for a project whose hub is running, and
|
|
1626
|
+
with one question right after an operation was cancelled or ended from its
|
|
1627
|
+
screen: it asks for the project (when there are several) and the scope, prints
|
|
1628
|
+
the dry run of `ahub reset` or `ahub reset --all`, and applies it with `--yes`
|
|
1629
|
+
only after a second confirmation. While an operation holds the lock it refuses,
|
|
1630
|
+
as `ahub reset` does.
|
|
1631
|
+
|
|
1632
|
+
Ending a peer's running turn is not part of these screens: finish or interrupt
|
|
1633
|
+
it in that peer's terminal, answer approvals with `ahub permit` or the console,
|
|
1634
|
+
or cancel and upgrade later.
|
|
1635
|
+
|
|
1309
1636
|
### A partial operation
|
|
1310
1637
|
|
|
1311
1638
|
`ahub recovery status <operation-id>` reads the receipt without changing it:
|
|
@@ -1354,6 +1681,28 @@ next actions").
|
|
|
1354
1681
|
restart snapshot.
|
|
1355
1682
|
A second `resume` while its own hold still stands checks the peers again
|
|
1356
1683
|
before it closes anything.
|
|
1684
|
+
- If a restart stops with `database_busy`, the receipt stays `blocked` and
|
|
1685
|
+
carries `failure: { code: "database_busy", retryable: true, site: [...] }`.
|
|
1686
|
+
Let the other connection settle, inspect `ahub recovery status <id>` and
|
|
1687
|
+
use its offered `ahub recovery resume <id>`. Resume rechecks the source and
|
|
1688
|
+
reconciles a commit that may already have been requested. A busy read while
|
|
1689
|
+
that committed source is stopping stays inside the existing shutdown wait.
|
|
1690
|
+
A stop-and-archive that meets contention instead says to retry that
|
|
1691
|
+
disposition; resume remains refused while abandonment is partway. Successful
|
|
1692
|
+
abort, fresh-session choice and disposal clear the earlier failure annotation.
|
|
1693
|
+
Do not delete database files or start a second operation to bypass the lock.
|
|
1694
|
+
A failed installed-layout CI restart retains bounded, redacted fixture logs,
|
|
1695
|
+
receipt fields (including `commitSent` and failure frames) and file-mode
|
|
1696
|
+
metadata as a per-OS artifact.
|
|
1697
|
+
|
|
1698
|
+
The historical CI receipt (38061057253, attempt 1) kept no throw site or
|
|
1699
|
+
hub log. At its main, status/inspect RPC failures were swallowed and the
|
|
1700
|
+
synchronous catch sent a fixed sentence, so its raw SQLite text could only
|
|
1701
|
+
have come from the commit rejection or the runner's own `registry.db` read.
|
|
1702
|
+
"Resume | wait until the hub settles", without stop-and-archive, means its
|
|
1703
|
+
next inspection saw neither running nor stopped/missing. Which of the two
|
|
1704
|
+
paths, which statement and which holder remain unknown. The controlled
|
|
1705
|
+
rollback-copy reproduction is separate evidence, not that historical cause.
|
|
1357
1706
|
- When a target hub dies after it started (a crash or a reboot), `resume`
|
|
1358
1707
|
starts it again from the operation's snapshot while the project's state
|
|
1359
1708
|
directory still holds it: it records the restart (status shows `restarts`),
|
|
@@ -1492,8 +1841,9 @@ crash of one is not reported this way.
|
|
|
1492
1841
|
spends no cloud quota), and on a fresh session if that fails, keeping the
|
|
1493
1842
|
recorded backend and model; the report says which. Malformed records in
|
|
1494
1843
|
`sessions.json` are skipped. A Pi that ran in a terminal (`--mode tui`) is never started on its
|
|
1495
|
-
recorded session by the hub; the report gives the command
|
|
1496
|
-
`pi.auto_start` a fresh headless Pi starts instead
|
|
1844
|
+
recorded session by the hub; the report gives the command. With
|
|
1845
|
+
`pi.auto_start` a fresh headless Pi starts instead only when Pi's start mode
|
|
1846
|
+
is headless; with the default (tui) nothing is started in its place.
|
|
1497
1847
|
- Codex's app-server died with the hub; run `ahub codex` again. Claude Code's
|
|
1498
1848
|
plugin reconnects by itself while that session is open.
|
|
1499
1849
|
|
|
@@ -1620,7 +1970,7 @@ whose MLX slot is still busy after that wait goes to `dgx/fast` first (`source:
|
|
|
1620
1970
|
so does an enforced tool loop pinned to it (`source: "pin"`); without it nothing moves for load. `dgx/fast`
|
|
1621
1971
|
never goes first while it is cooling down, or while its own last dispatch failed in any way,
|
|
1622
1972
|
an error status or a failed stream included, until it succeeds or 30 s pass (`ahub status`:
|
|
1623
|
-
`
|
|
1973
|
+
a `dispatch held` detail with a relative time and `no load moves until then`). No load move or pin happens while the request
|
|
1624
1974
|
runs under an execution budget, and enforced, a load move happens only at a user turn. A moved
|
|
1625
1975
|
attempt gets 15 s to its response headers after the gateway lookup (OmniRoute's own probe,
|
|
1626
1976
|
up to two 4 s rounds when no gateway is cached) and is then abandoned for MLX, which serves
|
|
@@ -1634,7 +1984,7 @@ consecutive transport or startup failures outside a cooldown (a failure more tha
|
|
|
1634
1984
|
the last counted one starts the count over), a relay alias cools down for 30 s, doubling up to
|
|
1635
1985
|
5 min. A busy MLX slot and timeouts cut short by an execution budget never count; any HTTP
|
|
1636
1986
|
answer, a success or an error status, proves the transport works and ends the streak and the
|
|
1637
|
-
cooldown. `ahub status` shows `cooling
|
|
1987
|
+
cooldown. `ahub status` shows a `cooling` detail with a relative time and failure count and `events.jsonl`
|
|
1638
1988
|
records `cooldown` events.
|
|
1639
1989
|
Progress judgements suggest reassignment; they never change task ownership.
|
|
1640
1990
|
|
|
@@ -1774,7 +2124,8 @@ sequential seeded-guard job. Main and release jobs reuse only a successful full
|
|
|
1774
2124
|
PR or push check with the identical Git tree and all three successful jobs. An absent or
|
|
1775
2125
|
unreadable result runs the main gate again and refuses release. A manual
|
|
1776
2126
|
`prepare_bundle` dispatch builds reviewable plugin assets without publishing;
|
|
1777
|
-
it is never accepted as full-gate evidence.
|
|
2127
|
+
it is never accepted as full-gate evidence. A `timing_runs=20` dispatch runs only the daemon, PII screen and ACP
|
|
2128
|
+
test files twenty times on macOS, in its own concurrency group; it does not replace the full gate.
|
|
1778
2129
|
|
|
1779
2130
|
## Preview initialization and native launch
|
|
1780
2131
|
|
|
@@ -1803,9 +2154,19 @@ ownership, bind servers or start agents, sidecars or models.
|
|
|
1803
2154
|
`ahub status`, `ahub tail` and the dashboard show native context occupancy,
|
|
1804
2155
|
source and measurement freshness. Claude readings come from the status-line
|
|
1805
2156
|
tee installed by `ahub claude`; Codex readings come from its current thread's
|
|
1806
|
-
native token-usage updates.
|
|
2157
|
+
native token-usage updates. Kimi readings come from its ACP `usage_update`
|
|
2158
|
+
(`{used, size}`, source `acp_usage_update`): context occupancy, not
|
|
2159
|
+
consumption, so no token total is counted from it; the adapter accepts the
|
|
2160
|
+
update whenever it names the current session, because 2.1.1's source text
|
|
2161
|
+
emits it after the turn settles (read from the source, not yet observed live
|
|
2162
|
+
through the hub; docs/smoke.md), so the peer may already be idle.
|
|
2163
|
+
Pi and other unsupported surfaces show unknown.
|
|
1807
2164
|
A stale or disconnected reading is unknown, not 0%. Codex's accumulated session
|
|
1808
|
-
usage is never used as context occupancy.
|
|
2165
|
+
usage is never used as context occupancy. In the tail (`ahub tail` and the
|
|
2166
|
+
console's stream) a reading prints once and repeats only when the line changes
|
|
2167
|
+
apart from its time: the printed percentage, the freshness, the source, or known
|
|
2168
|
+
against unknown. Status, the Peers panel and the dashboard always read the
|
|
2169
|
+
latest reading with its time.
|
|
1809
2170
|
|
|
1810
2171
|
Context-triggered checkpoints are disabled by default. To enable them, add
|
|
1811
2172
|
this to `.agenthub/config.json` and restart the daemon deliberately:
|
|
@@ -1817,8 +2178,9 @@ this to `.agenthub/config.json` and restart the daemon deliberately:
|
|
|
1817
2178
|
`gate` is a fraction between 0 and 1; 0 disables checkpoint requests.
|
|
1818
2179
|
`stale_min` must be positive. A reading at or above the threshold records a metadata-only
|
|
1819
2180
|
event and console notice, then asks an attached Claude/Codex with active work
|
|
1820
|
-
for a checkpoint when no checkpoint request is already outstanding
|
|
1821
|
-
|
|
2181
|
+
for a checkpoint when no checkpoint request is already outstanding (an ACP peer
|
|
2182
|
+
such as Kimi gets the event and notice only; no checkpoint request is sent to it
|
|
2183
|
+
yet). The request supplies a `request_id`; include that id with
|
|
1822
2184
|
`hub_checkpoint {summary, request_id}`. Repeated high readings do not repeat
|
|
1823
2185
|
it until a fresh below-threshold reading or new session rearms the crossing.
|
|
1824
2186
|
|
|
@@ -1849,13 +2211,88 @@ Pi exit records show code or signal, turn/tool activity, whether teardown was
|
|
|
1849
2211
|
expected, startup status, and the last tool's name without arguments. An
|
|
1850
2212
|
unobserved native-terminal exit records unknown OS status. The console notice
|
|
1851
2213
|
gives the next action, usually `ahub pi`, or says why automatic start is held.
|
|
1852
|
-
A
|
|
1853
|
-
|
|
2214
|
+
A replacement says the owner stopped for a new Pi owner, including when the
|
|
2215
|
+
replacement is refused. Internal failure teardown directs session inspection
|
|
2216
|
+
rather than claiming a person requested it. Replacement, failed-start and
|
|
2217
|
+
active-turn guidance appears before automatic-start-disabled guidance.
|
|
1854
2218
|
|
|
1855
2219
|
With `pi.auto_start`, an unexpectedly idle headless Pi is resumed on its
|
|
1856
2220
|
verified persisted session once. The 60-second retry window rearms when the
|
|
1857
2221
|
attempt settles; a second exit inside that window stays offline. Missing or
|
|
1858
2222
|
invalid session history has no fresh fallback; inspect it before running
|
|
1859
2223
|
`ahub pi`. Active turns/tools, failed startup, a superseded owner, native
|
|
1860
|
-
terminal exits, requested
|
|
1861
|
-
restart. Crash recovery's #66
|
|
2224
|
+
terminal exits, a requested stop (`ahub stop pi`), requested shutdown and
|
|
2225
|
+
recovery operations suppress this restart. Crash recovery's #66
|
|
2226
|
+
recorded-session/fresh-start choices are unchanged.
|
|
2227
|
+
|
|
2228
|
+
### Pi/local unanswered approvals
|
|
2229
|
+
|
|
2230
|
+
An expired Pi/local request says "approval expired: no person answered". The
|
|
2231
|
+
worker must not retry that call; hand the task off or stop. Two consecutive
|
|
2232
|
+
unanswered requests end the current turn and produce a console notice. An
|
|
2233
|
+
expiry counts only when no person answered a request of that peer while it
|
|
2234
|
+
was pending, so a batch of parallel requests does not stop a worker whose
|
|
2235
|
+
person is answering; a grant served from the always-allow cache or a permission
|
|
2236
|
+
mode is not an answer and does not reset the count. A new turn also resets it. The turn ends
|
|
2237
|
+
through the same abort path an execution-budget stop uses: Pi stays attached
|
|
2238
|
+
and the sender is told the approval reason. Supported Pi and local settle that
|
|
2239
|
+
delivery after reporting the reason, so the next queued message runs without
|
|
2240
|
+
an operator release. Pi clears turn-only approval state at settlement; the
|
|
2241
|
+
person's idle `!command` remains usable and a later failure keeps its own reason.
|
|
2242
|
+
A Pi whose extension cannot abort
|
|
2243
|
+
a turn (an older hub extension or a runtime without native abort support) goes
|
|
2244
|
+
offline instead. Inspect prior work, restart with `ahub pi`, find the held
|
|
2245
|
+
delivery with `ahub queue list --peer pi`, inspect it with `ahub queue show <id>`,
|
|
2246
|
+
then explicitly settle it with `ahub queue resolve <id> --action completed|retry|discard --reason "<text>"`.
|
|
2247
|
+
A cancelled tool withdraws
|
|
2248
|
+
its request immediately; a later `ahub permit` answer is refused and cannot
|
|
2249
|
+
create an always-allow grant. Tool requests from a previous turn or an older
|
|
2250
|
+
extension missing session/turn identity are refused before execution; restart
|
|
2251
|
+
Pi with the current hub extension rather than retrying that old call.
|
|
2252
|
+
|
|
2253
|
+
The dashboard shows the number of waiting Pi/local requests and where to
|
|
2254
|
+
answer them. It remains deny-only for those private rows. Use the console or
|
|
2255
|
+
`ahub tail` to inspect the request, then `ahub permit` to answer it. Recovery
|
|
2256
|
+
stops waiting for an approval when that request is withdrawn.
|
|
2257
|
+
|
|
2258
|
+
A person's `!command` in the managed Pi TUI runs through the managed sandbox
|
|
2259
|
+
without asking for another hub approval. Its reported exit code comes from
|
|
2260
|
+
the process, including a nonzero exit; text printed by the command does not
|
|
2261
|
+
set its status. This exception requires the current idle TUI owner's reserved
|
|
2262
|
+
request and does not apply to model-origin bash calls.
|
|
2263
|
+
|
|
2264
|
+
### Stop one headless peer
|
|
2265
|
+
|
|
2266
|
+
`ahub stop kimi`, `ahub stop pi` (headless mode), or `ahub stop local` stops
|
|
2267
|
+
that hub-owned runtime through its adapter and prints `<peer>: offline`.
|
|
2268
|
+
The hub and its other peers keep running. The command is human-only;
|
|
2269
|
+
agent shells and tools-role connections cannot use the `peer_stop` request.
|
|
2270
|
+
An older hub that does not know the request needs an upgrade before this
|
|
2271
|
+
command is available.
|
|
2272
|
+
|
|
2273
|
+
Claude, Codex and Pi in TUI mode belong to their native terminals: end them
|
|
2274
|
+
in those terminals. The upgrade plan's end-agents action closes a TUI through
|
|
2275
|
+
its verified terminal binding and uses `peer_stop` for a headless runtime.
|
|
2276
|
+
Unknown and already-offline peers are refused with a next action. A recovery
|
|
2277
|
+
operation or shutdown holds stop mutations; finish that operation first.
|
|
2278
|
+
A peer's concurrent start, stop or permission-mode change must also finish
|
|
2279
|
+
before another lifecycle change is admitted, and an upgrade or restart does not
|
|
2280
|
+
prepare the hub while a stop is in progress.
|
|
2281
|
+
|
|
2282
|
+
A requested stop does not automatically restart a peer. A person or an authorized
|
|
2283
|
+
conductor can explicitly start it again; conductor starts remain permitted. Start it with
|
|
2284
|
+
`ahub kimi`, `ahub pi` or `ahub local`. Pending approvals are withdrawn before
|
|
2285
|
+
teardown. An in-flight delivery becomes `needs_review`, with a reason naming
|
|
2286
|
+
the requested stop; it is neither completed nor automatically replayed.
|
|
2287
|
+
Inspect partial effects with `ahub queue list --peer <peer>` and
|
|
2288
|
+
`ahub queue show <delivery-id>`, then explicitly choose `completed`, `retry`
|
|
2289
|
+
or `discard` with `ahub queue resolve`. Restarting alone does not release
|
|
2290
|
+
that held delivery. Work queued behind an idle stopped peer is retained and
|
|
2291
|
+
runs when it is started again, subject to its existing pauses and holds. New work
|
|
2292
|
+
arriving during teardown stays queued too, even if a console resume runs meanwhile.
|
|
2293
|
+
An idle Pi with no message/file yet records its live empty-session proof before
|
|
2294
|
+
stopping, so its next start resumes that identity. A Pi stopped after its first
|
|
2295
|
+
prompt was accepted but before history was persisted is not treated as empty:
|
|
2296
|
+
its delivery is held, and another start refuses until resume history is verified.
|
|
2297
|
+
Inspect and settle the held delivery before deliberately replacing that unpersisted
|
|
2298
|
+
session by restarting the hub; the stop never silently chooses a fresh session.
|