@staix/agent-hub 0.6.4 → 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/README.md +16 -15
- package/docs/operations.md +217 -0
- package/docs/quickstart.md +121 -0
- package/docs/security.md +57 -0
- package/docs/smoke.md +545 -0
- package/docs/specs/2026-09-19-agent-hub-design.md +675 -0
- package/docs/specs/2026-09-19-multi-project-design.md +95 -0
- package/docs/specs/2026-09-20-durable-delivery-design.md +67 -0
- package/docs/specs/2026-09-20-pi-local-models-design.md +40 -0
- package/docs/specs/2026-09-20-upgrade-recovery-design.md +151 -0
- package/package.json +2 -1
- package/plugins/agent-hub/.claude-plugin/plugin.json +1 -1
- package/plugins/agent-hub/server.js +31 -10
- package/src/adapters/acp.ts +40 -7
- package/src/adapters/claude-channel.ts +22 -5
- package/src/adapters/codex-appserver.ts +50 -7
- package/src/adapters/local-worker.ts +20 -3
- package/src/adapters/pi.ts +33 -7
- package/src/cli/main.ts +49 -0
- package/src/cli/status-lines.ts +4 -1
- package/src/cli/terminal-recovery.ts +20 -5
- package/src/cli/upgrade-runtime.ts +8 -8
- package/src/hub/bus.ts +290 -38
- package/src/hub/control-client.ts +5 -3
- package/src/hub/daemon.ts +75 -19
- package/src/hub/delivery-journal.ts +830 -0
- package/src/hub/manager.ts +6 -4
- package/src/hub/peers.ts +16 -3
- package/src/hub/restart.ts +2 -0
- package/src/ui/index.html +7 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.7.1
|
|
4
|
+
|
|
5
|
+
- Restore native sessions while unrelated agents remain in the same worktree; the coordinator continues to fence uncertain terminal creations (#48).
|
|
6
|
+
- Allow a bounded inventory refresh after closing the captured terminal before reporting uncertain shutdown (#48).
|
|
7
|
+
|
|
8
|
+
## 0.7.0
|
|
9
|
+
|
|
10
|
+
- Persist queued deliveries and expose uncertain handoffs for explicit operator reconciliation (#46).
|
|
11
|
+
- Show disconnected recipients, important pending counts and work needing review in CLI and dashboard; add console queue inspection and resolution (#46).
|
|
12
|
+
- Separate adapter acceptance from execution completion, use protocol 10 receipts, and support controlled protocol 9 to 10 upgrades (#46).
|
|
13
|
+
- Add an English daily operations and recovery guide with measured evidence and explicit operational limits (#46).
|
|
14
|
+
|
|
3
15
|
## 0.6.4
|
|
4
16
|
|
|
5
17
|
- Refuse accidental CLI flags in `say` and `remember`, while preserving message text around the `--` separator (#40, #44).
|
package/README.md
CHANGED
|
@@ -4,15 +4,14 @@ Native multi-agent hub for one developer's machine: Claude Code, Codex, Kimi Cod
|
|
|
4
4
|
hub-owned local-LLM worker collaborate as peers in independent project directories, with
|
|
5
5
|
task-aware model routing (Switchyard) in front of a self-hosted gateway (OmniRoute).
|
|
6
6
|
|
|
7
|
-
Status: 0.
|
|
8
|
-
|
|
7
|
+
Status: 0.7.1, control protocol 10. Durable delivery records distinguish queued
|
|
8
|
+
work from uncertain execution. The [smoke checklist](docs/smoke.md) records
|
|
9
|
+
verified paths and remaining prerequisites.
|
|
9
10
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
`ahub recovery status <operation-id>` reports progress. Existing protocol-5–7
|
|
15
|
-
hubs require their matching CLI and an attended maintenance bootstrap.
|
|
11
|
+
Read the [operations guide](docs/operations.md) for the daily workflow, queue
|
|
12
|
+
reconciliation, and the staged protocol-9 to protocol-10 upgrade command.
|
|
13
|
+
Controlled recovery preserves work; uncertain effects are never automatically
|
|
14
|
+
replayed and may require operator review.
|
|
16
15
|
|
|
17
16
|
## Start here
|
|
18
17
|
|
|
@@ -29,7 +28,7 @@ cd <your project> && ahub init && ahub up && ahub tail
|
|
|
29
28
|
Or install the same version from GitHub:
|
|
30
29
|
|
|
31
30
|
```bash
|
|
32
|
-
bun add -g github:STAIxBWLB/agent-hub#v0.
|
|
31
|
+
bun add -g github:STAIxBWLB/agent-hub#v0.7.1 && ahub setup
|
|
33
32
|
```
|
|
34
33
|
|
|
35
34
|
The installed commands remain `ahub` and `agent-hub`.
|
|
@@ -39,6 +38,7 @@ instructions and `ahub setup` to refresh the Claude plugin. Restart the daemon
|
|
|
39
38
|
and agent sessions so both load the update.
|
|
40
39
|
|
|
41
40
|
- [Quickstart](docs/quickstart.md): install, first session, the local worker, the commands of a working day
|
|
41
|
+
- [Operations guide](docs/operations.md): managed launchers, task/review flow, receipts, shutdown and recovery
|
|
42
42
|
- [Security notes](docs/security.md): what the hub defends and what it does not
|
|
43
43
|
- [Design spec](docs/specs/2026-09-19-agent-hub-design.md): how it is built and why, with every amendment made along the way
|
|
44
44
|
- [Smoke checklist](docs/smoke.md): the live checks, and what has and has not been verified against real agents
|
|
@@ -101,9 +101,10 @@ starts. Inspect `ahub status` for requested routes and reported backend models.
|
|
|
101
101
|
A project has one managed Pi session owner. Mode changes require the agent to
|
|
102
102
|
settle and preserve the session file. Before the first generation, a live source
|
|
103
103
|
verified to be empty can instead retain its exact session ID without a file.
|
|
104
|
-
Missing history from a nonempty session blocks handover. Protocol 9 adds Pi
|
|
105
|
-
|
|
106
|
-
|
|
104
|
+
Missing history from a nonempty session blocks handover. Protocol 9 adds Pi
|
|
105
|
+
recovery metadata. Protocol 10 is the 0.7.0 target for durable delivery
|
|
106
|
+
receipts and conservative queue recovery; it is pending live verification.
|
|
107
|
+
Older protocol hubs still require their matching CLI and an attended bootstrap.
|
|
107
108
|
|
|
108
109
|
## Runtime
|
|
109
110
|
|
|
@@ -165,7 +166,7 @@ worktrees recall their parent and composite identity. A shared-alias notice does
|
|
|
165
166
|
not mean that task boards or agent sessions are shared. Provider quota readings
|
|
166
167
|
may describe the same account and should not be added across projects.
|
|
167
168
|
|
|
168
|
-
Before upgrading
|
|
169
|
-
update the package/plugin and restart the desired projects and agent sessions.
|
|
169
|
+
Before upgrading an older hub, inspect the plan with the matching CLI.
|
|
170
170
|
Incompatible or unverified processes are shown explicitly and are never killed by
|
|
171
|
-
PID-name matching. See the [
|
|
171
|
+
PID-name matching. See the [operations guide](docs/operations.md) and the
|
|
172
|
+
[multi-project specification](docs/specs/2026-09-19-multi-project-design.md).
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
# Operations guide
|
|
2
|
+
|
|
3
|
+
This guide describes ahub 0.7.1 and control protocol 10. Live verification
|
|
4
|
+
results and remaining prerequisites are recorded separately in [the smoke ledger](smoke.md).
|
|
5
|
+
|
|
6
|
+
## Install and start
|
|
7
|
+
|
|
8
|
+
Use Bun 1.3 or newer. Install the released package and install its Claude
|
|
9
|
+
channel plugin:
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
bun add -g @staix/agent-hub
|
|
13
|
+
ahub setup
|
|
14
|
+
cd <project>
|
|
15
|
+
ahub init
|
|
16
|
+
ahub up
|
|
17
|
+
ahub tail
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
`ahub init` writes the project configuration and managed instruction blocks.
|
|
21
|
+
Run it after an upgrade when those blocks need refreshing. `ahub setup`
|
|
22
|
+
updates the shared Claude plugin. Keep `ahub tail` open when a local worker
|
|
23
|
+
may request an approval.
|
|
24
|
+
|
|
25
|
+
Managed launchers attach native peers to the project daemon:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
ahub claude
|
|
29
|
+
ahub codex
|
|
30
|
+
ahub kimi
|
|
31
|
+
ahub pi --mode headless --backend auto
|
|
32
|
+
ahub local
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Start only the peers configured for the project. A launcher records and checks
|
|
36
|
+
its project and session identity; do not start a second terminal by guessing
|
|
37
|
+
from a process name. For multiple projects, use the explicit selector before
|
|
38
|
+
the command, for example `ahub --project /path/to/project codex`.
|
|
39
|
+
|
|
40
|
+
## A two-agent task and review
|
|
41
|
+
|
|
42
|
+
Choose an owner explicitly, then inspect the reviewer selected by the project
|
|
43
|
+
routing policy before work begins:
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
ahub task propose implement "Update the parser" --owner codex --path src/parser.ts
|
|
47
|
+
ahub board
|
|
48
|
+
ahub task show <task-id>
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
The owner accepts with `hub_task_accept`, makes the change, and reports with
|
|
52
|
+
`hub_task_done` including a summary and refs. The reviewer receives a review
|
|
53
|
+
request and responds with `hub_review`. A console review uses:
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
ahub review <task-id> approved "verified against the requested behavior"
|
|
57
|
+
# or
|
|
58
|
+
ahub review <task-id> changes_requested "describe the required correction"
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
A task reaching `approved` is a board transition. It is not proof that an
|
|
62
|
+
external side effect happened unless the task's refs and a live readback show
|
|
63
|
+
that effect. The hub can reassign after repeated review changes according to
|
|
64
|
+
the routing configuration.
|
|
65
|
+
|
|
66
|
+
Use targeted messages for coordination:
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
ahub say @codex "[IMPORTANT] inspect the failing fixture"
|
|
70
|
+
ahub say @claude "[STATUS] the test run is complete"
|
|
71
|
+
ahub say @kimi "[FYI] the result is recorded"
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
`@peer` addresses one known peer. With no recipient, `ahub say` broadcasts
|
|
75
|
+
to attached peers. `[IMPORTANT]` can bypass batching where the peer supports
|
|
76
|
+
it; `[STATUS]` may batch, and `[FYI]` is recorded without follow-on
|
|
77
|
+
delivery. A delivery or answer is not a task completion receipt.
|
|
78
|
+
|
|
79
|
+
## Approvals and pauses
|
|
80
|
+
|
|
81
|
+
Inspect permission requests in the terminal:
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
ahub tail
|
|
85
|
+
ahub permit <request-id> allow
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Use the exact option shown by `ahub tail`; do not approve an unresolved or
|
|
89
|
+
unexpected request. `ahub pause <peer>` holds delivery and `ahub resume
|
|
90
|
+
<peer>` releases a manual pause. Budget pauses are distinct:
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
ahub budget
|
|
94
|
+
ahub budget resume <peer>
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
A budget pause remains authoritative until the budget command explicitly
|
|
98
|
+
overrides it or the window resets. Check `ahub status` and `ahub board` after
|
|
99
|
+
a pause or handoff.
|
|
100
|
+
|
|
101
|
+
## Durable delivery and queue resolution
|
|
102
|
+
|
|
103
|
+
Protocol 10 records each recipient delivery in the private project journal.
|
|
104
|
+
The states are `queued`, `dispatching`, `accepted`, `completed`,
|
|
105
|
+
`needs_review`, `failed`, and `discarded`. Adapter acceptance means that
|
|
106
|
+
the native bridge received the delivery; it does not prove that the agent
|
|
107
|
+
executed it. Only native completion or a correlated reply can settle a receipt.
|
|
108
|
+
|
|
109
|
+
The console interface is:
|
|
110
|
+
|
|
111
|
+
```text
|
|
112
|
+
ahub queue list [--peer <id>] [--json]
|
|
113
|
+
ahub queue show <delivery-id>
|
|
114
|
+
ahub queue resolve <delivery-id> --action completed|retry|discard --reason "<text>"
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
These queue commands are part of 0.7.0 and are not available in the released
|
|
118
|
+
0.6.4 CLI. Until protocol 10 is installed, use `ahub status`, `ahub tail`,
|
|
119
|
+
and the task board. A known offline recipient may be queued explicitly once
|
|
120
|
+
the 0.7.0 journal is active; broadcast and automatic assignment still require
|
|
121
|
+
an attached peer.
|
|
122
|
+
|
|
123
|
+
Resolution requires the current observed revision. A retry closes the old
|
|
124
|
+
record and creates one linked attempt. Stale or conflicting resolutions fail.
|
|
125
|
+
If dispatching or accepted work has an uncertain outcome after a crash,
|
|
126
|
+
the system marks it `needs_review`. Establish evidence before choosing
|
|
127
|
+
`completed`, `retry`, or `discard`. Timeouts,
|
|
128
|
+
disconnects, cancellation, and partial effects are uncertain; do not replay
|
|
129
|
+
them automatically.
|
|
130
|
+
|
|
131
|
+
## Graceful shutdown
|
|
132
|
+
|
|
133
|
+
Before stopping, let active turns and approvals settle when possible:
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
ahub status
|
|
137
|
+
ahub tail
|
|
138
|
+
ahub kill
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
The daemon waits for shutdown work that must survive termination. Afterward,
|
|
142
|
+
run `ahub status` or `ahub up` and read the project state before restarting
|
|
143
|
+
peers. A stopped daemon does not delete task records or the durable journal.
|
|
144
|
+
Do not kill a native terminal by PID or start a replacement while ownership is
|
|
145
|
+
uncertain.
|
|
146
|
+
|
|
147
|
+
## Upgrade and crash recovery
|
|
148
|
+
|
|
149
|
+
For an upgrade from 0.6.4 (protocol 9) or 0.7.0, use the patched coordinator without
|
|
150
|
+
replacing the global CLI prematurely. Run from the project directory:
|
|
151
|
+
|
|
152
|
+
```bash
|
|
153
|
+
bunx --package @staix/agent-hub@0.7.1 ahub upgrade --to 0.7.1 --dry-run
|
|
154
|
+
bunx --package @staix/agent-hub@0.7.1 ahub upgrade --to 0.7.1 --yes
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
The coordinator verifies and retains the exact target package, preserves its
|
|
158
|
+
own source, and promotes the global CLI only after restored projects pass
|
|
159
|
+
readback. Do not use the old protocol-9 coordinator to target protocol 10.
|
|
160
|
+
|
|
161
|
+
Once the installed CLI is 0.7.1, review the current project or all registered
|
|
162
|
+
projects first:
|
|
163
|
+
|
|
164
|
+
```bash
|
|
165
|
+
ahub restart --dry-run
|
|
166
|
+
ahub upgrade --to 0.7.1 --dry-run
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
Apply only after reviewing the plan:
|
|
170
|
+
|
|
171
|
+
```bash
|
|
172
|
+
ahub restart --yes
|
|
173
|
+
ahub upgrade --to 0.7.1 --yes
|
|
174
|
+
ahub recovery status <operation-id>
|
|
175
|
+
ahub recovery resume <operation-id>
|
|
176
|
+
ahub recovery abort <operation-id>
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
The 0.7.0 transition stages the verified package and runs a retained
|
|
180
|
+
coordinator from the source tree. It accepts a verified protocol-9 source and
|
|
181
|
+
moves to a protocol-10 target. The source journal, queued envelopes, tasks,
|
|
182
|
+
manual pauses, budget state, and native session identity are read back before
|
|
183
|
+
release. The global CLI is promoted last.
|
|
184
|
+
|
|
185
|
+
A lost commit or start reply is reconciled against the actual daemon identity,
|
|
186
|
+
package digest, terminal binding, and phase receipt. An uncertain terminal
|
|
187
|
+
creation is never repeated blindly. If Claude shows its development-channel confirmation screen, confirm it in
|
|
188
|
+
the captured terminal, then run `ahub recovery resume <operation-id>`; resume must not open a duplicate terminal.
|
|
189
|
+
Kimi and local sessions may start fresh with preserved routing and task context.
|
|
190
|
+
Previously stopped projects stay stopped; only the reviewed running projects
|
|
191
|
+
are upgraded.
|
|
192
|
+
|
|
193
|
+
Do not run an upgrade with an incompatible active protocol, an unverified
|
|
194
|
+
terminal binding, or an unresolved operation lock. Dry-run performs no package,
|
|
195
|
+
plugin, daemon, or terminal mutation.
|
|
196
|
+
|
|
197
|
+
## Evidence and limits
|
|
198
|
+
|
|
199
|
+
The 0.6.4 release has real measurements in [the smoke checklist](smoke.md):
|
|
200
|
+
Pi returned an exact file marker through MLX in 5.800 seconds in the production
|
|
201
|
+
probe; the installed-package checks measured Pi MLX at 2.234 seconds, Pi DGX
|
|
202
|
+
at 1.324 seconds, and a 208 ms MLX-to-DGX handover with the same session
|
|
203
|
+
identity. A real Kimi 2.0.1 and Pi run showed queue counts and priority counts
|
|
204
|
+
matching between the CLI and status file. These are individual observations,
|
|
205
|
+
not a latency or reliability benchmark.
|
|
206
|
+
|
|
207
|
+
The 0.6.4 production readback retained two envelopes for a disconnected Codex
|
|
208
|
+
peer with identical IDs before and after recovery; general status lists attached
|
|
209
|
+
peers and therefore did not show that backlog. No messages were deleted. The
|
|
210
|
+
0.7.0 queue readback and receipt semantics remain pending live verification.
|
|
211
|
+
|
|
212
|
+
Issue [#12](https://github.com/STAIxBWLB/agent-hub/issues/12) remains open for
|
|
213
|
+
off-campus Access credentials and a natural near-limit budget pause. Tests,
|
|
214
|
+
synthetic approvals, and an authenticated internal network do not close those
|
|
215
|
+
prerequisites. Adapter acceptance is not task completion, and package
|
|
216
|
+
installation or a passing test suite is not proof of a successful production
|
|
217
|
+
cutover.
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
# Quickstart
|
|
2
|
+
|
|
3
|
+
agent-hub lets the coding agents on one machine work as peers in one project directory: Claude Code, Codex, Kimi Code, and `local`, a worker the hub runs itself on a model you host. You talk to all of them from the hub console.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
Needs [Bun](https://bun.sh) 1.3 or newer and macOS (Linux works without the `local` worker's `bash` and `git` tools, which need the macOS sandbox).
|
|
8
|
+
|
|
9
|
+
Node alone is not supported. Keep `bun` on PATH even if you install with npm.
|
|
10
|
+
The registry package uses the `staix` organization scope. Install from npm:
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
bun add -g @staix/agent-hub # installs `ahub` (also as `agent-hub`)
|
|
14
|
+
ahub setup # installs the Claude Code channel plugin from this package, then runs doctor
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Or use the matching GitHub release:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
bun add -g github:STAIxBWLB/agent-hub#v0.7.1
|
|
21
|
+
ahub setup
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
From a clone instead: `git clone`, `bun install`, `bun link`.
|
|
25
|
+
|
|
26
|
+
`ahub doctor` tells you what is installed, running and configured. Rows you do not need can stay red: the hub works with any subset of the peers.
|
|
27
|
+
|
|
28
|
+
For managed launchers, two-agent task/review work, approvals, graceful shutdown,
|
|
29
|
+
and upgrade or crash recovery, see the [operations guide](operations.md).
|
|
30
|
+
|
|
31
|
+
## First session
|
|
32
|
+
|
|
33
|
+
In your project directory, one terminal each:
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
ahub init # .agenthub/config.json, .agenthub/routing.toml, marker blocks in CLAUDE.md and AGENTS.md
|
|
37
|
+
ahub up # the daemon for this directory (loopback only)
|
|
38
|
+
ahub tail # keep open: the conversation, state changes, permission requests
|
|
39
|
+
ahub kimi # Kimi, headless
|
|
40
|
+
ahub codex # Codex TUI, attached through the hub
|
|
41
|
+
ahub claude # Claude Code with the hub channel
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Then talk:
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
ahub say "Each of you: reply with your name." # broadcast
|
|
48
|
+
ahub say @kimi "run the tests and report" # one peer
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## The local worker
|
|
52
|
+
|
|
53
|
+
`local` needs an OpenAI-compatible gateway. Put yours in `.agenthub/config.json`:
|
|
54
|
+
|
|
55
|
+
```json
|
|
56
|
+
{ "omniroute": { "urls": ["http://your-gateway:20128/v1"], "api_key_file": "/path/to/key" } }
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
or set `OMNIROUTE_API_KEY`. Name the model in `.agenthub/routing.toml` (`[local] fixed_model`). Then `ahub local`. It works only inside the project, asks before it writes or runs anything (`ahub permit <id> allow`), and everything it executes is sandboxed.
|
|
60
|
+
|
|
61
|
+
## The five commands of a working day
|
|
62
|
+
|
|
63
|
+
| Command | What for |
|
|
64
|
+
| --- | --- |
|
|
65
|
+
| `ahub say [@peer] <text>` | talk; start with `[STATUS]` to let it batch, `[FYI]` for the record only |
|
|
66
|
+
| `ahub task propose [--class <c>] <title>` | put work on the board; the hub picks an owner and a reviewer, and the class if you name none |
|
|
67
|
+
| `ahub board` | who has what; `ahub task show <id>` for one task |
|
|
68
|
+
| `ahub status` | peers, queues, pauses; `ahub budget` for quota windows |
|
|
69
|
+
| `ahub ask <question>` | what the board, shared memory and the log say, with the ids the answer rests on |
|
|
70
|
+
| `ahub kill` | stop the daemon and everything it started |
|
|
71
|
+
|
|
72
|
+
More: `ahub help`. How it is built and why: [`docs/specs/2026-09-19-agent-hub-design.md`](specs/2026-09-19-agent-hub-design.md). What it protects and what it does not: [`docs/security.md`](security.md).
|
|
73
|
+
|
|
74
|
+
## Browser dashboard
|
|
75
|
+
|
|
76
|
+
After `ahub up`, run `ahub ui` to open the local dashboard. It refreshes the
|
|
77
|
+
conversation stream, peer queues, task board, budget windows and approvals every
|
|
78
|
+
second. No build step, web server command or browser extension is needed.
|
|
79
|
+
|
|
80
|
+
Use the page to pause/resume a peer, send a console message, propose/assign tasks,
|
|
81
|
+
and allow/deny agent permission requests. Local-worker requests show no tool
|
|
82
|
+
contents: inspect them with `ahub tail`, then use `ahub permit <id> <option>` to
|
|
83
|
+
allow. They can be denied on the page. PII task details remain available only via
|
|
84
|
+
`ahub task show <id>` in the terminal.
|
|
85
|
+
|
|
86
|
+
`ahub ui --no-open` prints a one-time link instead of launching a browser. Open it
|
|
87
|
+
within 60 seconds. A session expires after one hour; run `ahub ui` again. Restarting
|
|
88
|
+
the daemon invalidates all links and sessions. The UI listener is started only on
|
|
89
|
+
request, binds loopback and stops with the daemon. Remote access is not supported.
|
|
90
|
+
|
|
91
|
+
The stream retains the latest 200 events since the dashboard listener was started;
|
|
92
|
+
it does not load historical logs. An unopened dashboard has no listener or event
|
|
93
|
+
buffer. A paused budget window cannot be overridden on the page; the CLI's
|
|
94
|
+
`ahub budget resume <peer>` remains the explicit override.
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
## Concurrent project development (0.4.0)
|
|
98
|
+
|
|
99
|
+
Initialize and start each repository/worktree separately, or use the global
|
|
100
|
+
`--project <path|id>` prefix. `ahub projects` lists registered roots and live
|
|
101
|
+
status; `ahub status --all` includes peer/task summaries. Within a subdirectory,
|
|
102
|
+
commands use the nearest project inside that Git working-tree boundary.
|
|
103
|
+
|
|
104
|
+
Open `ahub ui --all` from any directory to manage all registered hubs. Use Start
|
|
105
|
+
to launch an initialized project, Use to view a running project, and Stop to stop
|
|
106
|
+
the selected hub. Stop confirmation names its root. Terminal agent launch is
|
|
107
|
+
still `ahub --project <path> claude` or `ahub --project <path> codex`.
|
|
108
|
+
|
|
109
|
+
The manager is independent: `ahub ui --all --stop` closes its browser sessions
|
|
110
|
+
without stopping project hubs. One-time links and session expiry work the same
|
|
111
|
+
way as the project-local dashboard. For headless environments use `--no-open`.
|
|
112
|
+
|
|
113
|
+
Project data is retained after stopping and after `ahub projects remove <id>`.
|
|
114
|
+
To use a custom runtime directory initially, set both `AGENTHUB_PROJECT_DIR` to
|
|
115
|
+
the canonical project root and `AGENTHUB_STATE_DIR` to the desired directory;
|
|
116
|
+
subsequent explicit project selection reads the registered location.
|
|
117
|
+
|
|
118
|
+
For dashboard-started model workers, put gateway URLs and credential-file
|
|
119
|
+
references in that project's config. The manager never copies another project's
|
|
120
|
+
gateway override or unattended setting. Native memory and provider accounts keep
|
|
121
|
+
their existing sharing rules; the dashboard marks shared native memory aliases.
|
package/docs/security.md
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# Security notes
|
|
2
|
+
|
|
3
|
+
agent-hub connects agents that can each run commands. This page says what the hub defends, how, and what it does not.
|
|
4
|
+
|
|
5
|
+
## Trust boundaries
|
|
6
|
+
|
|
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, a fixed header line plus 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
|
+
- **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`. External clients cannot claim the console user's id or a hub-managed peer's id.
|
|
9
|
+
- **Permission prompts stay on.** `ahub claude` and `ahub codex` add nothing that weakens the agents' own prompts. Kimi's and `local`'s permission requests are relayed to the console and cancelled after 120 s of silence. `--unattended` turns prompts off, says so loudly, and is never the default.
|
|
10
|
+
- **The local worker is boxed in.** Paths are resolved through symlinks and must stay inside the project; a secrets denylist (`.env*`, keys, credential files, the hub's own state) applies to its file tools, its git arguments and its memory capture alike; `.git` and `.agenthub` are not writable. Writes, edits, shell commands and mutating git wait for approval, and the approver sees what will be written or run, with control characters escaped. Everything it executes runs under the macOS sandbox, attended or not: no writes outside the project, its git dir and temp; the home directory is unreadable except toolchains; no `.git/hooks` or `.git/config` writes; no network, loopback included. Without the sandbox there is no `bash` tool.
|
|
11
|
+
- **PII has an enforced path.** A task matching `signals.pii_patterns` goes to `local` or to nobody; its text is absent from other peers' envelopes, the console stream, the log and the board listing; the console user reviews it; `local` answers such a turn to the console only, keeps it out of its history, refuses it when the only gateway is off campus, and may not save notes or spin off tasks during it. Nothing about it is sent to claude-mem, whose observer is a cloud model.
|
|
12
|
+
- **Secrets stay where they are read.** The gateway key and Cloudflare Access values are read inside the gateway client and go only into request headers: never into logs, errors, envelopes, tool output, memory, or the generated Switchyard config (the key travels by environment variable name). Subscription logins of Claude, Codex and Kimi are never proxied or pooled.
|
|
13
|
+
- **The hub's own model calls are fenced.** Digest condensation and task triage read agent-written text as data; their output is capped text framed as untrusted, or a value checked against a closed list. It is never used as a route, a peer id, a tool call or an instruction.
|
|
14
|
+
|
|
15
|
+
## What is not defended
|
|
16
|
+
|
|
17
|
+
- **A malicious local process running as you.** It can read the control token, `hub.db`, the project and your home directory without the hub's help. The token keeps web pages and other users out, not your own processes.
|
|
18
|
+
- **An agent you launched without its own safeguards.** The hub frames and routes; it does not sandbox Claude Code, Codex or Kimi. `--unattended` plus untrusted peer text is a risk you opt into.
|
|
19
|
+
- **What an approved command does inside the project.** The sandbox bounds where a command can write and what it can read, not whether `rm -rf src` was a good idea. Read what you approve.
|
|
20
|
+
- **Network-level proof for PII.** The hub proves at its own boundaries (tests search every output) that PII text does not leave; packet-level verification of your gateway path is an operations check.
|
|
21
|
+
- **Other operating systems' sandboxes.** Only macOS seatbelt is implemented.
|
|
22
|
+
|
|
23
|
+
## Reporting
|
|
24
|
+
|
|
25
|
+
Please report vulnerabilities privately through GitHub's "Report a vulnerability" on this repository rather than in a public issue.
|
|
26
|
+
|
|
27
|
+
## Local dashboard sessions (issue #6)
|
|
28
|
+
|
|
29
|
+
- `ahub ui` uses the authenticated console control connection to start an ephemeral HTTP listener on `127.0.0.1`. No UI listener exists before that command. The control and Codex proxy ports continue to refuse every `Origin` header.
|
|
30
|
+
- The daemon issues a cryptographically random, single-use bootstrap ticket valid for 60 seconds. The CLI opens the dashboard with that ticket in the URL fragment, never a query string or the control token. The static page removes the fragment immediately and exchanges it with a same-origin POST. Tickets are consumed once; expired tickets cannot create sessions.
|
|
31
|
+
- The exchange creates a separate random session, valid for one hour without renewal, in an `HttpOnly; SameSite=Strict; Path=/` cookie named for this listener's port. Sessions and tickets live only in memory and die with the daemon. HTTP is loopback-only; the cookie is not a substitute for the origin checks.
|
|
32
|
+
- Every request must have the exact listener Host. Every data or action request, including the ticket exchange and snapshot polling, must be POST with the exact listener Origin and JSON content type. Foreign and missing origins, missing or expired sessions, oversized bodies and unknown actions are rejected. There is no CORS support. The only unauthenticated GET is the fixed, data-free HTML shell. No files or paths are served dynamically.
|
|
33
|
+
- Responses are non-cacheable, cannot be framed, suppress referrers, and use a content security policy restricting scripts/styles to the shipped inline content and connections to this origin. Browser text is rendered with textContent, never interpreted as HTML.
|
|
34
|
+
- The browser receives a bounded redacted event stream, peer states and queue counts, public task views, budget windows and pending approvals. Private envelope bodies and PII task text never cross this endpoint. Local-worker approval titles can contain PII, so their details remain terminal-only; the dashboard identifies the request and directs the operator to `ahub tail` before allowing it. Budget checkpoint summaries are also omitted.
|
|
35
|
+
- The closed action list is permission response, peer pause/resume, console message, task proposal and task assignment. These use the existing daemon/task paths and budget pause rules. There is no generic control proxy, task-detail read, shell, file access, configuration edit, budget override, peer launch or daemon shutdown API.
|
|
36
|
+
- The listener stops with the daemon. Expired sessions must be reopened with `ahub ui`; the page does not silently obtain new credentials.
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
## Multi-project manager (protocol 7)
|
|
40
|
+
|
|
41
|
+
The manager has its own loopback session server and authenticated local control
|
|
42
|
+
endpoint. Browsers provide registered project IDs and expected daemon instance
|
|
43
|
+
IDs; they cannot submit arbitrary paths, ports, PIDs or control tokens. The
|
|
44
|
+
manager forwards the same closed, redacted dashboard operations as a project-local
|
|
45
|
+
page. It cannot expose private task history or allow local-worker tools.
|
|
46
|
+
|
|
47
|
+
Per-project control handshakes verify project, root and instance against the
|
|
48
|
+
runtime manifest. Shutdown removes only the owning instance's runtime files and
|
|
49
|
+
waits for owned child processes. Registry and manager startup claims serialize
|
|
50
|
+
concurrent starts; uncertain ownership is reported, not forcibly reclaimed.
|
|
51
|
+
A stale browser action against a restarted daemon is rejected, and mutations are
|
|
52
|
+
never automatically replayed after a connection failure.
|
|
53
|
+
|
|
54
|
+
The manager can start registered hubs in attended mode. Its project launches do
|
|
55
|
+
not inherit state, unattended or gateway URL/key overrides from the session that
|
|
56
|
+
opened the manager. Native memory is deliberately not a project-isolation boundary:
|
|
57
|
+
its existing basename/worktree aliases and provider accounts can remain shared.
|