@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 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.6.4. All six milestones of the design spec are implemented; the [smoke checklist](docs/smoke.md)
8
- says what has and has not been verified against real agents.
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
- Version 0.5.0 adds [controlled upgrade and session recovery](docs/specs/2026-09-20-upgrade-recovery-design.md).
11
- After bootstrapping a protocol-8 hub, use `ahub restart --dry-run` to inspect one
12
- project or `ahub upgrade --to <exact-version> --dry-run` to inspect an upgrade of
13
- the running projects. Remove `--dry-run` to review and schedule the operation;
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.6.4 && ahub setup
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 recovery metadata;
105
- protocol-8 hubs can use controlled upgrade, while protocols 5-7 still require
106
- their matching CLI and an attended bootstrap.
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 to protocol 7, stop existing hubs with their matching CLI, then
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 [multi-project specification](docs/specs/2026-09-19-multi-project-design.md).
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.
@@ -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.