@staix/agent-hub 0.12.42 → 0.12.44
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 +30 -0
- package/README.md +5 -4
- package/docs/adding-an-ai-tool.md +140 -0
- package/docs/agent-notes/README.md +5 -0
- package/docs/agent-notes/adapters.md +11 -4
- package/docs/agent-notes/budget.md +2 -2
- package/docs/agent-notes/bus.md +2 -0
- package/docs/agent-notes/daemon.md +15 -6
- package/docs/agent-notes/tasks.md +7 -2
- package/docs/agent-notes/tests.md +6 -2
- package/docs/operations.md +159 -26
- package/docs/quickstart.md +11 -3
- package/docs/sdlc.md +1 -1
- package/docs/security.md +7 -5
- package/docs/specs/2026-09-19-agent-hub-design.md +209 -13
- package/docs/verification/2026-10-21-0.12.43.md +50 -0
- package/docs/verification/2026-10-21-0.12.44.md +54 -0
- package/docs/verification/2026-10-21-agy-1.4.3-t0.md +65 -0
- package/docs/verification/2026-10-21-grok-config-acp-t0.md +30 -0
- package/docs/verification/2026-10-21-pii-screen.md +14 -0
- package/docs/verified.json +34 -19
- package/package.json +1 -1
- package/plugins/agent-hub/.claude-plugin/plugin.json +1 -1
- package/plugins/agent-hub/server.js +808 -255
- package/src/adapters/acp-owned-group.ts +124 -0
- package/src/adapters/acp.ts +92 -25
- package/src/adapters/agy/definition.ts +1 -3
- package/src/adapters/agy/entry.ts +4 -1
- package/src/adapters/agy/hooks.ts +7 -2
- package/src/adapters/channel-peer.ts +143 -0
- package/src/adapters/claude-channel.ts +7 -7
- package/src/adapters/codex-appserver.ts +16 -2
- package/src/adapters/configured-acp.ts +124 -0
- package/src/adapters/definitions/builtin-metadata.ts +37 -33
- package/src/adapters/definitions/native-channel-state.ts +41 -0
- package/src/adapters/definitions/native-cli-entry-kimi.ts +3 -1
- package/src/adapters/definitions/native-cli-preview-qwen.ts +1 -1
- package/src/adapters/definitions/native-identity-defaults.ts +14 -0
- package/src/adapters/definitions/qwen.ts +3 -8
- package/src/adapters/definitions/reviewer-variants.ts +3 -7
- package/src/adapters/jcode.ts +4 -0
- package/src/adapters/local-worker.ts +4 -0
- package/src/adapters/pi.ts +50 -16
- package/src/adapters/registry-types.ts +18 -16
- package/src/adapters/registry.ts +68 -6
- package/src/adapters/reviewer-print.ts +4 -0
- package/src/cli/agy-mcp.ts +3 -2
- package/src/cli/completion.ts +173 -0
- package/src/cli/configured-acp-entry.ts +58 -0
- package/src/cli/console-state.ts +116 -24
- package/src/cli/console.ts +9 -6
- package/src/cli/facts-hook.ts +2 -1
- package/src/cli/help.ts +8 -1
- package/src/cli/identity.ts +8 -7
- package/src/cli/launch.ts +5 -4
- package/src/cli/main.js +5 -1
- package/src/cli/main.ts +84 -27
- package/src/cli/memory.ts +13 -10
- package/src/cli/output.ts +1 -0
- package/src/cli/preview.ts +9 -0
- package/src/cli/recovery-guidance.ts +1 -1
- package/src/cli/terminal-recovery.ts +33 -21
- package/src/cli/upgrade-restore-state.ts +3 -2
- package/src/cli/upgrade-runtime.ts +21 -6
- package/src/cli/upgrade.ts +3 -2
- package/src/hub/board.ts +9 -6
- package/src/hub/budget.ts +9 -2
- package/src/hub/bus.ts +6 -2
- package/src/hub/claude-state.ts +2 -37
- package/src/hub/conductor.ts +8 -6
- package/src/hub/config-apply.ts +26 -14
- package/src/hub/config-reload.ts +39 -11
- package/src/hub/config-trust.ts +1 -1
- package/src/hub/context-window.ts +6 -0
- package/src/hub/control-client.ts +1 -1
- package/src/hub/crash.ts +8 -6
- package/src/hub/daemon.ts +471 -338
- package/src/hub/hub-tools.ts +37 -1
- package/src/hub/instance-config.ts +20 -11
- package/src/hub/instance-execution.ts +4 -4
- package/src/hub/instances.ts +45 -21
- package/src/hub/lifecycle-schema.ts +5 -3
- package/src/hub/main-checkout.ts +2 -2
- package/src/hub/manager.ts +10 -2
- package/src/hub/memory-profile.ts +16 -3
- package/src/hub/no-writes.ts +50 -0
- package/src/hub/permission-mode.ts +9 -7
- package/src/hub/roster.ts +7 -4
- package/src/hub/routing.ts +21 -20
- package/src/hub/settings.ts +51 -17
- package/src/hub/snapshots.ts +276 -17
- package/src/hub/start-mode.ts +10 -8
- package/src/hub/task-sweep.ts +8 -2
- package/src/hub/tasks.ts +101 -19
- package/src/memory/capture.ts +2 -1
- package/src/ui/index.html +5 -0
- package/templates/AGENTS.block.md +1 -1
- package/templates/profiles/general.json +1 -1
- package/templates/profiles/research.json +1 -1
- package/templates/profiles/writing.json +1 -1
package/docs/operations.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Operations guide
|
|
2
2
|
|
|
3
|
-
This guide describes ahub 0.12.
|
|
3
|
+
This guide describes ahub 0.12.43 and control protocol 16. Live verification
|
|
4
4
|
results and remaining prerequisites are recorded separately in [the smoke ledger](smoke.md).
|
|
5
5
|
|
|
6
6
|
## Agent-operated live verification
|
|
@@ -93,6 +93,27 @@ cyan, arguments and descriptions the terminal's default foreground. It has no
|
|
|
93
93
|
not `dumb` and `NO_COLOR` is empty or absent. Pipes and redirects get plain text
|
|
94
94
|
without escape sequences, laid out for 80 columns.
|
|
95
95
|
|
|
96
|
+
### Shell completion
|
|
97
|
+
|
|
98
|
+
`ahub completion zsh|bash|fish` prints a completion script; it never installs
|
|
99
|
+
files or edits shell configuration. On each Tab the script runs
|
|
100
|
+
`ahub __complete`, which answers from the help entries above (commands,
|
|
101
|
+
subcommands, options, their listed values and file names for path arguments)
|
|
102
|
+
without loading the rest of the CLI or contacting a hub, so completion always
|
|
103
|
+
matches the installed `ahub`. Agent shells may print the script too.
|
|
104
|
+
|
|
105
|
+
```sh
|
|
106
|
+
# zsh: any directory on fpath works; this one needs no .zshrc change with oh-my-zsh
|
|
107
|
+
ahub completion zsh > ~/.oh-my-zsh/custom/completions/_ahub && rm -f ~/.zcompdump* && exec zsh
|
|
108
|
+
# bash
|
|
109
|
+
ahub completion bash > ~/.local/share/bash-completion/completions/ahub
|
|
110
|
+
# fish
|
|
111
|
+
ahub completion fish > ~/.config/fish/completions/ahub.fish
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
Upgrading ahub needs no regeneration. To remove it, delete that file and start
|
|
115
|
+
a new shell.
|
|
116
|
+
|
|
96
117
|
## Operator console and panels
|
|
97
118
|
|
|
98
119
|
`ahub console` combines the existing tail stream with peer, quota, approval-age
|
|
@@ -121,7 +142,7 @@ without color. The Approvals tab counts pending requests and the Queue tab
|
|
|
121
142
|
counts `needs_review` deliveries, in the attention and failure tones.
|
|
122
143
|
|
|
123
144
|
The console attention companion (#280) shows waiting, blocked, review, working,
|
|
124
|
-
idle or asleep with separate action/watch counts. `n` selects the exact approval,
|
|
145
|
+
idle or asleep with separate action/watch counts. Outside the Tasks table, `n` selects the exact approval,
|
|
125
146
|
held queue or review row, or prints applicable guidance; it never answers a
|
|
126
147
|
request or runs a command. Editing, choices and confirmation retain their controls.
|
|
127
148
|
`P` cycles the five built-in characters and off for the current console.
|
|
@@ -145,7 +166,8 @@ chunk can only edit the command line, but a read that holds nothing but arrow or
|
|
|
145
166
|
Home/End sequences is that many key presses, so a held key repeats its move. Home
|
|
146
167
|
or `<` jumps to a panel's first row and End or `>` to its last; the Events tab
|
|
147
168
|
follows new events while the last row is selected and stays on a row you moved to.
|
|
148
|
-
`w` opens the dashboard
|
|
169
|
+
`w` opens the dashboard outside the Peers tab; in Peers it edits the selected
|
|
170
|
+
peer's WIP limit. `o` opens the pet window; `:ui --all` and `:pet --window --close`
|
|
149
171
|
work on the command line too. In the Peers tab the planner's row reads `(planner)`, and
|
|
150
172
|
`l` then `y` makes the selected peer the planner (`ahub settings set planner <peer>`). In the Events
|
|
151
173
|
tab a row's header line is tokenized and coloured exactly as the same event in
|
|
@@ -160,14 +182,54 @@ meter keeps a fixed column at the right edge.
|
|
|
160
182
|
|
|
161
183
|
| Panel | Columns |
|
|
162
184
|
|---|---|
|
|
163
|
-
| Peers | PEER STATE MODE LINK Q ! REVIEW PAUSE QUOTA MODEL |
|
|
185
|
+
| Peers | PEER STATE MODE LINK Q ! WIP REVIEW PAUSE QUOTA MODEL |
|
|
164
186
|
| Approvals | ID PEER LEFT TITLE |
|
|
165
187
|
| Tasks | ID STATE OWNER REVIEWER CLASS AGE TITLE STAGE |
|
|
188
|
+
| Tasks, backlog view (`b`) | ID PRI RESERVED DEPS CLASS AGE TITLE |
|
|
166
189
|
| Queue | ID PEER STATE REV AGE |
|
|
167
190
|
| Settings | GROUP KEY VALUE SOURCE APPLIES |
|
|
168
191
|
|
|
192
|
+
In Tasks, `b` toggles open work and backlog. The backlog heading counts its rows;
|
|
193
|
+
rows sort by rank, then id. PRI shows priority/rank, RESERVED the reserved peer,
|
|
194
|
+
and DEPS either `ready` or the unapproved dependency ids. Titles use the public
|
|
195
|
+
board projection, so PII work remains `[pii]`. Narrow layouts keep ID, RESERVED
|
|
196
|
+
and TITLE before the other columns.
|
|
197
|
+
|
|
198
|
+
On a backlog row, `p` prefills `backlog pull-ready <id> <planningRevision> <reason>`,
|
|
199
|
+
`a` prefills `backlog plan` with a reservation JSON object, and `e` prefills the
|
|
200
|
+
same command with priority, rank and deps. Edit the JSON and supply a reason;
|
|
201
|
+
`c` uses the existing revision-bound `task cancel` command. Once pulled into open
|
|
202
|
+
work, `a` uses the usual task assignment flow. In either Tasks view, `n` prefills
|
|
203
|
+
`backlog add implement `; edit the class and title, or use
|
|
204
|
+
`:task propose --backlog` with paths/deps flags. On proposed or in-progress open
|
|
205
|
+
work, `R` prefills `backlog return <id>` for an ownerless proposal, or the
|
|
206
|
+
planning-revision-and-reason form for accepted, untouched work. The hub refuses
|
|
207
|
+
returns with execution, branch or commit evidence; its refusal appears as a notice.
|
|
208
|
+
|
|
209
|
+
These actions run the existing person CLI commands, after explicit confirmation;
|
|
210
|
+
Esc sends nothing. Row-prefilled ids and revisions cannot be edited, and stale
|
|
211
|
+
row revisions require a reload. `:backlog list` reads without confirmation;
|
|
212
|
+
backlog mutations (including pull, pull-ready, return, plan, split and undo)
|
|
213
|
+
confirm first. The console adds no write path or planner authority.
|
|
214
|
+
|
|
169
215
|
The MODE column appears only when at least one peer has a non-`ask` mode.
|
|
170
|
-
|
|
216
|
+
Peers' WIP column shows planner work in progress as `wip/limit` from `taskWip`,
|
|
217
|
+
including `0/2`; a peer without an entry reads `-`. At or above the limit, the
|
|
218
|
+
cell uses the attention tone. At narrow widths WIP gives way before PEER, STATE
|
|
219
|
+
and QUOTA, whether or not MODE is present.
|
|
220
|
+
|
|
221
|
+
In Peers, select a row and press `w` to edit `tasks.wip_limits.<peer>`, prefilled
|
|
222
|
+
with its current limit. The editor stays on Peers and uses the existing Settings
|
|
223
|
+
value, daemon preview, nonempty reason and `y` confirmation flow; Esc cancels without writing. The
|
|
224
|
+
setting definition supplies the bounds (currently 0..32), risk label (`raises`)
|
|
225
|
+
and `applies: live`; the shortcut adds no configuration write path. The Peers
|
|
226
|
+
hint reads `w WIP limit` and shortens to `w WIP` at narrow widths, alongside
|
|
227
|
+
`m permission mode` shortening to `m mode`. Without a `taskWip` entry, `w` shows
|
|
228
|
+
a notice and opens no edit. Press `6`, then `u` to preview and confirm the usual
|
|
229
|
+
Settings undo. These controls remain person-only, and `ahub settings` retains
|
|
230
|
+
its agent-shell refusal.
|
|
231
|
+
|
|
232
|
+
Other zero counters and unknown values read `-`. Durations read `45s`, `12m`, `3h05m`
|
|
171
233
|
or `2d03h`; quota resets and budget pauses read `in 2h13m`, and a pause by the
|
|
172
234
|
console user reads `user`. When a peer's status carries #205's optional
|
|
173
235
|
`toolsOnly` field (a Claude session attached without channel pushes), LINK reads
|
|
@@ -899,7 +961,12 @@ later. Your own `ahub task assign` is not blocked by those exclusions, and it
|
|
|
899
961
|
drops the agent's reservation. The PII constraint and capability limits
|
|
900
962
|
still apply, so a PII task goes to `local` or nobody whoever was reserved.
|
|
901
963
|
`ahub task assign` on a task that waits changes its reserved owner instead of
|
|
902
|
-
handing it over.
|
|
964
|
+
handing it over. On a task that does not wait, an assignment whose named owner cannot take
|
|
965
|
+
the task now (offline or not attached, excluded, a capability or PII limit, or
|
|
966
|
+
an enforce-mode SDLC gap) is refused with the reason and the task is unchanged;
|
|
967
|
+
assign again once the peer is attached (#601). When a proposal names an owner,
|
|
968
|
+
a self-claim included, and that owner did not get the task, the proposal's
|
|
969
|
+
result says why and names `hub_task_assign`. `ahub route explain <id>` names the reserved owner; once the
|
|
903
970
|
task is ready it also says whether routing would honor the reservation now, and
|
|
904
971
|
why not.
|
|
905
972
|
|
|
@@ -1080,6 +1147,7 @@ ahub undo <turn> --yes --context # Codex's latest turn: also drop it from Codex
|
|
|
1080
1147
|
Nothing is restored then. It plans again right before restoring and stops if
|
|
1081
1148
|
anything moved meanwhile. A turn that is already undone says so.
|
|
1082
1149
|
- A file the turn created is deleted; a file it deleted comes back.
|
|
1150
|
+
- When HEAD moves during a turn, the hub reads the appended HEAD reflog (bounded to 64 moves and 128 KiB). The turn's own commits, amends, cherry-picks and rebase picks still count as its changes. Files brought in by a pull, merge, rebase start, branch checkout or fast-forward reset are left out, unless they are still dirty at the turn's end. An unreadable or ambiguous reflog, a rewinding reset, or a file touched by both kinds of move makes the turn's files unknown (#576).
|
|
1083
1151
|
- `--context` asks Codex (`thread/revert`) to drop the turn, and every later one,
|
|
1084
1152
|
from its thread's saved history before the files are restored; Codex receives
|
|
1085
1153
|
nothing while that runs. It changes no file itself, works only on Codex's
|
|
@@ -1093,7 +1161,11 @@ ahub undo <turn> --yes --context # Codex's latest turn: also drop it from Codex
|
|
|
1093
1161
|
snapshotted by later turns like any other file. Keep PII files in an ignored
|
|
1094
1162
|
directory.
|
|
1095
1163
|
- A turn the hub stopped in the middle of shows the state `no end snapshot` and
|
|
1096
|
-
cannot be undone.
|
|
1164
|
+
cannot be undone. So does a turn whose boundary evidence is unknown: snapshot
|
|
1165
|
+
Git calls made in one callback burst share a 250 ms budget, and a capture that
|
|
1166
|
+
runs past it, fails, or sees HEAD move while it is taken is unknown, never a
|
|
1167
|
+
stale baseline (hub.log says `snapshot unavailable` once per burst). A turn
|
|
1168
|
+
whose diff or HEAD-move evidence cannot be read is unknown as well (#576).
|
|
1097
1169
|
- Claude's turns are not recorded: its channel shows the hub no turn boundary.
|
|
1098
1170
|
Claude Code's own checkpoints cover its edits, though not its shell commands.
|
|
1099
1171
|
- The snapshots are unreferenced objects in the repository's own object store, so
|
|
@@ -1516,7 +1588,7 @@ A guarded file edit that the daemon keeps at its accepted value remains visible
|
|
|
1516
1588
|
| Routing | `routing.stay_switch`, `routing.classes.<class>.peers`, `.escalate_to`, `.route`, `.pi_backend` | `routing.local.toml` | at once |
|
|
1517
1589
|
| Switches | `research.enabled`, `approvals.notify`, `snapshots.enabled` | `config.local.json` | live, without disturbing an active turn |
|
|
1518
1590
|
| Switches | `coordination` | `config.local.json` | newly created tasks only |
|
|
1519
|
-
| Switches | `task_sweep.enabled`, `.auto_reassign`, `.interval_s`, `.unaccepted_min`, `.idle_min`, `.review_min`, `.ready_min`, `.ladder_min` | `config.local.json` | live;
|
|
1591
|
+
| Switches | `task_sweep.enabled`, `.auto_reassign`, `.interval_s`, `.unaccepted_min`, `.idle_min`, `.review_min`, `.ready_min`, `.ladder_min`, `.no_writes_turns` | `config.local.json` | live; `.no_writes_turns` sets the turn threshold independently; other keys reschedule the sweep timer |
|
|
1520
1592
|
| Routing | `tasks.wip_limits.<peer>` | `config.local.json` | live |
|
|
1521
1593
|
| Routing | `tasks.escalate_after` (1-10, default 3: consecutive `changes_requested` before a task moves to the next `escalate_to` peer) | `config.local.json` | live; the next verdict uses it |
|
|
1522
1594
|
| Roles | `planner` (the one peer that plans) | `config.local.json` | at once |
|
|
@@ -1618,6 +1690,15 @@ A peer that has a TUI the hub attaches to starts in it by default (issue #269).
|
|
|
1618
1690
|
never downgraded to headless. `ahub settings` lists each start mode, and the
|
|
1619
1691
|
dashboard's Start control says which mode a start will use and where its
|
|
1620
1692
|
terminal comes from.
|
|
1693
|
+
- **A headless start gets a watch pane** (#286 AC10): when the hub itself
|
|
1694
|
+
starts Kimi or Qwen headless (Kimi when its start mode is `headless`), it
|
|
1695
|
+
also opens `ahub watch <peer>` through the same provider, a fixed command
|
|
1696
|
+
with no caller text, at most once per 30 seconds per peer. The headless
|
|
1697
|
+
start has already succeeded, so with no provider, or one that fails, the
|
|
1698
|
+
start still stands and its result and the hub's notice give the command to
|
|
1699
|
+
run by hand. A start in TUI mode opens the peer's own terminal instead, as
|
|
1700
|
+
above; an already attached peer, a declared extra instance and a peer
|
|
1701
|
+
without the watch capability open no pane.
|
|
1621
1702
|
- **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.
|
|
1622
1703
|
- The conductor cannot choose the mode: `hub_peer_start` takes the peer's own.
|
|
1623
1704
|
- Recovery restores each peer in the mode its recorded session had. After an
|
|
@@ -2044,21 +2125,21 @@ section is what they run.
|
|
|
2044
2125
|
|
|
2045
2126
|
Upgrade running projects with the target release's own coordinator. It accepts
|
|
2046
2127
|
a running source on control protocol 9 (0.6.x), 10 (0.7.0 through 0.12.0),
|
|
2047
|
-
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.
|
|
2128
|
+
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.43), and only
|
|
2048
2129
|
a target on its own protocol, so the target's coordinator fits every supported
|
|
2049
2130
|
source and carries every recovery fix released up to it. Protocol 8 and older
|
|
2050
2131
|
(0.5.x and earlier) are refused as `manual-bootstrap-required`. Run from the
|
|
2051
2132
|
project directory, without replacing the global CLI first:
|
|
2052
2133
|
|
|
2053
2134
|
```bash
|
|
2054
|
-
bunx --package @staix/agent-hub@0.12.
|
|
2055
|
-
bunx --package @staix/agent-hub@0.12.
|
|
2135
|
+
bunx --package @staix/agent-hub@0.12.43 ahub upgrade --to 0.12.43 --dry-run
|
|
2136
|
+
bunx --package @staix/agent-hub@0.12.43 ahub upgrade --to 0.12.43 --yes
|
|
2056
2137
|
```
|
|
2057
2138
|
|
|
2058
2139
|
| Running now | Coordinator to use |
|
|
2059
2140
|
| --- | --- |
|
|
2060
2141
|
| 0.6.x (protocol 9) | the target's, through `bunx` as above |
|
|
2061
|
-
| 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.
|
|
2142
|
+
| 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.43 (protocol 16) | the target's, through `bunx` as above |
|
|
2062
2143
|
| any supported source, with the installed CLI already at the target | `ahub upgrade` below, which is the same coordinator |
|
|
2063
2144
|
| 0.5.x or earlier (protocol 8 and older) | not supported: bootstrap by hand with the matching CLI |
|
|
2064
2145
|
|
|
@@ -2090,14 +2171,14 @@ projects first:
|
|
|
2090
2171
|
|
|
2091
2172
|
```bash
|
|
2092
2173
|
ahub restart --dry-run
|
|
2093
|
-
ahub upgrade --to 0.12.
|
|
2174
|
+
ahub upgrade --to 0.12.43 --dry-run
|
|
2094
2175
|
```
|
|
2095
2176
|
|
|
2096
2177
|
Apply only after reviewing the plan:
|
|
2097
2178
|
|
|
2098
2179
|
```bash
|
|
2099
2180
|
ahub restart --yes
|
|
2100
|
-
ahub upgrade --to 0.12.
|
|
2181
|
+
ahub upgrade --to 0.12.43 --yes
|
|
2101
2182
|
ahub recovery status [<operation-id>]
|
|
2102
2183
|
ahub recovery resume [<operation-id>]
|
|
2103
2184
|
ahub recovery abort [<operation-id>]
|
|
@@ -2174,7 +2255,7 @@ A lost commit or start reply is reconciled against the actual daemon identity,
|
|
|
2174
2255
|
package digest, terminal binding, and phase receipt. An uncertain terminal
|
|
2175
2256
|
creation is never repeated blindly. Recovery retains the exact-pinned first-party memory package with the preserved runtime, includes its identity and bytes in the digest, and refuses missing, symlinked or changed retained dependencies instead of resolving a mutable ancestor/global installation. It does not copy the full dependency tree.
|
|
2176
2257
|
|
|
2177
|
-
After creating a managed terminal, the coordinator saves its exact handle, incarnation and worktree before waiting up to 600 seconds (10 minutes) for authenticated attachment to the expected target hub and conversation. A pending or failed creation receipt also waits when the current target has a verified live launcher; its saved binding retains the pending/failed origin across interruption. An idle terminal alone is not attachment proof. Without a current launch record, a confirmed-ended row for another terminal and an attached session still reporting no id keep the chosen terminal waiting within the same bound; a late matching record continues that wait. Live replacement and unreadable records still block. Only non-offline session ids count, and older-instance launchers are checked before declaring a launch gone. Timeout retains the binding and diagnostic receipt; resume waits on that same binding rather than opening a duplicate.
|
|
2258
|
+
After creating a managed terminal, the coordinator saves its exact handle, incarnation and worktree before waiting up to 600 seconds (10 minutes) for authenticated attachment to the expected target hub and conversation. A pending or failed creation receipt also waits when the current target has a verified live launcher; its saved binding retains the pending/failed origin across interruption. An idle terminal alone is not attachment proof: after idle, the coordinator re-reads the launch record and Orca's identity every second within the same bound, until the terminal maps to the expected session or contradicts it (#599). Without a current launch record, a confirmed-ended row for another terminal and an attached session still reporting no id keep the chosen terminal waiting within the same bound; a late matching record continues that wait. Live replacement and unreadable records still block. Only non-offline session ids count, and older-instance launchers are checked before declaring a launch gone. Timeout retains the binding and diagnostic receipt; resume waits on that same binding rather than opening a duplicate.
|
|
2178
2259
|
|
|
2179
2260
|
The wait checks the selected launcher's signed identity on each poll. When that exact launcher exits and the target confirms no session or other live launcher, a pending-origin wait (including a new terminal) records failure and offers the failed-restoration choices, including fresh-session for Codex or Claude. A failed-origin wait returns to its existing retry path. A replacement terminal, missing or unreadable launcher identity, unreadable target or different attached conversation blocks without treating unknown as gone. Success clears the waiting origin and preserves exact terminal/session revalidation. A launcher from an older target instance still blocks without another terminal. The 10-minute limit matches terminal creation readiness; terminal idle can precede native resume and MCP handshake completion. The zero-turn Claude exception still applies only when no original transcript exists. If Claude shows its development-channel confirmation screen, confirm it in
|
|
2180
2261
|
the captured terminal, then run `ahub recovery resume <operation-id>`; resume must not open a duplicate terminal.
|
|
@@ -2484,9 +2565,11 @@ next actions").
|
|
|
2484
2565
|
gone. One that dies before recording itself leaves no record to read, and
|
|
2485
2566
|
what happens next depends on whether Orca reports the bare login shell it
|
|
2486
2567
|
returned to as TUI-idle, which is not verified. If it does, the coordinator
|
|
2487
|
-
|
|
2488
|
-
|
|
2489
|
-
|
|
2568
|
+
re-reads the terminal's mapping every second (#599) and stops at once only when
|
|
2569
|
+
Orca names another peer or session; otherwise it stops with "original session
|
|
2570
|
+
restoration needs manual verification" (the terminal cannot be mapped to the
|
|
2571
|
+
session) when the 10-minute wait ends. If it does not, it stops with the same
|
|
2572
|
+
error after the 10-minute wait. Either way the receipt stays
|
|
2490
2573
|
`pending`; close that terminal in Orca (or wait, if the session may still
|
|
2491
2574
|
attach), then `resume`: with no live launcher and no attached session it
|
|
2492
2575
|
records `restored:<peer>` `failed` and lists the failed-restoration choices.
|
|
@@ -2825,6 +2908,8 @@ The daemon advertises `task_cancel`; a current CLI refuses cancellation against
|
|
|
2825
2908
|
|
|
2826
2909
|
## Task idle sweep
|
|
2827
2910
|
|
|
2911
|
+
Writing-owner no-op detection (#498) is independent of the time sweep: `task_sweep.no_writes_turns` defaults to 2, and 0 disables its notices. Known file changes, HEAD/shared-branch ref movement and task-tool effects reset the streak. A canonical snapshot with recorded branch, worktree-path or PR/head evidence is unknown. Negative canonical evidence also needs exclusive worktree scope and no `.worktrees` directory, so uncommitted work in a separate checkout is not reported as empty. Done advisories use the first acceptance in the current ownership span; plan updates do not discard earlier touches.
|
|
2912
|
+
|
|
2828
2913
|
The between-turn task sweep (#186) is disabled by default. Set `task_sweep` in
|
|
2829
2914
|
`.agenthub/config.json` (or its machine-local override) to enable it:
|
|
2830
2915
|
|
|
@@ -2944,7 +3029,7 @@ PR or push check with the identical Git tree and all three successful jobs. An a
|
|
|
2944
3029
|
unreadable result runs the main gate again and refuses release. A manual
|
|
2945
3030
|
`prepare_bundle` dispatch builds reviewable plugin assets without publishing;
|
|
2946
3031
|
it is never accepted as full-gate evidence. A `timing_runs=20` dispatch runs only the daemon, PII screen and ACP
|
|
2947
|
-
test files twenty times on macOS, in its own concurrency group; it does not replace the full gate.
|
|
3032
|
+
test files twenty times on macOS, in its own concurrency group; it does not replace the full gate. Each PR has its own CI concurrency group, so PRs run side by side; within a PR a newer pending run replaces the older pending one and an admitted run is never cancelled; main pushes and dispatches keep queueing every run. Two groups admitting the same tree at once may run it twice, never a false green (#609). `scripts/check.sh --changed [<base>]` runs every non-test step but only the affected test files, and the full suite when it cannot tell; the full gate stays CI's (#610).
|
|
2948
3033
|
`scripts/check.sh` stops a suite still running after `AHUB_CHECK_HANG_S` seconds
|
|
2949
3034
|
(960 by default); hosted CI sets 1080 on Linux and 1260 on macOS inside a 25-minute
|
|
2950
3035
|
job limit (#378, #593).
|
|
@@ -2989,7 +3074,7 @@ consumption, so no token total is counted from it; the adapter accepts the
|
|
|
2989
3074
|
update whenever it names the current session, because 2.1.1's source text
|
|
2990
3075
|
emits it after the turn settles (read from the source, not yet observed live
|
|
2991
3076
|
through the hub; docs/smoke.md), so the peer may already be idle.
|
|
2992
|
-
Pi and other unsupported surfaces show unknown.
|
|
3077
|
+
Pi, Qwen (until a native source is verified, #625) and other unsupported surfaces show unknown.
|
|
2993
3078
|
A stale or disconnected reading is unknown, not 0%. Codex's accumulated session
|
|
2994
3079
|
usage is never used as context occupancy. In the tail (`ahub tail` and the
|
|
2995
3080
|
console's stream) a reading prints once and repeats only when the line changes
|
|
@@ -3207,7 +3292,7 @@ Modes: ask maps to default, scoped frequency maps to auto-edit, never-ask maps t
|
|
|
3207
3292
|
yolo. Qwen yolo approves every tool outside any hub sandbox; its own vendor bounds
|
|
3208
3293
|
apply. Auto and plan are not hub mode mappings. Unknown quota refusals are not
|
|
3209
3294
|
classified as authoritative quota; until a real pinned refusal is recorded, pause
|
|
3210
|
-
by hand.
|
|
3295
|
+
by hand. Context occupancy shows unknown until a native source is verified; it no longer uses Kimi's usage parser (#625). Roles
|
|
3211
3296
|
do not establish that Qwen can reliably replace Kimi before the live leg.
|
|
3212
3297
|
|
|
3213
3298
|
Qwen controlled recovery and automatic crash resume load the recorded conversation with ACP session/load. The emitted launcher passes --session-id; a controlled plan with a missing or unsafe identity refuses before effects. Preview redacts the id. A custom executable argv keeps its wrapper arguments before appended model flags. Native recovery remains unverified.
|
|
@@ -3235,18 +3320,58 @@ Native policy is unmanaged and has NO hub sandbox; no permission_modes.jcode or
|
|
|
3235
3320
|
|
|
3236
3321
|
## Optional Antigravity (agy) peer
|
|
3237
3322
|
|
|
3238
|
-
Antigravity is optional and off roster by default. Use `ahub roster add agy`, then run `ahub agy` in a terminal: it runs the Antigravity CLI as a fresh pull-only TUI in that terminal. It accepts the 1.4.x line: 1.4.2 is the verified version, any other 1.4.x launches with a stderr warning (agy updates itself), and other versions are refused (#589). The running hub must advertise `native_hook_launch`; an older hub refuses before any write with an upgrade-or-restart remedy. Only the person's launcher starts it: conductor starts are refused, there is no controlled restore or resume, and
|
|
3323
|
+
Antigravity is optional and off roster by default. Use `ahub roster add agy`, then run `ahub agy` in a terminal: it runs the Antigravity CLI as a fresh pull-only TUI in that terminal. It accepts the 1.4.x line: 1.4.2 is the verified version, any other 1.4.x launches with a stderr warning (agy updates itself), and other versions are refused (#589). The running hub must advertise `native_hook_launch`; an older hub refuses before any write with an upgrade-or-restart remedy. Only the person's launcher starts it: conductor starts are refused, there is no controlled restore or resume, and a declared agy extra instance is refused when the config loads (#625). Headless/print, resume (`--conversation`, `--continue`, `--new`), `--mode`, `--dangerously-skip-permissions` and `--unattended` are refused until their native mapping is verified; `--print-command` previews without writing.
|
|
3239
3324
|
|
|
3240
3325
|
The launcher writes exactly `plugin.json`, `mcp_config.json` and `hooks.json` in `.agents/plugins/agent-hub/`, refusing linked or foreign entries before any write, and removes only its own matching files when the TUI ends. It never writes project-level `.agents/hooks.json` or the person's `~/.gemini` settings. Run `ahub init` afterwards to ignore the untracked plugin directory; a tracked plugin is written with a warning. The native model sees the hub tools under the server name `agent-hub_agent-hub`.
|
|
3241
3326
|
|
|
3242
|
-
Like Kimi's TUI, agy is pull-only: it reads `hub_inbox` and shares results with `hub_send`, messages do not interrupt it, and automatic routing never picks it. Its roles are capped at implementer and verifier; a plan or review assignment and PII work are refused. Native permissions are unmanaged, with no hub sandbox, hub permission mode, quota source or session resume. Plugin hooks bound to that launch carry the hub's turn facts and report each completed native turn. The live TUI/account leg is unverified ([T0 receipt](verification/2026-10-19-agy-p1-t0.md)).
|
|
3327
|
+
Like Kimi's TUI, agy is pull-only: it reads `hub_inbox` and shares results with `hub_send`, messages do not interrupt it, and automatic routing never picks it. Its roles are capped at implementer and verifier; a plan or review assignment and PII work are refused. Native permissions are unmanaged, with no hub sandbox, hub permission mode, quota source or session resume. Plugin hooks bound to that launch carry the hub's turn facts and report each completed native turn. A native read is recorded as a peer `Read` fact: `view_file` (`AbsolutePath`) in 1.4.2 and `read_file` (`Path`) in 1.4.3; a `StartLine`/`EndLine` range counts as a partial read, never a whole-file view (#555). The live TUI/account leg is unverified ([T0 receipt](verification/2026-10-19-agy-p1-t0.md)). The 1.4.3 T0 re-run keeps 1.4.3 unverified: its `call_mcp_tool` schema and native tool names changed, and the TUI attaches the hub tools only from the second model turn ([1.4.3 receipt](verification/2026-10-21-agy-1.4.3-t0.md), #607).
|
|
3328
|
+
|
|
3329
|
+
## Configured ACP adapters (#451 A3)
|
|
3330
|
+
|
|
3331
|
+
A tool that speaks standard ACP over stdio can join a project without a code change. The declaration is machine-local authority: put it only in an untracked `.agenthub/config.local.json` (in `config.json` or a tracked file it is ignored with a notice), then restart the hub. The hub compiles its adapter catalog once at startup, so adding, changing or removing a declaration needs a restart; settings list the change as pending restart and never edit `adapters`.
|
|
3332
|
+
|
|
3333
|
+
{
|
|
3334
|
+
"adapters": {
|
|
3335
|
+
"myagent": {
|
|
3336
|
+
"transport": "acp",
|
|
3337
|
+
"command": "/opt/myagent/bin/myagent",
|
|
3338
|
+
"args": ["acp"],
|
|
3339
|
+
"displayName": "My Agent",
|
|
3340
|
+
"roles": ["implementer", "verifier"],
|
|
3341
|
+
"identity": { "name": "<initialize agentInfo.name>", "version": "<agentInfo.version>" },
|
|
3342
|
+
"permission": { "ask": "<native mode id>", "ask-when-needed": "<native mode id>", "never-ask": "<native mode id>" },
|
|
3343
|
+
"readOnly": "<native read-only mode id>"
|
|
3344
|
+
}
|
|
3345
|
+
}
|
|
3346
|
+
}
|
|
3347
|
+
|
|
3348
|
+
- The kind matches `[a-z][a-z0-9-]`, has at most 32 characters, and may not collide with a builtin peer, an `ahub` command or a reserved id. A project can declare at most 64 kinds. Unknown fields refuse the config.
|
|
3349
|
+
- `roles` is a non-empty subset of `planner`, `implementer`, `verifier` and `reviewer`. `conductor` is refused here; only explicit project role policy can appoint one.
|
|
3350
|
+
- `identity` is the name and version that ACP `initialize` reports. A start without it, or with a mismatch, refuses before any prompt.
|
|
3351
|
+
- `args` may not select a leader, attach, connect or remote mode (`--leader*`, `--attach*`, `--connect*`, `--remote*`): only a foreground process the hub owns is supported. A Grok declaration (kind `grok`, a `grok` executable or identity name `grok`) must also pass a standalone `--no-leader` before any `--`. Grok 1.0.62 itself is not supported ([T0 receipt](verification/2026-10-21-grok-config-acp-t0.md)).
|
|
3352
|
+
- `permission` maps hub modes to native ACP mode ids. Only mapped modes can be selected, and the session must advertise and acknowledge each one. Without a map (or with an empty one) native policy is unmanaged: `ahub permission <kind> <mode>` and `permission_modes.<kind>` are refused. No hub sandbox applies either way.
|
|
3353
|
+
- `readOnly` names the native mode that read-only instances use (below). It is not applied to the kind itself.
|
|
3354
|
+
|
|
3355
|
+
ahub roster add myagent # configured kinds are off roster by default
|
|
3356
|
+
ahub myagent # headless; asks the running hub to start it
|
|
3357
|
+
ahub myagent --session-id <id> # load a recorded native session; the agent must echo the id
|
|
3358
|
+
ahub myagent --print-command # preview: executable, argv and session id are withheld
|
|
3359
|
+
ahub stop myagent
|
|
3360
|
+
|
|
3361
|
+
`ahub <kind>` accepts only `--mode headless`, `--as <instance>`, `--session-id <id>` and one of `--print-command`/`--dry-run`; model, route, unattended and other launch overrides are refused. The running hub must advertise `configured_acp` and list the kind as loaded; otherwise the command tells you to upgrade or restart. If the file changed since the hub started, the start warns and uses the running definition. A conductor may start the kind with `hub_peer_start` (headless, with no session override). There is no TUI form: `peers.<kind>.start_mode` accepts only `headless`, and `ahub watch` is not available. Default routing never picks a configured kind; it gets work through its roles, an explicit owner or reviewer, or a reservation.
|
|
3362
|
+
|
|
3363
|
+
Before admission the hub verifies the native identity, a valid session id, the requested native mode and positive ownership of the spawned process and its process group. A failure refuses the start with a generic reason; the agent's stderr and error text are withheld from the log. `ahub stop` signals only that original verified group. If teardown cannot be confirmed, the peer stays offline but held, and new starts are refused until `ahub stop <kind>` succeeds.
|
|
3364
|
+
|
|
3365
|
+
Extra instances use the existing `instances` block. For example, `"myagent-review": { "kind": "myagent", "roles": ["reviewer"], "readOnly": true }` is started with `ahub myagent --as myagent-review`. Unlike the kind, a declared instance is on the roster by default. `readOnly: true` requires the kind's `readOnly` mode, and the session must advertise and acknowledge that mode before a prompt. Native permission requests other than read, search and think are rejected. The instance is offered only `hub_send`, `hub_inbox`, `hub_delivery_done`, `hub_review`, `hub_task_show`, `hub_task_list`, `hub_memory_search|show|graph` and `hub_status`; the hub refuses every other hub tool. Its permission mode is locked: settings show it as read-only, no write, undo or `ahub permission` changes it, and `permission_mode` next to `readOnly` is refused.
|
|
3366
|
+
|
|
3367
|
+
Configured kinds are cloud peers and never receive PII work. Quota and context are unknown, and a kind with no budget source is exempt from quota accounting, so pause it by hand if its provider refuses. After a crash the hub resumes a recorded session through `session/load` only when the agent echoes the same id, and it never reuses a recorded model. Controlled recovery (`ahub upgrade`, `restart`, `recovery`) refuses a running configured kind: stop it, then start it again with its session id. While the project declares adapters, the upgrade or restart target must advertise `configured_acp`.
|
|
3243
3368
|
|
|
3244
3369
|
# Headless ACP watch (#286)
|
|
3245
3370
|
|
|
3246
3371
|
- A person opens `ahub watch kimi` or `ahub watch qwen` in a second terminal. `--no-thoughts` hides thought items; `--color=auto|always|never` controls colour. `q` or Ctrl+C leaves the view, keeping the peer running. Answer approvals in `ahub console` or with `ahub permit`.
|
|
3247
3372
|
- Watch replays bounded memory history from this daemon, then displays live updates. It is the hub's read-only view, with no prompt input. It does not read native session files.
|
|
3248
3373
|
- Kimi's default is its own pull-only TUI (#316). Watch requires `ahub kimi --mode headless`; its own TUI remains visible in its native terminal. Qwen requires roster participation and verified ACP 0.25.0. `ahub qwen --mode tui` remains refused.
|
|
3249
|
-
- Protocol stays 16; a same-protocol older daemon answers the new request as unknown, which the CLI reports.
|
|
3374
|
+
- Protocol stays 16; a same-protocol older daemon answers the new request as unknown, which the CLI reports. Since 0.12.44 a headless start that the hub itself makes for Kimi or Qwen opens this view automatically through the terminal provider (see Start modes; #286).
|
|
3250
3375
|
- Native T0 limits: [ACP watch verification](verification/2026-10-11-acp-watch-t0.md).
|
|
3251
3376
|
|
|
3252
3377
|
# Acceptance-criteria checklist (#481)
|
|
@@ -3416,7 +3541,7 @@ unapproved dependencies, frozen scope and overriding person P0 order/reservation
|
|
|
3416
3541
|
The person uses `ahub backlog pull-ready <id> <revision> <reason>` or Pull within
|
|
3417
3542
|
WIP on a card. Explicit manual pull/assignment retain their existing authority.
|
|
3418
3543
|
|
|
3419
|
-
Capacity defaults to one per peer. `ahub settings set tasks.wip_limits.codex 2`
|
|
3544
|
+
Capacity defaults to one per peer. Each declared instance has its own `tasks.wip_limits.<instance>` key. `ahub settings set tasks.wip_limits.codex 2`
|
|
3420
3545
|
uses the existing machine-local registry path; integers 0..32 apply live (the next
|
|
3421
3546
|
admission reads the current value), with 0 disabling planner admission for that
|
|
3422
3547
|
peer. Status and the agent legend count
|
|
@@ -3498,7 +3623,7 @@ recovery action can be shown. The output never resumes, aborts or disposes a run
|
|
|
3498
3623
|
Person-reviewed tasks contribute review actions; an offline peer holding
|
|
3499
3624
|
unfinished work contributes one watch item with its lowest task id. The console
|
|
3500
3625
|
receives those structural facts through its existing authenticated status reply.
|
|
3501
|
-
`n` selects an exact visible review task, or prints the task/review guidance if
|
|
3626
|
+
Outside the Tasks table, `n` selects an exact visible review task, or prints the task/review guidance if
|
|
3502
3627
|
that row is unavailable. Offline guidance names status/task reads and an explicit
|
|
3503
3628
|
assignment command. No command is executed by navigation. There is no extra
|
|
3504
3629
|
console poll, timer or task-list request for stream mode.
|
|
@@ -3753,3 +3878,11 @@ blocks that undo until the identity and workspace can be reviewed.
|
|
|
3753
3878
|
Use `ahub sdlc train report <release-id>` for scope readiness and recorded release metrics. The planner creates future release rows, activates one train, and assigns tasks through the release-only hub tools. A due date requests a cut review; it never clears unfinished work. Move missed tasks to the next row with a reason, then use `ahub sdlc train cut <release-id> <revision>` from the person's terminal or `hub_release_cut` as the planner. The cut retains a short host admission lease through freeze and defers on held gate slots or unknown/quota-limited peer windows with a real quota source. Accounts without a quota reader (Kimi included when `kimi_tokens_5h` is zero) report `no quota source`; manual and budget-record pauses still defer. It does not run release preparation or publish anything. Schedule bundle/check/docs work under separate heavy admission and retain the person's native verification, authorization and upgrade window. A hotfix records its enumerated cause and keeps every gate.
|
|
3754
3879
|
|
|
3755
3880
|
The per-release "gates run" record is deferred to S6/S7. Person ruling 2026-10-19 supersedes the earlier S11 upgrade-admission ruling: upgrades use pre-S11 recovery readiness (no busy peers, pending approvals resolved, completion checks settled) and retain the existing operation checks. S11 adds no host-admission, quota or all-idle requirement to upgrade. An active/frozen configured train still requires recovery-target `release_trains` compatibility. Release-cut admission remains unchanged: follow its refusal's applicable exit by stopping or resuming the paused peer, adjusting `ahub budget set`, or using `ahub release drop`. Missing/shadowed `dot` requires the resource controller or a PATH correction for the cut; nested admission requires retrying the cut outside the outer lease.
|
|
3881
|
+
|
|
3882
|
+
|
|
3883
|
+
## Codex cancellation identity notice
|
|
3884
|
+
|
|
3885
|
+
If Codex is offline with `statusNotice.code = unidentified-cancellation`, the hub
|
|
3886
|
+
could not identify a cancelled native turn. Reattach the native session before
|
|
3887
|
+
further hub delivery. A late completion keeps this hold; verified native
|
|
3888
|
+
reattachment or TUI detachment clears it. The notice contains fixed guidance, without native ids.
|
package/docs/quickstart.md
CHANGED
|
@@ -17,7 +17,7 @@ ahub setup # installs the Claude Code channel plu
|
|
|
17
17
|
Or use the matching GitHub release:
|
|
18
18
|
|
|
19
19
|
```bash
|
|
20
|
-
bun add -g github:STAIxBWLB/agent-hub#v0.12.
|
|
20
|
+
bun add -g github:STAIxBWLB/agent-hub#v0.12.44
|
|
21
21
|
ahub setup
|
|
22
22
|
```
|
|
23
23
|
|
|
@@ -30,6 +30,14 @@ and upgrade or crash recovery, see the [operations guide](operations.md). To
|
|
|
30
30
|
move running projects to a newer release later, run `ahub upgrade` in a
|
|
31
31
|
terminal: it reviews the plan with you, applies it and follows it.
|
|
32
32
|
|
|
33
|
+
## Upgrading to 0.12.44
|
|
34
|
+
|
|
35
|
+
Run `ahub init` once per project to refresh the hub block in `AGENTS.md`: it tells agents in the agy TUI not to report the hub missing when no `hub_*` tool is listed on the first turn (#607). agy no longer shows Claude's context reading or Claude's transcript usage as its own (#624). When the hub itself starts Kimi or Qwen headless, it also opens `ahub watch <peer>` through its terminal provider; with no provider, or a failing one, the start still succeeds and reports the command to run (#286). When an `implement` or `bulk_edit` owner completes two turns in a row with no recorded writes or task-tool effects, the planner gets a notice, and a done report with no writes since acceptance says so in the review request; set `task_sweep.no_writes_turns` to change the count, or 0 to turn it off (#498). A declared agy extra instance is refused when the config loads, and Qwen's context occupancy shows unknown until a native source is verified (#625). A standard ACP agent can now be declared as a config-only adapter (`adapters.<kind>` in untracked `.agenthub/config.local.json`); restart the hub, then run `ahub roster add <kind>` and `ahub <kind>` (see the operations guide, #451). A project that declares adapters can be upgraded or restarted only to a release that advertises `configured_acp`. A `peers.<id>` block now accepts only `start_mode`: any other field stops the config from loading at hub start, where 0.12.43 ignored it at startup. Restart Claude sessions so they load the 0.12.44 plugin. Coming from 0.12.42 or older, the notes below apply too.
|
|
36
|
+
|
|
37
|
+
## Upgrading to 0.12.43
|
|
38
|
+
|
|
39
|
+
A busy hub no longer stalls when the checkout's HEAD moves under open turns: snapshot Git work in one burst shares a 250 ms budget, and incoming checkouts, merges and fast-forwards are told apart from a peer's own commits through the HEAD reflog, so they no longer raise false concurrent-edit warnings (#576). `ahub task assign` and `hub_task_assign` now refuse with the reason when the named peer cannot take the task (#601). `ahub completion zsh|bash|fish` prints a shell completion script (#603). The console's Peers tab shows each peer's planner WIP, and `w` edits its limit (#532). agy native file reads are recorded as peer facts on 1.4.2 and 1.4.3 (#555); 1.4.3 stays unverified, and in its TUI the hub tools appear from the second turn (#267, #607). Coming from 0.12.41 or older, the notes below apply too.
|
|
40
|
+
|
|
33
41
|
## Upgrading to 0.12.42
|
|
34
42
|
|
|
35
43
|
0.12.42 lets `ahub agy` start again after the Antigravity CLI updated itself to 1.4.3: the launcher accepts the 1.4.x line, launching 1.4.2 (the verified version) silently and another 1.4.x patch with a warning (#589). The rest of the release is contributor tooling (#591, #593, #595). Coming from 0.12.40 or older, the notes below apply too.
|
|
@@ -40,7 +48,7 @@ terminal: it reviews the plan with you, applies it and follows it.
|
|
|
40
48
|
|
|
41
49
|
## Upgrading to 0.12.40
|
|
42
50
|
|
|
43
|
-
Restart Claude sessions after upgrading: each keeps the plugin server it started with until restarted, so a restart loads the
|
|
51
|
+
Restart Claude sessions after upgrading: each keeps the plugin server it started with until restarted, so a restart loads the current plugin. That plugin asks Claude Code to list the hub tools again when a hub reconnect changes them (#490), and one from an older `ahub claude` launch is refused and stops reconnecting instead of reclaiming the peer (#551).
|
|
44
52
|
|
|
45
53
|
`ahub jcode` opens its TUI again; on 0.12.39 it stopped after the first hub turn (#564). A busy Jcode now takes an `important` message into its running turn (#572), and `ahub doctor` lists the extra MCP servers the hub-owned Jcode loads from its config files. See [Jcode operations](operations.md#optional-jcode-peer).
|
|
46
54
|
|
|
@@ -62,7 +70,7 @@ Upgrading from 0.12.37 or earlier, the 0.12.38 notes below also apply.
|
|
|
62
70
|
|
|
63
71
|
The 0.12.38 plugin reports a reply stopped by the hop cap as not delivered instead of as sent (#546); the restart above loads it.
|
|
64
72
|
|
|
65
|
-
Antigravity (`agy`) can join as an optional pull-only implementer (#485). It is off roster by default: install the Antigravity CLI 1.4.x (1.4.2 verified; other 1.4.x patches launch with a warning), run `ahub roster add agy`, then run `ahub agy` in a terminal. Its native permissions are unmanaged and it has no hub sandbox. See [Antigravity operations](operations.md#optional-antigravity-agy-peer).
|
|
73
|
+
Antigravity (`agy`) can join as an optional pull-only implementer (#485). It is off roster by default: install the Antigravity CLI 1.4.x (1.4.2 verified; other 1.4.x patches launch with a warning; on 1.4.3 the hub tools appear from the second TUI turn), run `ahub roster add agy`, then run `ahub agy` in a terminal. Its native permissions are unmanaged and it has no hub sandbox. See [Antigravity operations](operations.md#optional-antigravity-agy-peer).
|
|
66
74
|
|
|
67
75
|
Reviews can rotate across fresh Claude, Codex and Kimi reviewer sessions (#519, #533). Declare headless reviewer-only instances in `.agenthub/config.local.json`; Codex and Kimi join only with `review_mode: "fresh"`. Codex also needs an installed Codex 0.146.0 (select it with `codex_bin` when PATH resolves another version), and Kimi needs Kimi Code 2.2.0 on PATH, signed in with its own OAuth login. A headless reviewer instance without `review_mode` keeps its native behavior and stays out of the pool. agy is not a reviewer: naming it in `review.pool` shows an unavailable skip in `ahub route explain`, never a review. Once a train is active or frozen, or `review.pool` is set or fresh reviewer instances are declared, `ahub upgrade` refuses a target release without that support, so an older release cannot take the project over. See [fresh reviewer pool](operations.md#fresh-reviewer-pool-519).
|
|
68
76
|
|
package/docs/sdlc.md
CHANGED
|
@@ -229,7 +229,7 @@ The planner can provide scope with `hub_plan_review`; the person can run `ahub s
|
|
|
229
229
|
|
|
230
230
|
A review request is premature if its task head does not match the PR head, configured required checks are not green, or a pending bot thread is unanswered. A resolved thread is settled; an unresolved one needs a user reply after its last bot comment. The hub reads identity, timestamps, authorship type and resolution only, never comment bodies. Without explicit required checks the native floor is both OS checks plus `seeded guards`. Advise reports the gap; enforce refuses before the requesting done/cohort writes. A private turn may finish its own PII task in advise with a generic unknown-readiness notice and no remote metadata read; the private-turn refusal for ordinary work remains. Delayed checks revalidate before completing. Background roster/quota role changes remain fact, but enforce holds a new review envelope without an admission readback; refresh it through a manual reviewer assignment after CI and replies are ready. The brief and verdict coverage belong to #520, separate from this admission.
|
|
231
231
|
|
|
232
|
-
CI controllers are serialized
|
|
232
|
+
CI controllers are serialized per pull request (`check-pr-<number>`) and for main pushes and dispatches (`check-main`), for the entire workflow and without canceling an admitted controller (#609). Within a PR `queue: single` lets a newer pending run replace the older pending one; main keeps `queue: max`, which preserves up to 100 waiting controllers ([GitHub concurrency documentation](https://docs.github.com/en/actions/how-tos/write-workflows/choose-when-workflows-run/control-workflow-concurrency)). Different PRs run side by side: a repository-wide lock serialized every PR (17-18 min alone, 40-54 min with 4-5 PRs in flight on 2026-10-20). Two groups admitting the same tree at the same instant can run it twice; that duplicate costs one run and never a false green. Required job names and read-only token permissions are unchanged. Before PR or push gates, `scripts/ci-reuse.mjs` reuses successful full proof for the identical Git tree, including its workflow. On reuse the two OS matrix jobs still expand and report their exact required names, while the seeded aggregate reports its exact name. They run only a `Reuse verified identical-tree full gate` marker step naming the original proof; full setup and gates are skipped. Skipped jobs and successful reuse-reporting jobs never count as fresh full proof. A running identical-tree gate refuses duplicate admission; unknown active coverage refuses safely. Metadata reads are bounded to 100 recent successes/active runs and 240 calls within 60 seconds. Pending serialized controllers are not admitted gates. Run focused tests locally and one full gate at the final head; a known flake warrants only one rerun of its failed job with recorded evidence.
|
|
233
233
|
|
|
234
234
|
`hub_sdlc_costs` and the person's `ahub sdlc costs [owner/repo]` report linked merged PRs without changing the board. A review round is a board done-to-verdict handoff, not each reviewer in a multi-reviewer round. An observed handoff still counts when its declared scope was none. The report counts distinct check-workflow run ids, extra attempts (`run_attempt - 1`), full re-reviews, delta rounds and summed review intervals, with GitHub review counts alongside them. Unspecified scope and unavailable evidence stay unknown/incomplete. Only current public links are projected; a private counterpart withholds the whole PR. Up to 16 linked PR reads share 20 seconds; each PR covers at most 100 commits, reviews and recent check-workflow runs, and the pure aggregator bounds 500 tasks, 200 PRs and 10,000 history entries. Truncation is explicit. S10 exposes pure band-breach proposal data; S7 owns rolling baselines, band configuration, automatic scheduling and board-card creation.
|
|
235
235
|
|
package/docs/security.md
CHANGED
|
@@ -6,8 +6,8 @@ agent-hub connects agents that can each run commands. This page says what the hu
|
|
|
6
6
|
|
|
7
7
|
- **Other agents' text is untrusted.** Every message that crosses from one peer to another is framed as untrusted input: a channel tag with `meta.source` for Claude started with `ahub claude`; otherwise a fixed header line (`frame()`, `[agent-hub message from ...]`) with an instruction that says it is untrusted, the plugin's server instructions for a tools-only Claude reading `hub_inbox` and a standing instruction for the others. A message body cannot forge the hub's own headers: such lines are quoted (`sanitize`). Replies inherit a hop count capped at 3, so agents cannot ping-pong forever; neither a digest nor a steer can reset it.
|
|
8
8
|
- **The control link is loopback plus a secret.** The daemon and the Codex proxy bind 127.0.0.1 only. The control WebSocket requires a per-run token (`.agenthub/state/control-token`, mode 600), and both servers refuse any request that carries an `Origin` header: any web page can open a WebSocket to localhost, and browsers always send `Origin`. The bearer header a Codex TUI sends to the proxy carries only the terminal launch id (#586): it binds terminal ownership and is not a credential. External clients cannot claim the console user's id or a hub-managed peer's id.
|
|
9
|
-
- **Permission prompts stay on unless an operator selects a permission mode.** `ask` leaves native decisions unchanged. `ask-when-needed` grants scoped Claude file tools or Pi/local writes and edits; Kimi and Codex use their own native policies. `never-ask` requires explicit runtime confirmation or a person's console `y` for a config default at hub start. Until that config confirmation the peer runs in `ask`. Kimi's and `local`'s permission requests are relayed to the console and cancelled after `approvals.timeout_s` (default 120 s) of silence; the macOS notification for a waiting request carries the peer and the tool name only. The one exception is the hub's own tools (`hub_send` and the task tools, matched by exact name): Kimi's requests for them are approved once without a prompt and logged by name, the same trust Codex gets through `approval_mode` in the hub's config. They invoke hub-owned operations rather than arbitrary file or shell tools, and every call passes the hub's own checks. Identity comes from the exact permission title, or from the earlier tool-call title bound to the same call id and resolved against the configured MCP servers when the permission title contains argument JSON (Qwen). Payload text and unrelated display titles never establish identity. For ACP agents, a payload longer than the console shows is marked as cut and never offers a session-wide grant. Pi's write, edit, shell and git write requests are relayed the same way and can be answered `Always allow <tool> until Pi restarts`: later calls of that tool by the same Pi start skip the prompt but stay inside the path guard and sandbox. The grant covers every later call of that tool whatever its payload, is kept in memory only, cannot be given from the dashboard, and each call it allows is logged by tool name. A Pi or `local` request whose call was cancelled or whose turn ended is withdrawn at once: a later answer is refused and grants nothing, an `Always allow` included. One shell command runs without a hub approval: the `!command` a person types in the managed Pi TUI. It stays inside the same sandbox and denylist, and the hub takes it only from the verified owner process of a Pi in TUI mode, while Pi is idle, on a reservation that is used once; a model's own bash call never takes that path (issue #253). `--unattended` turns prompts off, says so loudly, and is never the default.
|
|
10
|
-
- **A committed config cannot choose launch commands, credential files, data endpoints, permission modes or a wider sandbox.** The machine-local fields (`kimi_cmd`, `permission_modes`, `codex_bin`, `pi.cmd`, `checks`, `mlx.bin`, `mlx.runtimeDir`, `mlx.modelPath`, `omniroute.urls`, `omniroute.access_hosts`, the `omniroute` key files, `memory.worker_url`, `local.read_allow`, `local.bash_network`, `local.network_allow`, `terminal.open`, `instances`) apply only from a config file git confirms nobody committed (`instances` is read only from an untracked `.agenthub/config.local.json`; in `config.json` it is ignored even when untracked): `.agenthub/config.json` or `.agenthub/config.local.json`, matched by file identity so no other spelling the file system accepts slips past, and `.agenthub` itself not a committed symlink or submodule. Without a repository, or when git fails, they keep their defaults; an empty value always means the default. "Untracked" is answered by the repository that contains the project: a checkout copied or extracted into an unrelated repository, or into an ignored directory of one, is trusted like your own files. So a cloned repository cannot choose a launch command, a completion check, a gateway to send a key file to, a memory endpoint, a permission mode, the command that opens a terminal, or a wider sandbox. A command in `checks` runs as you, outside the local worker's sandbox, like a git hook. So do the `setup` and `verify` commands of a benchmark suite (issue #251): `ahub bench run <suite.json>` is a person's command, refused from an agent session, and it resets the work tree for each attempt, so it runs only with `bench.enabled`, at the root of a clean repository that tracks nothing under `.agenthub/`. Nothing in `routing.toml` or in task text is ever run. `routing.toml` and the other shared fields still come from the checkout, and they matter: `routing.toml` picks the models the local worker and the hub's inference use at your gateway and can turn the PII constraint off, and roles and budget shape who does what. Review them in a repository you do not trust. The hub's own git calls outside the sandbox (snapshots, facts, config trust, project discovery, memory recall, the bench runner) all use the single hardened implementation in the exact-pinned first-party `@staix/agent-mem/platform` package, re-exported by `src/hub/git.ts`, which disables the programs a repository's configuration can name — the file-system monitor, hooks, external diff, the pager, and the credential and askpass helpers, with prompts failing closed — so a config that ever does get written cannot run code with the hub's rights. Of those, the monitor, hooks and external diff are reachable by commands the hub issues (the planted-program test exercises all three; a `diff --no-index` reads the repo's config, so that call also passes `--no-ext-diff` and `--no-textconv`); the pager is not (every call pipes stdout). Credential and askpass helpers are disabled for project repositories; memory sync alone may use credentials for its own memory repository, without prompts. The cost: `core.fsmonitor=false` also turns off a person's enabled built-in monitor for the hub's own calls, so the per-turn snapshot's `add -A` scans the whole tree (the snapshot
|
|
9
|
+
- **Permission prompts stay on unless an operator selects a permission mode.** `ask` leaves native decisions unchanged. `ask-when-needed` grants scoped Claude file tools or Pi/local writes and edits; Kimi and Codex use their own native policies. `never-ask` requires explicit runtime confirmation or a person's console `y` for a config default at hub start. Until that config confirmation the peer runs in `ask`. Kimi's and `local`'s permission requests are relayed to the console and cancelled after `approvals.timeout_s` (default 120 s) of silence; the macOS notification for a waiting request carries the peer and the tool name only. The one exception is the hub's own tools (`hub_send` and the task tools, matched by exact name): Kimi's requests for them are approved once without a prompt and logged by name, the same trust Codex gets through `approval_mode` in the hub's config. They invoke hub-owned operations rather than arbitrary file or shell tools, and every call passes the hub's own checks. Identity comes from the exact permission title, or from the earlier tool-call title bound to the same call id and resolved against the configured MCP servers when the permission title contains argument JSON (Qwen). Payload text and unrelated display titles never establish identity. Configured ACP kinds (#451) never get this exception: a request whose title spells a hub tool exactly still goes to the person approval path, and only a mapped native mode changes what the agent itself asks. For ACP agents, a payload longer than the console shows is marked as cut and never offers a session-wide grant. Pi's write, edit, shell and git write requests are relayed the same way and can be answered `Always allow <tool> until Pi restarts`: later calls of that tool by the same Pi start skip the prompt but stay inside the path guard and sandbox. The grant covers every later call of that tool whatever its payload, is kept in memory only, cannot be given from the dashboard, and each call it allows is logged by tool name. A Pi or `local` request whose call was cancelled or whose turn ended is withdrawn at once: a later answer is refused and grants nothing, an `Always allow` included. One shell command runs without a hub approval: the `!command` a person types in the managed Pi TUI. It stays inside the same sandbox and denylist, and the hub takes it only from the verified owner process of a Pi in TUI mode, while Pi is idle, on a reservation that is used once; a model's own bash call never takes that path (issue #253). `--unattended` turns prompts off, says so loudly, and is never the default.
|
|
10
|
+
- **A committed config cannot choose launch commands, credential files, data endpoints, permission modes or a wider sandbox.** The machine-local fields (`kimi_cmd`, `permission_modes`, `codex_bin`, `pi.cmd`, `checks`, `mlx.bin`, `mlx.runtimeDir`, `mlx.modelPath`, `omniroute.urls`, `omniroute.access_hosts`, the `omniroute` key files, `memory.worker_url`, `local.read_allow`, `local.bash_network`, `local.network_allow`, `terminal.open`, `instances`) apply only from a config file git confirms nobody committed (`instances` is read only from an untracked `.agenthub/config.local.json`; in `config.json` it is ignored even when untracked): `.agenthub/config.json` or `.agenthub/config.local.json`, matched by file identity so no other spelling the file system accepts slips past, and `.agenthub` itself not a committed symlink or submodule. Without a repository, or when git fails, they keep their defaults; an empty value always means the default. "Untracked" is answered by the repository that contains the project: a checkout copied or extracted into an unrelated repository, or into an ignored directory of one, is trusted like your own files. So a cloned repository cannot choose a launch command, a completion check, a gateway to send a key file to, a memory endpoint, a permission mode, the command that opens a terminal, or a wider sandbox. A command in `checks` runs as you, outside the local worker's sandbox, like a git hook. So do the `setup` and `verify` commands of a benchmark suite (issue #251): `ahub bench run <suite.json>` is a person's command, refused from an agent session, and it resets the work tree for each attempt, so it runs only with `bench.enabled`, at the root of a clean repository that tracks nothing under `.agenthub/`. Nothing in `routing.toml` or in task text is ever run. `routing.toml` and the other shared fields still come from the checkout, and they matter: `routing.toml` picks the models the local worker and the hub's inference use at your gateway and can turn the PII constraint off, and roles and budget shape who does what. Review them in a repository you do not trust. The hub's own git calls outside the sandbox (snapshots, facts, config trust, project discovery, memory recall, the bench runner) all use the single hardened implementation in the exact-pinned first-party `@staix/agent-mem/platform` package, re-exported by `src/hub/git.ts`, which disables the programs a repository's configuration can name — the file-system monitor, hooks, external diff, the pager, and the credential and askpass helpers, with prompts failing closed — so a config that ever does get written cannot run code with the hub's rights. Of those, the monitor, hooks and external diff are reachable by commands the hub issues (the planted-program test exercises all three; a `diff --no-index` reads the repo's config, so that call also passes `--no-ext-diff` and `--no-textconv`); the pager is not (every call pipes stdout). Credential and askpass helpers are disabled for project repositories; memory sync alone may use credentials for its own memory repository, without prompts. The cost: `core.fsmonitor=false` also turns off a person's enabled built-in monitor for the hub's own calls, so the per-turn snapshot's `add -A` scans the whole tree (the snapshot Git calls of one burst share a 250 ms budget, each call at most 10 s; a boundary that runs out is recorded as unknown, never as a stale baseline) (#576). git has no global switch for filter drivers, and of the hub's commands only the snapshot's `add`/`restore` would run one (its driver command lives in the protected `.git/config`).
|
|
11
11
|
- **Telemetry holds no bodies.** `.agenthub/state/events.jsonl` (issue #40) records envelope ids, routing and sizes, task ids and states, overlapping paths and token counts, and the task id (with a PII flag) that each usage and token record is attributed to. It never records a message body, a task title or detail, and marks private (PII) envelopes and tasks as such. It stays on the machine; `ahub export` only prints it. Two opt-in stores copy numbers from it into your home directory, shared by every project on the machine (directories mode 700, files 600): research records (issue #247, `research.enabled`) in `~/.agenthub/research/` hold per approved task the ids, states, counts, tokens, times and PII flag the events hold, a person's label from a closed list, and a hash in place of the project id; benchmark runs (issue #251) in `~/.agenthub/bench/` hold suite name and hash, arm label, the attached peers' ids, models and permission modes, task ids, outcomes, exit codes, counts, tokens and times, never suite text or a command's output.
|
|
12
12
|
- **Snapshots stay in your repository.** Per-turn snapshots (issue #33) are git objects in the project's own object store, written through a temporary index; nothing is referenced, pushed or copied elsewhere, and `git gc` prunes them. They hold what the work tree held, including untracked files that are not ignored, so keep secrets in ignored files. They carry the repository's own permissions, and nothing caps their disk use but `git gc`. A turn of a peer holding an open PII task is not snapshotted; a PII file left in the project is snapshotted by later turns like any other file. `ahub undo` restores only files whose current content is exactly what the turn left.
|
|
13
13
|
- **The edit hook reads, never decides.** `ahub check-path --hook` (issue #32) reads hub.db and returns context for Claude and a line for you; it sets no permission decision, so your permission rules stay in charge. It names other owners' task ids, titles and states, which then reach Claude's model; PII tasks are left out.
|
|
@@ -183,7 +183,7 @@ Please report vulnerabilities privately through GitHub's "Report a vulnerability
|
|
|
183
183
|
- A settings session is as strong as the console for these settings and no stronger elsewhere. A mode change is the console's own request with the same refusals; tool approvals stay deny-only for Pi and local; there is still no shell, file, task-detail or launch-command API. `ahub ui --settings` and `ahub settings` pass the same identity gate as `ahub permission`, which is an operating policy, not authentication. The hostile-agent boundary above applies unchanged: an agent with an unrestricted shell as the same user can impersonate the console, and so can open a settings session.
|
|
184
184
|
- Every change writes a `settings` event (the key, the value before and after, the source `dashboard` or `terminal`) and a line in `hub.log` and open consoles; opening a settings session is logged too. The unified dashboard (`ahub ui --all`) forwards settings actions as an ordinary session and opens no settings session.
|
|
185
185
|
- Configuration reload (issue #439). The daemon watches `config.json`, `config.local.json`, `routing.toml` and `routing.local.toml` and re-reads the complete candidate after a change, as the dashboard's Reload configuration and `ahub settings reload` do; an invalid candidate applies nothing. Each changed key is then authorized on its own against its file's actual git provenance. A privacy tightening (local-only PII, the model screen on, added PII patterns, narrower roles or capability lists, unless it moves the planner or conductor) and a safe registered setting apply from any file. Every other change, machine-local fields included, keeps its running value when its file is tracked or git cannot answer. From an untracked file such a guarded change is adopted only by `ahub settings reload` in an interactive terminal, after it lists each guarded key with its full before and after values and the person types `y` within 30 seconds; the confirmation is bound to the file contents and accepted state it was shown for. File watches and dashboard reloads, a settings session's included, never confirm, and no reload changes the roster: membership moves only through the roster setting. Keys whose consumers are bound at start (memory, the gateway and MLX, checks, the privacy and sandbox policy of existing sessions, the terminal provider and others) stay pending until a restart.
|
|
186
|
-
- Start modes. A start the hub makes itself (the dashboard's Start control, `peer_start` from a console child, the conductor's `hub_peer_start`, `pi.auto_start`) takes the peer's start mode. Through settings only a settings session or the terminal can set it to headless; a config file can also set `peers.<id>.start_mode`, the shared one included (it is not a machine-local field: headless was the only form for Pi, Kimi and the local worker before this change, and for Jcode before 0.12.39, a hub-made headless Codex start is the app-server the hub already ran for it, and a start mode grants nothing a permission mode or a capability controls). A declared extra instance accepts only `headless` from any surface; a Claude channel instance accepts no start mode, and a headless Claude instance must have roles exactly `["reviewer"]` and no worktree. For a TUI the hub opens a terminal running `<runtime> <its own entry point> --project <this project> <peer>` (with `--mode tui` for Pi, Kimi and Jcode): every word is the hub's own, the command line is those words each quoted for a POSIX shell, and no request field, tool argument or agent message is part of it. In a `terminal.open` template `{command}` is that quoted line and `{title}` and `{cwd}` are raw text for argv elements of their own; each placeholder is substituted once, so a project path that itself contains a placeholder, a quote or `$` stays one word. A provider's own error text goes to `hub.log`, not to the caller. The terminal comes from `terminal.open`, a machine-local command template that config trust refuses from a committed file and that no settings surface can write, or from Orca. The opened terminal's environment carries no agent marker, so `ahub` there has the console's identity. Without a provider the start is refused with the command to run by hand; it is never downgraded to headless. A conductor can start a peer but cannot choose its mode.
|
|
186
|
+
- Start modes. A start the hub makes itself (the dashboard's Start control, `peer_start` from a console child, the conductor's `hub_peer_start`, `pi.auto_start`) takes the peer's start mode. Through settings only a settings session or the terminal can set it to headless; a config file can also set `peers.<id>.start_mode`, the shared one included (it is not a machine-local field: headless was the only form for Pi, Kimi and the local worker before this change, and for Jcode before 0.12.39, a hub-made headless Codex start is the app-server the hub already ran for it, and a start mode grants nothing a permission mode or a capability controls). A declared extra instance accepts only `headless` from any surface; a Claude channel instance accepts no start mode, and a headless Claude instance must have roles exactly `["reviewer"]` and no worktree. For a TUI the hub opens a terminal running `<runtime> <its own entry point> --project <this project> <peer>` (with `--mode tui` for Pi, Kimi and Jcode): every word is the hub's own, the command line is those words each quoted for a POSIX shell, and no request field, tool argument or agent message is part of it. In a `terminal.open` template `{command}` is that quoted line and `{title}` and `{cwd}` are raw text for argv elements of their own; each placeholder is substituted once, so a project path that itself contains a placeholder, a quote or `$` stays one word. A provider's own error text goes to `hub.log`, not to the caller. The terminal comes from `terminal.open`, a machine-local command template that config trust refuses from a committed file and that no settings surface can write, or from Orca. The opened terminal's environment carries no agent marker, so `ahub` there has the console's identity. Without a provider the start is refused with the command to run by hand; it is never downgraded to headless. After a successful headless start of a watch-capable peer (Kimi, Qwen) the hub also opens `<runtime> <its own entry point> --project <this project> watch <peer>` through the same provider under the same fixed-words rule, at most once per peer per 30 s and never for an already attached peer or a declared instance; the pane has the console's identity, and a missing or failing provider leaves the start standing and reports the command (#286). A conductor can start a peer but cannot choose its mode.
|
|
187
187
|
|
|
188
188
|
## Multi-project manager (protocol 7)
|
|
189
189
|
|
|
@@ -196,7 +196,7 @@ page. It cannot expose private task history or allow local-worker tools.
|
|
|
196
196
|
Per-project control handshakes verify project, root and instance against the
|
|
197
197
|
runtime manifest. Shutdown removes only the owning instance's runtime files and
|
|
198
198
|
waits for owned child processes. Registry and manager startup claims serialize
|
|
199
|
-
concurrent starts; uncertain ownership is reported, not forcibly reclaimed.
|
|
199
|
+
concurrent starts; uncertain ownership is reported, not forcibly reclaimed. An open whose spawned manager lost to another one stops the process it started, so no unowned manager keeps running (#584).
|
|
200
200
|
A stale browser action against a restarted daemon is rejected, and mutations are
|
|
201
201
|
never automatically replayed after a connection failure.
|
|
202
202
|
|
|
@@ -254,7 +254,9 @@ this production table. Startup diagnostics withhold native host/payload details.
|
|
|
254
254
|
|
|
255
255
|
Jcode is optional, source/version-fenced and runs native tools without a hub sandbox or hub permission-mode mapping. .jcode joins the scoped-grant exclusion, including lexical/resolved aliases. Only a person writes its unique project MCP entry; foreign/override/symlink entries refuse. The hub owns a private daemon/socket and ACP group, never the global daemon, and copies no credentials. It accepts only a plain jcode release from 0.98.0 up to, not including, 1.0.0 (#529), and runs every owned jcode process (probe, serve, ACP and TUI) with `JCODE_NO_TELEMETRY=1`, because jcode's telemetry can report the provider account's email. Native diagnostics withhold payloads/hosts. Unproved conversation loads refuse; no fresh replacement is called a restore. A finished task's advisory about the project root checkout names the branch only after the hub's whole public-text screen (`Tasks.publicMetadataText`: a PII pattern, a secret shape and a project-private path) passes it and it is a plain ref name; otherwise a generic sentence carries no part of it (#572). Native TUI launch exposes its private socket/session tuple only to the authenticated console, bound to the same live owned socket and session after read-only native persistence proof. Tools/status do not receive it. The TUI has no single-writer guard: person input may interleave with ACP. Native policy remains unmanaged and closing the frontend does not stop ACP. An `important` message reaches a busy Jcode as a soft interrupt written to the hub's own private server socket for the owned session (#572); the hub never cancels a turn to deliver, and a steer that was sent but not acknowledged, or whose turn ended first, is held as `needs_review`, never replayed. Jcode has no switch to choose its MCP servers, so the owned serve and ACP processes load every server named in `<JCODE_HOME>/mcp.json` and the project's `.jcode/mcp.json`, `.mcp.json` and `.claude/mcp.json`, besides the hub's own; `ahub doctor` lists their names only. Point `jcode_home` at a separate home, or remove a server from those files, to keep it out.
|
|
256
256
|
|
|
257
|
-
Antigravity (`agy`, #485) is optional, cloud and off roster by default. The launcher accepts the Antigravity CLI 1.4.x line; only 1.4.2 has a native receipt, so another 1.4.x patch launches with a warning that it is unverified, and every other version is refused before a hub connection or plugin write (#589). It runs native tools under its own unmanaged permissions, without a hub sandbox or hub permission-mode mapping; headless, resume, unattended and native permission flags are refused. Its roles are capped at implementer and verifier, so it never plans, reviews or receives PII work. Only the person's `ahub agy` launcher writes its three plugin files in `.agents/plugins/agent-hub/` (`plugin.json`, `mcp_config.json`, `hooks.json`): linked or foreign entries refuse before any write, cleanup removes only that launch's matching files, and it never writes project-level `.agents/hooks.json` or the person's `~/.gemini` settings. Conductor starts are refused. Hook authority (`native_hook_launch`) comes only from that launcher, belongs to the console socket that began it and ends when that socket closes; hook input over 1 MiB is refused, and observations are bound to the daemon, launch, native session and project.
|
|
257
|
+
Antigravity (`agy`, #485) is optional, cloud and off roster by default. The launcher accepts the Antigravity CLI 1.4.x line; only 1.4.2 has a native receipt, so another 1.4.x patch launches with a warning that it is unverified, and every other version is refused before a hub connection or plugin write (#589). It runs native tools under its own unmanaged permissions, without a hub sandbox or hub permission-mode mapping; headless, resume, unattended and native permission flags are refused. Its roles are capped at implementer and verifier, so it never plans, reviews or receives PII work. Only the person's `ahub agy` launcher writes its three plugin files in `.agents/plugins/agent-hub/` (`plugin.json`, `mcp_config.json`, `hooks.json`): linked or foreign entries refuse before any write, cleanup removes only that launch's matching files, and it never writes project-level `.agents/hooks.json` or the person's `~/.gemini` settings. Conductor starts are refused, and a declared agy extra instance is refused at config load (#625). Hook authority (`native_hook_launch`) comes only from that launcher, belongs to the console socket that began it and ends when that socket closes; hook input over 1 MiB is refused, and observations are bound to the daemon, launch, native session and project.
|
|
258
|
+
|
|
259
|
+
Configured ACP adapters (#451 A3) are declared only by the person, in a Git-confirmed untracked `.agenthub/config.local.json`. The whole declaration (command, argv, identity, roles and mode maps) is machine-local authority: a shared or tracked declaration is ignored with a notice, settings never edit it, and changes need a hub restart. The hub runs only the declared argv, never a module or callback. Argv that selects a leader, attach, connect or remote mode is refused, and a Grok declaration needs `--no-leader`. Each start requires the pinned native identity, an exact `session/load` echo on resume, and positive ownership of the spawned process and its original process group; unknown ownership refuses, and stop signals only that verified group. An agent that hands its work to a process outside that group is outside this boundary. Without a mode map native policy is unmanaged, and there is no hub sandbox either way. Configured kinds are cloud peers (never PII), headless only and off roster by default, and the hub makes no quota, context or controlled-recovery claims for them. A read-only instance needs the native read-only mode acknowledged before a prompt and is limited to read and review hub tools, both in the published MCP list and at the host; its native non-read tool requests are rejected, and no setting or runtime change can raise it. These agents' stderr and error text are withheld from logs, and previews redact the executable, argv and session id.
|
|
258
260
|
|
|
259
261
|
# Transient ACP activity (#286)
|
|
260
262
|
|