@staix/agent-hub 0.14.0 → 0.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +17 -0
- package/README.md +16 -6
- package/docs/agent-notes/README.md +4 -0
- package/docs/agent-notes/adapters.md +17 -3
- package/docs/agent-notes/budget.md +4 -4
- package/docs/agent-notes/bus.md +1 -0
- package/docs/agent-notes/daemon.md +14 -9
- package/docs/agent-notes/tasks.md +9 -4
- package/docs/agent-notes/tests.md +3 -3
- package/docs/dogfood.md +9 -4
- package/docs/events.md +21 -7
- package/docs/operations.md +90 -18
- package/docs/profiles.md +1 -0
- package/docs/quickstart.md +9 -3
- package/docs/sdlc.md +17 -0
- package/docs/security.md +37 -10
- package/docs/specs/2026-09-19-agent-hub-design.md +74 -10
- package/docs/verification/2026-10-23-0.15.0.md +80 -0
- package/docs/verification/2026-10-23-daemon-responsiveness.md +44 -0
- package/docs/verification/2026-10-23-headless-claude-permissions.md +47 -0
- package/docs/verification/2026-10-23-terminal-claude-execution-root.md +41 -0
- package/docs/verified.json +29 -17
- package/package.json +1 -1
- package/plugins/agent-hub/.claude-plugin/plugin.json +1 -1
- package/plugins/agent-hub/server.js +992 -312
- package/src/adapters/acp.ts +43 -7
- package/src/adapters/claude-channel.ts +26 -4
- package/src/adapters/claude-implementer.ts +243 -0
- package/src/adapters/claude-print-child.ts +90 -0
- package/src/adapters/claude-task-sessions.ts +80 -0
- package/src/adapters/compat.ts +4 -0
- package/src/adapters/conformance/enrollment.ts +2 -1
- package/src/adapters/conformance/fakes/acp-server.ts +3 -1
- package/src/adapters/definitions/builtin-metadata.ts +14 -2
- package/src/adapters/definitions/native-channel-state.ts +1 -1
- package/src/adapters/definitions/native-cli-entry-claude.ts +13 -8
- package/src/adapters/definitions/native-cli-entry-types.ts +2 -0
- package/src/adapters/definitions/native-factories.ts +8 -0
- package/src/adapters/kimi-wire-usage.ts +303 -0
- package/src/adapters/registry-types.ts +7 -3
- package/src/adapters/registry.ts +14 -2
- package/src/adapters/reviewer-print.ts +30 -53
- package/src/cli/console-config.ts +123 -0
- package/src/cli/console-state.ts +28 -1
- package/src/cli/console.ts +25 -1
- package/src/cli/facts-hook.ts +9 -5
- package/src/cli/help.ts +4 -3
- package/src/cli/launch.ts +10 -4
- package/src/cli/main.ts +47 -9
- package/src/cli/output.ts +28 -0
- package/src/cli/reset.ts +1 -1
- package/src/cli/settings-edit.ts +89 -0
- package/src/cli/terminal-recovery.ts +1 -6
- package/src/hub/action-enforce.ts +82 -0
- package/src/hub/action-policy.ts +22 -10
- package/src/hub/board.ts +26 -2
- package/src/hub/budget.ts +5 -0
- package/src/hub/bus.ts +5 -5
- package/src/hub/claude-launch-proof.ts +33 -0
- package/src/hub/config-apply.ts +5 -0
- package/src/hub/config-edit-host.ts +173 -0
- package/src/hub/config-edit.ts +282 -0
- package/src/hub/config-tier.ts +89 -0
- package/src/hub/control-client.ts +24 -3
- package/src/hub/daemon.ts +368 -59
- package/src/hub/deliverable-files.ts +131 -0
- package/src/hub/deliverables.ts +125 -0
- package/src/hub/delivery-journal.ts +18 -2
- package/src/hub/events.ts +3 -1
- package/src/hub/hub-tools.ts +19 -3
- package/src/hub/instances.ts +7 -4
- package/src/hub/kimi-usage.ts +144 -0
- package/src/hub/manager.ts +1 -1
- package/src/hub/peers.ts +7 -0
- package/src/hub/permission-payload.ts +15 -0
- package/src/hub/routing.ts +118 -3
- package/src/hub/settings.ts +1 -1
- package/src/hub/tasks.ts +202 -15
- package/src/hub/token-window.ts +33 -0
- package/src/hub/usage-rollup.ts +16 -6
- package/src/hub/workflow.ts +16 -0
- package/src/ui/index.html +115 -1
|
@@ -431,8 +431,12 @@ inside a peer.
|
|
|
431
431
|
update whenever it names the current session, since 2.1.1's source text emits it
|
|
432
432
|
after the prompt resolves (an order read from the source, not yet observed live
|
|
433
433
|
through the hub; docs/smoke.md). A gate crossing records the
|
|
434
|
-
event and notice for an ACP peer but sends it no checkpoint request yet.
|
|
435
|
-
|
|
434
|
+
event and notice for an ACP peer but sends it no checkpoint request yet. Since #285 phase 2 the soft ceiling's counter is the
|
|
435
|
+
hub's own count of Kimi's session wire log (`src/adapters/kimi-wire-usage.ts`, wire protocol 1.5, read on Kimi 2.3.0; the issue
|
|
436
|
+
read 2.1.1), not an ACP total: each `usage.record` row of the owned session, sub-agents included, is a `usage` event
|
|
437
|
+
(`source: kimi_wire`) and a `tokens` event, and the rolling 5 h sum of `inputOther + inputCacheCreation + output` (cache reads are
|
|
438
|
+
recorded, never counted) is the `tokens` window, source `hub count, kimi wire log, of kimi_tokens_5h N`. Any read the reader
|
|
439
|
+
cannot trust gives unknown (one notice, the reading dropped), never a short count. `ahub budget set`
|
|
436
440
|
feeds a reading by hand. `local` has no quota and is never paused.
|
|
437
441
|
- Gate at `budget.gate` (default 0.9) on any fresh window; readings older than
|
|
438
442
|
`budget.stale_min` are ignored. Checkpoint first, pause second: the peer gets one
|
|
@@ -927,6 +931,13 @@ This slice provides the pure classifier, machine-local policy, host-only per-ses
|
|
|
927
931
|
- The first selected action asks. One explicit person approval of the class allowance authorizes that invocation and caches at most budget minus one follow-up invocations of each selected class. An ordinary allow_once answer never seeds this cache; adapter prompts must describe the class allowance they request. The next invocation after exhaustion asks again. Requests consume all selected class slots synchronously or none; an unselected/unclassified action returns `native`, which means the existing permission decision still runs. No ledger result overrides a denial, suppresses a prompt required by the native mode, or grants a tool capability. Session identity comes from the host's current runtime port; missing or changed identity cannot use a grant. New sessions, owner revocation and policy publication invalidate grants. One-use approval challenges are bound to the exact session handle and policy, so a late answer cannot grant to a replacement session or changed policy.
|
|
928
932
|
- Status reads never create/bind/reset a session. Status carries only classes, limits, remaining counters and enforcement state, without native session ids or command/task text. Approval copy is built through `actionApprovalText`, which takes the host's `publicView`, private-turn decision and whole-command privacy projection; private commands are withheld. Adapter integrations must retain the existing timeout-denies and generation/privacy rechecks after awaiting a person. Slice 1 creates no approval requests itself and makes no per-adapter A2 or live/native enforcement claim.
|
|
929
933
|
|
|
934
|
+
## Always-ask enforcement: Claude and ACP (#636 slice 2)
|
|
935
|
+
|
|
936
|
+
- **Claude.** The `facts` reply to a PreToolUse hook call carries `actionClasses` when `classifyAction` classes the tool and its arguments under the peer's execution root and the policy selects at least one class. `factsHook` then emits `permissionDecision: "ask"` (with `permissionDecisionReason: "agent-hub always-ask: <classes>"`) in every permission mode, and the `ask` replaces any `allow` the mode would add. The managed hook's contract is therefore: it may add `allow` as before and `ask` for a classed call, never `deny`; a hub that is down, slow or refusing decides nothing (`docs/agent-notes/daemon.md`). A value that is present but unreadable asks as well; an absent or empty one leaves the mode. Claude's dialog cannot carry a class-budget choice, so the ledger is never consulted for Claude: every classed call asks. A hub that cannot answer, or a call outside a verified hub hook, leaves Claude's own policy.
|
|
937
|
+
- **ACP.** `AcpPeer.answerPermission` consults `AcpOptions.actionGate` before `autoApprove`, with the announced and canonical tool names, the ACP kind and the arguments from `rawInput`, the announced `tool_call` or complete streamed JSON. A call with no reported payload is not classed (unknown follows the mode). A verdict (a classed call with no session budget left) is never auto-approved, drops `allow_always`, replaces the title with `actionApprovalText` (the task title only through `publicView`, the command only through the PII screen, withheld for a private turn or an open PII task) and sets `classed` on the `PermissionRequest`, so `--unattended` does not answer it. A throwing gate asks. The request uses the existing approval timeout and a timed-out request denies.
|
|
938
|
+
- **Class budget.** When a selected class has a budget above one, the request carries the hub's own option `agent-hub:action-budget` (kind `allow_once`). Only a person's choice of it calls `ActionBudgets.approve`, which spends the allowance for the current native session and policy; the agent is answered with its own `allow_once` id and never sees the hub's. A refused approval (changed policy, replaced session, no slot left) answers cancelled. An ordinary allow never seeds the ledger. Requests are concurrent, so several challenges can be open while a class is spent: the first approval opens the allowance, a later approval of a challenge issued before it consumes one slot instead of opening another (refused whole when any class has none left), so a budget of N lets through at most N approved calls. The ledger entry is revoked whenever an ACP owner goes offline, is stopped or removed, or a new owner is created, so a resumed session id never brings an allowance back. A call inside the cached allowance follows the permission mode as before.
|
|
939
|
+
- **Visibility.** `status.actionPolicyInfo[peer].enforceable` is true only where the call is seen before it runs: a Claude session with the launcher's PreToolUse hook that is not `--unattended`, and a hub-owned ACP peer in native mode `ask` (Kimi's `yolo` and `auto` send no request for a call they allow). For Claude the launch record alone is not proof (it outlives the process): the attached session must be online and its current generation must have run the hub's hook (`claudePermissionGenerations`). Every other peer, and Codex, Pi and the local worker until slice 3, says `always-ask not enforceable: <reason>`.
|
|
940
|
+
|
|
930
941
|
## Amendment: approval notifications and timeout (issue #5)
|
|
931
942
|
|
|
932
943
|
- A waiting permission request raises one macOS notification (`osascript`) with
|
|
@@ -2463,6 +2474,19 @@ acts on the stopped state directory.
|
|
|
2463
2474
|
- Control protocol: `settings_get`, `settings_set`, `settings_undo` and `settings_preview` are new console-role requests, and `ui` takes an optional `settings` flag and echoes it; an older hub answers the requests as unknown, and the CLI refuses a `ui` reply without the echo, so `PROTOCOL` stays 16. The `ui_snapshot` reply gains an optional `settings` object. Events schema stays 1.
|
|
2464
2475
|
- `ahub settings` talks to the running hub (ponytail: a file-only path if setting a start-time value on a stopped hub is ever wanted).
|
|
2465
2476
|
|
|
2477
|
+
## Amendment: structural configuration from the console and the dashboard (issue #689)
|
|
2478
|
+
|
|
2479
|
+
- The registry (`src/hub/settings.ts`) stays closed and unchanged. A second path, `src/hub/config-edit.ts` (plan and write) with `src/hub/config-tier.ts` (the tier rule) and `src/hub/config-edit-host.ts` (authority, confirmation, audit, scoped publish), edits structural keys. Tier 2: `instances.<id>.{kind, roles, start_mode, review_mode, readOnly, worktree, permission_mode}`, `review.{adaptive, min_reviews, pool, rerotate}`, `snapshots.keep`, `approvals.timeout_s`, `context.gate` (all `config.local.json`) and `sdlc.toml` `mode` and `required_checks`. Tier 3: the rest of `NEVER_EDITABLE` and an instance's `jcode_home`, `provider`, `model` and `provider_profile`. `roster`, `tasks.wip_limits` and the other registry keys are refused here with the registry command.
|
|
2480
|
+
- Validation is the daemon's own: `parseConfigSources` (raw bounds and instance declarations through `readInstanceConfig` and `validateInstances`), `loadConfig`, `checkJcodeInstanceHomes` for `config.local.json`, `sdlcConfig` for `sdlc.toml`. A loader's reason is returned as it is with the `field` it names. A candidate is built from the file on disk, and a request that would drop a tier 3 field of an existing instance (by replacing it with a tier 2 object) is refused.
|
|
2481
|
+
- Writes: revision check against the disk when planning and again before writing (sha256 of the file, or `absent`); a bounded backup in `<state dir>/config-backups/` (the newest five per file); a temp file and rename in the same directory with the file's mode; never a git-tracked `config.local.json`, a symlink or a file over its size limit (1 MiB, 64 KiB for `sdlc.toml`). `sdlc.toml` is edited line by line for `mode` and `required_checks` only, and the result is parsed and compared with the intended change before it is accepted.
|
|
2482
|
+
- Tiering reads the file: `configTier(file, path, value, held)` makes `instances.<id>` tier 3 to remove or replace when the instance holds `jcode_home`, `provider`, `model` or `provider_profile`, and `maskTier3` shows every tier 3 value in a reply, a diff line or a notice as `(set)`. `readEditable` refuses a symlinked `.agenthub` as well as a symlinked file, `viewRevisions` reports `unavailable` instead of throwing, and the sdlc editor keeps each untouched line's own line ending.
|
|
2483
|
+
- Authority: the console role (`config_edit_get`, `config_edit_preview`, `config_edit_apply`; `settings_get` also carries the file revisions) or a dashboard settings session (`config_edit_preview` and `config_edit_apply` actions; the manager forwards both). An ordinary session, a tools or peer connection and any agent shell are refused. A tier 3 key is refused for a dashboard session by the hub and is console only, with the key's name typed as the confirmation (one key per write). Recovery or shutdown holds edits.
|
|
2484
|
+
- Publication: `reloadConfig` stays the only path. The editor publishes each changed leaf with its own scope and registers that scope for the one reload (`structural` in `authorizeConfigLeaf`, admitted only for `config.local.json`, source `config` and `structuralLeaf`), so a settings session can publish a structural edit and nothing else it could not before. Instance declarations are restart-bound (`pending restart: instances`); `sdlc.toml` is read once at start and is added to `pendingRestart` in `status.json`, the console snapshot and the settings view until the running lifecycle equals the file.
|
|
2485
|
+
- Audit: a `config_edit` event (`file`, `paths` as `{path, before, after}` short value hashes, `fileBefore` and `fileAfter` revisions, `tier`, `source`, `by: "person"`, optional `reason`, `backup`). No value, no secret and no home path enters the event, the notice or `hub.log`.
|
|
2486
|
+
- Console: Settings key `c` (what to edit, each field, the hub's diff or loader reason, a reason, `y`; a tier 3 key asks for its name instead of `y`), `R` while a restart is pending prefills `restart`. CLI: `ahub settings edit` and `ahub settings backups`. Dashboard: a Structure group in Settings (forms inside a settings session, read only outside one, tier 3 as text with the console command, restart-pending badge, backups), both themes, 44 px targets, one column at phone width.
|
|
2487
|
+
- Control protocol: three new console-role requests and two new dashboard actions; no `PROTOCOL` bump, an older hub answers unknown and the CLI says to upgrade and restart it.
|
|
2488
|
+
- Unverified: a live `ahub ui --settings` browser session and a real restart that picks up an edited `sdlc.toml` (the person's leg).
|
|
2489
|
+
|
|
2466
2490
|
## Amendment: TUI by default, headless as opt-in (issue #269, part 2)
|
|
2467
2491
|
|
|
2468
2492
|
- `peers.<id>.start_mode` (`tui` or `headless`, for pi, codex, kimi and jcode; `tui` when unset) is the mode a start takes when nothing more specific was asked. Claude has only a TUI; Kimi defaults to its own pull-only TUI, with ACP selectable; local stays headless. The loader refuses a malformed `peers` block.
|
|
@@ -2699,6 +2723,7 @@ the queue.
|
|
|
2699
2723
|
- Base flow meanings, routing, budgets and permission checks stay unchanged; aliases persist beside their bases even for custom dev data. Ordinary tasks under custom dev data also retain profile semantics for document overlap; unmodified dev data keeps the legacy row shape. Unknown fields/base meanings, duplicate/unknown plan fields and oversized guidance fail before task effects.
|
|
2700
2724
|
- Schemas, CLI classification, Tasks, daemon/native contracts, plugin instructions, both local-worker tool-building paths, check-name allowlists and init use the same resolved data. No-override dev contracts/schemas/instructions remain byte-identical. Old accept schemas support existing task fields.
|
|
2701
2725
|
- Flow authority remains the separately validated `roles` map; executable checks remain trusted `checks`. Example checks are display data and do not execute. Managed instruction content keeps surrounding text and quotes forged headers.
|
|
2726
|
+
- Acceptance criteria with ids (#507b) reuse the #481 S8 `criteria` checklist, the only criteria model: `sendReview` lists the recorded criteria (`- <id>: <result>`, `(optional)` for a non-required one) ahead of the profile's checklist lines in every profile, and `Tasks.review` records on the verdict the ids that the reviewer's `unmet` items name, through the pure `unmetCriteriaIds` (an item names a criterion only by starting with its exact recorded id, followed by the end of the item or a delimiter; each id once, in first-named order). The ids come from the board's checklist at the verdict, never from the caller, and are stored as `HistoryEntry.unmetCriteria` (validated: at most 32 distinct bounded ids, on a saved review verdict only) and shown in the public history. The note text is unchanged. A PII task lists and records none; a task with no checklist, a verdict with no unmet items and an item with no matching id add nothing, so every existing request and verdict is byte-identical. #513 packing and #514 learning refer to these ids.
|
|
2702
2727
|
- Override maps are bounded to 32 class entries and existing base classes; plan selections use existing fields. Role text is 2000 characters, agents 16000, examples 16 strings of 2000 characters, review checklist 16 lines of 500 characters (#507). Native ingestion/retention/measurement remains unverified; configuration changes apply after daemon/MCP restart.
|
|
2703
2728
|
|
|
2704
2729
|
|
|
@@ -4422,21 +4447,22 @@ Declaration: `"claude-impl": { "kind": "claude", "roles": ["implementer"], "star
|
|
|
4422
4447
|
- first turn of a task: `--session-id <new uuid>`, session persisted (no `--no-session-persistence`);
|
|
4423
4448
|
- later turns: `--resume <that task's uuid>`; never `--continue`, never `--fork-session`, never another task's id;
|
|
4424
4449
|
- the task-to-session map is a per-peer state file named through `claudeStateFile(<id>, ...)` (daemon.md rule), listed in `sessionPointers` (`src/cli/reset.ts`);
|
|
4450
|
+
- a newly reserved UUID becomes resumable only after a stream-json frame names that exact session; a failed start before such evidence retries with `--session-id`, never a speculative `--resume`;
|
|
4425
4451
|
- a missing transcript (positive ENOENT through `transcriptPersisted`) starts a new session for that task and records `fresh` with a console notice; any other read error keeps the recorded id;
|
|
4426
4452
|
- chat with no task reuses a task's session only when the instance owns exactly one `in_progress` task. With none, or with more than one (a raised `tasks.wip_limits.<id>`), it goes to a one-off child with `--no-session-persistence`, so unscoped chat never enters an arbitrary task's context or attribution.
|
|
4427
|
-
- **argv.** `-p --output-format stream-json --verbose --strict-mcp-config --mcp-config <tools-mode server for <id>> --setting-sources "" --settings <0600 managed settings file with the PreToolUse facts hook, purpose permission> --permission-mode default --permission-prompts host --permission-prompt-tool mcp__agent-hub__hub_permission_request --allowedTools <implementer hub tools>`. No `--bare` (it skips hooks, `claude --help` 2.1.307). No `dontAsk`, no `bypassPermissions`.
|
|
4428
|
-
- **Hub tools.** The implementer set (`hub_task_accept`, `hub_task_decline`, `hub_task_done`, `hub_checkpoint`, `hub_send`, `hub_task_show`, `hub_task_propose`, `hub_remember`, `hub_inbox`) through the ordinary tools-mode server with `AGENTHUB_PEER_ID=<id>` and a per-child `AGENTHUB_LAUNCH_ID`. The daemon accepts a `tools` hello for this id only with the current child's launch id; it is revoked when the child's group is confirmed gone.
|
|
4453
|
+
- **argv.** `-p --output-format stream-json --verbose --strict-mcp-config --mcp-config <tools-mode server for <id>> --setting-sources "" --settings <0600 managed settings file with the PreToolUse facts hook, purpose permission> --permission-mode default --permission-prompts host --permission-prompt-tool mcp__agent-hub__hub_permission_request --allowedTools <implementer hub tools>`. No `--bare` (it skips hooks, `claude --help` 2.1.307). No `dontAsk`, no `bypassPermissions`. Verified on Claude Code 2.1.309 with a real native binary and a deterministic loopback model-protocol/MCP fixture, without account authentication or model inference: `docs/verification/2026-10-23-headless-claude-permissions.md`. Only a compat-admitted native version and unchanged binary may start; the receipt is evidence for the contract, not a runtime receipt gate. Real provider/model/person-approval behavior remains a live leg.
|
|
4454
|
+
- **Hub tools.** The implementer set (`hub_task_accept`, `hub_task_decline`, `hub_task_done`, `hub_checkpoint`, `hub_send`, `hub_task_show`, `hub_task_propose`, `hub_remember`, `hub_inbox`, `hub_permission_request`) through the ordinary tools-mode server with `AGENTHUB_PEER_ID=<id>` and a per-child `AGENTHUB_LAUNCH_ID`. The daemon accepts a `tools` hello for this id only with the current child's launch id; it is revoked when the child's group is confirmed gone. `hub_inbox` may pull only a batch whose host-resolved task attribution matches the current child, using the same unique-task rule for unscoped chat as delivery. A mixed-task batch is refused before any queue removal, so other tasks reach their own child/session.
|
|
4429
4455
|
- **Permissions.**
|
|
4430
4456
|
- `ask`: the hook decides nothing; every write, edit and shell call reaches the prompt tool.
|
|
4431
4457
|
- Both modes run Claude in its `default` permission mode, never `acceptEdits`: `acceptEdits` auto-approves in-worktree edits before the hook's path gate or the prompt tool is consulted, so protected paths (`.agenthub`, agent configuration, unsafe aliases) could be written without a person. Every automatic grant comes from the hook's explicit `allow`; other writes and shell calls require the person's answer through the prompt tool.
|
|
4432
4458
|
- `ask-when-needed`: the hook answers `allow` only for `projectFileTool` targets with `projectRoot` = the execution root (worktree), so `.git`, `.agenthub` and agent configuration stay protected (`src/cli/facts-hook.ts:20-54`, `:91-96`). Shell, git writes and every path outside the worktree reach the prompt tool. This is the Pi/local ask-when-needed grant ("bash and mutating git retain console approval", operator permission modes amendment), without its sandbox, so `never-ask` is refused (R1).
|
|
4433
4459
|
- The daemon puts `permission` in a `facts` reply for this instance's current child launch id, as it does for the recorded `ahub claude` launch (daemon.md facts-hook rule extended to this one case).
|
|
4434
|
-
- **Person approvals.** `hub_permission_request` (tools-mode server, callable only by this variant's current child) puts the request on the existing approval path: console `permission` push, macOS notification (#5), `approvals.timeout_s`. Payload is the tool name plus a public rendering of the arguments made by a bounded generic sanitizer, not `Tasks.publicView` (that takes a `Task`): JSON-stringify, `sanitize()`, the PII screen used for public metadata text (a match replaces the value with `[withheld]`), path values through the same screen, then a cut at
|
|
4460
|
+
- **Person approvals.** `hub_permission_request` (tools-mode server, callable only by this variant's current child) puts the request on the existing approval path: console `permission` push, macOS notification (#5), `approvals.timeout_s`. Payload is the tool name plus a public rendering of the arguments made by a bounded generic sanitizer, not `Tasks.publicView` (that takes a `Task`): JSON-stringify, `sanitize()`, the PII screen used for public metadata text (a match replaces the value with `[withheld]`), path values through the same screen, then a cut at a character boundary with a `[cut, N chars]` marker inside the 600-character title bound (#72 rule). It never includes task text. The original arguments stay in the child's pending request and are what Claude's allow response refers to; they are not logged or shown. Options are allow-once and deny; no allow-always. While a request waits, the watchdog is kept alive (as ACP, #5).
|
|
4435
4461
|
- **No answer.** At `approvals.timeout_s` the tool returns deny with "no person answered"; Claude continues the turn with the denial; the delivery is not failed by the timeout itself; a console and log line is written.
|
|
4436
|
-
- **Hub down or refusing.** The prompt tool returns deny.
|
|
4437
|
-
- **Hook down.** Decides nothing (`facts-hook.ts:6`), so the call reaches the prompt tool
|
|
4462
|
+
- **Hub down or refusing.** The prompt tool returns deny. The native model-free fixture observed no write when the permission tool was missing, returned an error or disconnected. A pending native permission request was externally stopped after 25 seconds with no write; a native internal timeout was not established. The hub's own approval deadline returns deny and does not rely on that native timeout.
|
|
4463
|
+
- **Hook down.** Decides nothing (`facts-hook.ts:6`), so the call reaches the prompt tool. A valid person allow still authorizes the call; failure of the prompt, its deadline, its connection or its current-child fence supplies no allow. The native fixture observed both deny and allow after a failing hook.
|
|
4438
4464
|
- **Lifecycle.** The #223 guarantees, shared code, not a copy: extract the spawn (`detached: true`, own process group, `src/adapters/reviewer-print.ts:315`), watchdog and group kill from `ReviewerPrintPeer` into one helper used by both. Stop fences the generation before any await, holds the delivery `needs_review`, keeps the peer busy until the group is confirmed gone and offline only after (`reviewer-print.ts:153-164`); a failed cleanup keeps it busy and refuses a start. A start failure before the child runs is `failed_safe`; after, `needs_review`. A watchdog timeout ends the turn, not the task: the task stays `in_progress` with this owner, and the next delivery resumes its session.
|
|
4439
|
-
- **Delivery.** Ordinary implementer delivery (task and chat items). The #223 R2 review-only filter does not apply (it keys on roles exactly `["reviewer"]`).
|
|
4465
|
+
- **Delivery.** Ordinary implementer delivery (task and chat items). Inadmissible notices or foreign task refs are dropped without vetoing admissible items in the same batch; a batch with no releasable input settles `failed_safe`. Private envelopes remain refused before spawn. The #223 R2 review-only filter does not apply (it keys on roles exactly `["reviewer"]`).
|
|
4440
4466
|
- **Usage.** Tokens from the child's `result` event `usage` (as `claude-print.ts:82-85`), added to the peer and attributed per task (#200). Account `claude`, shared pauses and readings (I2). Quota windows come only from the account's existing reader (the terminal statusline tee); none is classified from result text. A `result` with an error subtype is a failed turn, not a quota reading (unverified whether 2.1.307 emits a distinct rate-limit result).
|
|
4441
4467
|
- **Done.** `hub_task_done` from the child completes the task through `Tasks` with the ordinary owner check (`by === task.owner`), then the reviewer is notified (I-2 excludes this instance from reviewing it).
|
|
4442
4468
|
- **Recovery.** `session.freshOnRestore` is false; crash resume reuses the per-task map, and each task's session is checked by transcript as above. No terminal row. Controlled recovery requires target feature `role_stages` (below).
|
|
@@ -4446,7 +4472,7 @@ Declaration: `"claude-impl": { "kind": "claude", "roles": ["implementer"], "star
|
|
|
4446
4472
|
Declaration: `"claude-impl-t": { "kind": "claude", "roles": ["implementer"], "worktree": ".worktrees/claude-impl-t" }`.
|
|
4447
4473
|
|
|
4448
4474
|
- `ahub claude --as <id>` (`src/cli/launch.ts`) resolves the execution root with `resolveInstanceExecutionCwd`, starts Claude with that cwd, and records `executionCwd` in `claude-launch.<id>.json` beside `launchId`. The hub never starts it (daemon.md: channel extras stay out of `STARTABLE_PEERS`).
|
|
4449
|
-
- The channel's hello gains an optional `cwd` (realPath of the MCP server's `process.cwd()`); additive, no `PROTOCOL` bump.
|
|
4475
|
+
- The channel's hello gains an optional `cwd` (realPath of the MCP server's `process.cwd()`); additive, no `PROTOCOL` bump. Verified model-free on Claude Code 2.1.309: an actual stream-json session initialized its stdio MCP server in the session cwd with no user/model turn. Receipt: `docs/verification/2026-10-23-terminal-claude-execution-root.md`. The optional hello uses that server cwd. Other native versions or intentional native cwd changes are not certified by this receipt; missing or different cwd never proves ownership.
|
|
4450
4476
|
- **Admission as owner.** At attach the daemon sets `executionOwners[id]` only when all hold: the hello's `launchId` is this instance's current launch record (#551); the record's `executionCwd` equals `executionRoots[id]`; the reported `cwd` resolves to the same root; the root is not the canonical cwd. Otherwise the peer attaches as before but `ownerIsolation[id]` stays false, so `assign()` refuses it as a code owner (`routing.ts:402`) and status says why. Detach, a new launch id or a changed root clears it.
|
|
4451
4477
|
- The facts reply's `projectRoot` for this instance is its execution root, so ask-when-needed grants are worktree-scoped. `never-ask` follows the terminal's existing rules.
|
|
4452
4478
|
- Terminal recovery records `terminalRoot` = the verified execution root (I2 permits it); the I3 line "terminal recovery (project root, no worktree)" is amended for implementer channel instances only.
|
|
@@ -4509,7 +4535,7 @@ Additive optional fields, no `PROTOCOL` bump (daemon.md):
|
|
|
4509
4535
|
- Paths: new `src/adapters/claude-implementer.ts`, shared child helper extracted from `src/adapters/reviewer-print.ts`, `src/adapters/definitions/builtin-metadata.ts` (variant), `src/hub/daemon.ts` (start, facts permission for child launch id, tools hello fence, `executionOwners`, `role_stages` floor), `src/hub/claude-state.ts`, `src/cli/reset.ts`, `src/hub/hub-tools.ts` (`hub_permission_request`, published only to this variant's child) and `src/adapters/claude-channel.ts` tools mode (rebuild `plugins/agent-hub/server.js`), `test/fakes/` fake `claude -p`.
|
|
4510
4536
|
- Includes the `--permission-prompt-tool` probe gate.
|
|
4511
4537
|
- ACs: AC-4, AC-3 (with 525-6 for `codex-plan` and #535 for `codex-review`).
|
|
4512
|
-
5. **525-5 Terminal Claude implementer.** Size M. Depends on 525-1.
|
|
4538
|
+
5. **525-5 Terminal Claude implementer.** Size M. Depends on 525-1. (#735, before this slice: a person-started Claude channel instance owns no task of a write class. `ownerRoleOfClass(class)` in `src/hub/routing.ts` is the one derivation: `plan` is the planner's, `review` the reviewer's and every other class the implementer's, so a class added later is a write class by default. `assign()` refuses such an instance as owner with `owner admission: a person-started Claude instance owns no write-class task until #525-5 proves its execution root`, named or automatic and whatever `ownerIsolation` says, and `ahub route explain` prints it because it is the same function. This slice deletes that one line and lets the isolation check decide.)
|
|
4513
4539
|
- Paths: `src/cli/launch.ts`, `src/adapters/claude-channel.ts` (hello `cwd`), `src/hub/daemon.ts` (admission, `executionOwners`, facts `projectRoot`), `src/cli/terminal-recovery.ts`, rebuild bundle.
|
|
4514
4540
|
- ACs: terminal half of AC-1 at runtime; a test that a mismatched or missing root keeps `ownerIsolation` false and `assign()` refuses with `owner-admission`.
|
|
4515
4541
|
6. **525-6 Codex planner and visibility.** Size M. Depends on 525-2, 525-3.
|
|
@@ -4518,6 +4544,11 @@ Additive optional fields, no `PROTOCOL` bump (daemon.md):
|
|
|
4518
4544
|
|
|
4519
4545
|
Spec-first: each slice's PR amends this section where its implementation differs, together with `docs/operations.md`.
|
|
4520
4546
|
|
|
4547
|
+
### Amendment: write-class owners and the configured ACP planner rule (#735)
|
|
4548
|
+
|
|
4549
|
+
- **Write classes are derived.** Before 525-5, a person-started Claude channel instance (`instances.mode: "external"`, declared with `worktree` and the implementer or verifier role) owns no task whose class has the implementer as owner role. That is `ownerRoleOfClass(class) === "implementer"`: every class except `plan` and `review`. Previously only `implement`, `test` and `bulk_edit` were refused (the classes that need tests), so `summarize` and `triage` could still reach such an instance. The role ceiling uses the same function, so the two cannot disagree. The refusal is code `owner-admission` in `RoutingRefusal`, with its reason in the explain trace. A headless instance with a verified root (`ownerIsolation`) is judged by the existing check, as before.
|
|
4550
|
+
- **Configured ACP agents and `planner`.** Decision: a configured ACP agent may hold `planner`. Its `adapters.<kind>.roles` or a `roles.<kind>` entry keeps `planner`, because the planner filter (`loadConductorPolicy`, `effectiveInstanceRoles`) asks the builtin registry for `projection.plannerEligible`, and a configured kind is not in that registry (`definitionOf` is undefined, so the filter passes). What it cannot do is be named by the `planner` setting or picked as the automatic planner: those read `PLANNER_PEERS`, which is derived from builtin projections, and the capability scope refuses `projection` on a configured definition (#625). No projection is given to configured agents: a projection fixes the host's role and help order and the planner choice, which a project file must not decide. The earlier statement that #725 drops `planner` for configured agents was wrong: it drops it only for the builtin kinds that cannot plan (pi, local, agy) and for instances of them.
|
|
4551
|
+
|
|
4521
4552
|
## Amendment: typed host ports for the remaining native branches (#625 phase 6, slice 2+)
|
|
4522
4553
|
|
|
4523
4554
|
Audited against `main` @ `bab87cb2` (2026-10-22). Every `file:line` below is at that commit. Line numbers in `src/hub/daemon.ts` move with each slice; a slice cites the enclosing function, not the line.
|
|
@@ -4977,3 +5008,36 @@ Use `summarizeByTask`, `costMetrics` and bounded SDLC GitHub helpers. Bound file
|
|
|
4977
5008
|
- At most 40 symbols and 40 untouched names are listed, with the count of the rest. Advisory only: ripwire does not report deleted symbols.
|
|
4978
5009
|
- A symbol button closes the sheet, sets the Memory view's `node` to the symbol's canonical id (`symbol:<name>@<path>`) and switches to the Memory tab. The daemon's memory view reads a node of up to 512 characters when it starts with `symbol:` (200 otherwise) so a receipt id is never truncated into another node. Memory entries attached to that symbol appear once phase 3 links them; until then the graph shows the symbol node alone.
|
|
4979
5010
|
- Colours are design tokens only, and the group wraps at phone width with 44 px targets.
|
|
5011
|
+
|
|
5012
|
+
|
|
5013
|
+
## Amendment: daemon responsiveness (#719)
|
|
5014
|
+
|
|
5015
|
+
Periodic roster and supervision reads use pending delivery metadata/rows rather than materializing terminal envelope history. Queue revisions are metadata reads; explicit queue/history and recovery snapshots retain their full semantics. Usage folding keeps its existing byte cap and atomic rows/offset transaction, with a 20 ms slice checked between whole records; one record remains indivisible. Native launch connects alone retry transient transport failures with bounded backoff up to 15 seconds and one busy notice. Ordinary connect defaults and identity/authentication/protocol refusals stay unchanged.
|
|
5016
|
+
|
|
5017
|
+
## Amendment: terminal Claude execution-root admission (#525-5)
|
|
5018
|
+
|
|
5019
|
+
Slice 525-5 is implemented. The temporary #735 blanket refusal is replaced by the existing implementer-role and host owner-isolation gate for every write class. The bounded launch-proof reader binds the current daemon instance and launch id; owner proof additionally needs a private, single-link launch record, a matching recorded execution root, the MCP server's real cwd and the validated noncanonical branch worktree. The proof belongs to the exact attached claim generation and socket; a pending preface is not ownership, and detach, replacement or a changed launch record revokes it. Old/missing root evidence attaches without isolation. Facts grants for declared implementers and terminal-recovery publication require the current proof. Canonical planner/reviewer behavior and protocol 16 remain unchanged. The launcher preserves canonical AGENTHUB_PROJECT_DIR for hub identity while passing the execution root as native cwd. These are same-user process/record attestations, not a sandbox.
|
|
5020
|
+
|
|
5021
|
+
## Amendment: planner walk and reviewer independence in `assign()` (#525-3)
|
|
5022
|
+
|
|
5023
|
+
Slice 525-3 is implemented, as the "Purity" bullet of the #525 amendment specifies; this records what exists and what does not yet.
|
|
5024
|
+
|
|
5025
|
+
- **Planner walk.** `plannerWalk` (`src/hub/routing.ts`) is a pure function of the sorted settled holders, the task id, an optional named planner, an optional kept planner and a per-holder `blocked` reason. A PII task has no planner (`planner: none (pii: planning stays with the person)`). A named planner is exact: a name that is not a holder is refused in the trace and never replaced by rotation, and a named holder that is paused or offline is still the choice, with the state shown. Otherwise a recorded planner is kept while it is still a holder. Otherwise rotation starts at `task.id mod n` over the holders sorted by id and walks forward past unavailable holders; the denominator is every holder, so availability never renumbers it (the #519 rule); when all are unavailable the seed holder is taken, `rotation (none available)`.
|
|
5026
|
+
- **Inputs and outputs.** `assign()` takes `planners`, `namedPlanner` and `keptPlanner` and returns `Assignment.planner` and `plannerReason` (`rotation`, `named`, `kept`, `none`). Without `planners` it walks no planner, so a caller that does not pass them is unchanged. A holder is unavailable when the adapter role ceiling excludes planning, it is off roster, not attached, offline, paused under `budget_paused = skip_peer`, or failing: the same state inputs the owner and reviewer walks read. The walk is independent of both: planner and owner, or planner and reviewer, may be the same peer.
|
|
5027
|
+
- **Explain parity.** The walk's lines (` planner candidate X: ...`, then `planner: X (reason)`) are part of `assign()`'s trace, after the owner and before the reviewer. `Tasks.weights()` supplies `planners` (the rostered holders of the settled role map, sorted) to every `assign()` path, so `ahub route explain` prints exactly what assignment ran.
|
|
5028
|
+
- **I-2.** A peer with an `accepted` or `done` history entry on the task never reviews it (`implementers`), whoever owns it now, a named reviewer and the declared reviewer pool included: refusal code `policy`, reason `implemented this task`. It is the last check in `blocked()`, so it only ever removes a candidate that was otherwise eligible: a former implementer that is offline, not attached, paused, failing or off roster is refused for that real reason and leaves the outcome as it was before I-2 (a task with no other reviewer still approves directly). When I-2 removes the last eligible candidate, the reviewer is the person and `reviewBlocked` is set (`every eligible reviewer implemented this task: the person reviews`); there is no fallback to an implementer. The person's own entries are not an implementation. A review-class and a PII task are unchanged.
|
|
5029
|
+
- **Not in this slice.** Nothing records the planner: no board column, no history entry, no notice, no authority check. `Tasks` passes `planners` and reads nothing back; 525-2 owns recording and the per-task authority. A task proposed today behaves exactly as before.
|
|
5030
|
+
|
|
5031
|
+
## Amendment: deliverable records bound to content hashes (#509a)
|
|
5032
|
+
|
|
5033
|
+
The only artifact identity was GitHub (`repo`, `issue`, `pr`, `head`, `reviewedHead`); a report, translation or deck had no record of which bytes were reviewed and approved. Slice 509a adds one, with no dependence on git.
|
|
5034
|
+
|
|
5035
|
+
- **Claims.** `hub_task_done` and `hub_sdlc_record` (in `receipt`) take `deliverables: [{path, format, version?}]`, one to sixteen distinct paths. `parseDeliverableClaims` (`src/hub/deliverables.ts`, pure) refuses every field the hub does not own: a claimed `sha256`, `hash` or `bytes` is a refusal with the reason, never an input. Paths are relative, forward-slashed, with no `.`, `..`, empty or control segments.
|
|
5036
|
+
- **Root.** Paths resolve under the owner's execution root, the same one the owner writes in: `TasksDeps.executionRoot(peer)` (the daemon passes `ownerWriteRoot`), falling back to the project directory only when the port is absent. A declared worktree instance whose root is not verified refuses hashing (`DeliverableRefusal`), and a live read reports every file `unknown`, so an approval is refused and a file is never shown `unchanged` from the wrong tree.
|
|
5037
|
+
- **Hashing.** `src/hub/deliverable-files.ts` is the only code that opens a deliverable. It resolves the path with `realPath` and `guardPath` (read mode), refuses the project's secrets denylist and the hub's own state (`.git`, `.agenthub`, by `isHubWritePath`), a non-regular file, a missing file and sizes over 256 MiB each or 512 MiB together, then opens without following a final link (`O_NOFOLLOW`) and compares device, inode, size and mtime with what was vetted (Linux reuses an inode number at once, so the inode alone does not prove identity) and the size and mtime again after the read, so a swapped or concurrently changing file is refused. Chunked reads with an await between chunks keep the daemon responsive. Any refusal refuses the whole call before a board write.
|
|
5038
|
+
- **Reads and gates.** A live read (`checkDeliverables`) applies the aggregate limit to the current sizes: files that grew past it are read `unknown` and none is hashed, so `hub_task_show` and an approval attempt stay bounded. `specStageGate` reads a receipt without its `deliverables` field, as `recordSdlc` records it, so naming deliverables never skips the live spec edit-time check in enforce mode.
|
|
5039
|
+
- **Record.** `HistoryEntry.deliverables` holds `{id, path, format, version?, sha256, bytes, private?}` on `done`, `done (checking)` (carried to the completing `done` by `latestPendingDeliverables`), `lifecycle` and `approved`, validated on write (`parseDeliverableRecords`, which also checks the id against the path and format). `id` is opaque and stable across edits.
|
|
5040
|
+
- **Approval.** `Tasks.review` re-hashes the delivered files before an approval. Unchanged, the approval carries the same records. Changed, missing or unknown, a reviewer's approval is refused pre-effect (`deliverable changed since it was delivered`); the person may approve the current bytes, which are measured and bound, with a note. The delivered records are rechecked after the awaited hash, so a redelivery during the verdict refuses it.
|
|
5041
|
+
- **Reads.** `Tasks.deliverableStatus` compares the files as they are now with the approved (else delivered) records: `unchanged`, `changed`, `missing` or `unknown`, and `changedSinceReview` true only for a measured difference. It is added to `task_show` for the console and peers. A file the hub cannot vouch for is `unknown`, never `unchanged`.
|
|
5042
|
+
- **Privacy.** A record is private for a PII task or a path under `pii.paths` (`matchesPolicy`). `publicDeliverables` is the one projection every peer view, review request and status uses: a private record, or a path matching a PII pattern, shows id, hash and size only. The board keeps the path (as it keeps a PII task's text) so the file can be found again.
|
|
5043
|
+
- **Not here.** `ahub deliverables` and the dashboard column (#509 AC3) are the next slice. `PROTOCOL` is unchanged: the new tool fields are optional. Known limit: tool input schemas are not enforced on the way in, and a daemon from before this slice reads only `summary` and `refs` from `hub_task_done`, so a newer plugin talking to an older daemon has its `deliverables` silently dropped and the task is recorded without them. The plugin is installed apart from the daemon (docs/agent-notes/daemon.md), so after an upgrade restart the hub before relying on deliverables; a floor like `role_stages` is the upgrade path if that ever matters.
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# 0.15.0 release verification
|
|
2
|
+
|
|
3
|
+
This record covers release preparation and source review. It claims no publication, installation, running-hub restart or live TUI launch.
|
|
4
|
+
|
|
5
|
+
## Candidate
|
|
6
|
+
|
|
7
|
+
Version 0.15.0, built from merged main at 12dd7b66. The person directed the release on 2026-10-23. It includes features, so the minor version is bumped (AGENTS.md, Releasing step 1).
|
|
8
|
+
|
|
9
|
+
- Daemon responsiveness (#719, #741): the hot paths read only pending delivery-journal state, and a launch connect retries within a bound with `hub busy, retrying`. On this machine a 0.14.0 daemon sat at about 100% CPU. That also made codex-review's 2 s isolation proof commands time out, and the hub's 2 s claude-mem saves.
|
|
10
|
+
- Structural config editing from the console and a dashboard settings session: validated, previewed, audited and restart-aware (#689, #734).
|
|
11
|
+
- Claude implementer instances:
|
|
12
|
+
- a terminal instance's execution root is verified before it owns write tasks (#525-5, #742);
|
|
13
|
+
- a headless implementer has per-task sessions and person approvals that fail closed (#525-4, #747).
|
|
14
|
+
- Always-ask action classes are enforced in the Claude PreToolUse hook and in ACP `request_permission`, with a session class budget (#636 slice 2, #743).
|
|
15
|
+
- Routing:
|
|
16
|
+
- the planner walk and I-2 reviewer independence in `assign()`, shown by `ahub route explain` (#525-3, #744);
|
|
17
|
+
- no write-class task for a person-started Claude instance before 525-5 (#735, #738).
|
|
18
|
+
- Review evidence:
|
|
19
|
+
- acceptance-criteria ids in the review request and on the verdict (#507, #745);
|
|
20
|
+
- deliverable records bound to content hashes (#509 AC1, AC2, AC4, #746).
|
|
21
|
+
- Kimi tokens counted from its session wire log (#285 phase 2, #740).
|
|
22
|
+
- A finding carried to a follow-up of the same PR or branch is not a recurrence (#736, #737).
|
|
23
|
+
- `ahub backlog list` prints a table (#399, #739).
|
|
24
|
+
- Still open:
|
|
25
|
+
- #636 slice 3 (#313, PR #750);
|
|
26
|
+
- #285 phase 4 (#315, PR #749);
|
|
27
|
+
- the memory sync log fix (#401, PR #748);
|
|
28
|
+
- agent-mem#13 P3 (#391, agent-mem PR #34) and P4;
|
|
29
|
+
- #525-2 and #525-6.
|
|
30
|
+
|
|
31
|
+
## Reviews
|
|
32
|
+
|
|
33
|
+
The planner reviewed every PR. Where a PR changed permissions, process ownership, privacy or task authority, an independent read-only reviewer also checked it. Every codex-connector thread was fixed or answered, and resolved, before merge. Each PR merged on green CI at its exact head. Where a rebase touched only CHANGELOG, the result was checked to keep the code identical to the approved head.
|
|
34
|
+
|
|
35
|
+
| PR | Final head | Review | CI |
|
|
36
|
+
| --- | --- | --- | --- |
|
|
37
|
+
| #734 (#689) | see PR | Structural config editor, audit and person-only paths | exact head, success |
|
|
38
|
+
| #737 (#736) | see PR | Recurrence unions work units by PR and branch | exact head, success |
|
|
39
|
+
| #738 (#735) | see PR | Temporary write-class refusal for person-started Claude instances | exact head, success |
|
|
40
|
+
| #740 (#285 p2) | see PR | Kimi wire-log reader and counter | exact head, success |
|
|
41
|
+
| #741 (#719) | see PR | Pending-only journal reads; bounded launch-connect retry | exact head, success |
|
|
42
|
+
| #742 (#525-5) | 1c84e9d7 | Two rounds. A verifier instance gets no canonical fallback; best-effort hello cwd; seed re-anchored. Follow-up #400 records the status-path revalidation cost | exact head, success |
|
|
43
|
+
| #743 (#636 s2) | 66658255 | Two rounds plus a rebase onto #742. The hook contract allows `ask`; the class budget is revoked when the owner stops; concurrent approvals cannot exceed N; enforcement is claimed only for a live hook | exact head, success |
|
|
44
|
+
| #744 (#525-3) | 2fa94797 | Two rounds. I-2 is the last check, so only an eligible former implementer is removed; dogfood row | exact head, success |
|
|
45
|
+
| #745 (#507) | 45b2ca8e | One round, no findings | exact head, success |
|
|
46
|
+
| #746 (#509) | 1410aa21 | Two rounds. The identity check covers size and mtime (Linux reuses inodes); the spec gate sees the stripped receipt; reads apply the aggregate limit; the owner's verified root | exact head, success |
|
|
47
|
+
| #747 (#525-4) | eefc3899 | Two rounds, with an independent reviewer. Admissible envelopes are not held by inadmissible ones; approval cuts are marked; the inbox stays per task session; a session starts only on a native frame; `role_stages` recovery floor | exact head, success |
|
|
48
|
+
| #739 (#399) | b3ffd61c | Person-reviewed (implemented by the planner); rebased over CHANGELOG only | exact head, success |
|
|
49
|
+
|
|
50
|
+
## Document review
|
|
51
|
+
|
|
52
|
+
Thirteen documents were stale against the 0.14.0 stamps (d21a9ccc, and 88caef80 for benchmarks.md). Read-only reviewers in four groups checked each one against `git log <stamp>..HEAD` over its paths and the twelve PRs. They corrected every statement a merged change had made wrong.
|
|
53
|
+
|
|
54
|
+
| Document | Result | Checked claims and correction |
|
|
55
|
+
| --- | --- | --- |
|
|
56
|
+
| `README.md` | corrected | Status 0.15.0 and the verification link. Task board: reviewer independence, AC ids, hash-bound deliverables, terminal and headless Claude implementers. Always-ask in the guard rails. Structural config editing. |
|
|
57
|
+
| `docs/quickstart.md` | corrected | Install pin `v0.15.0`. A new "Upgrading to 0.15.0" section: always-ask prompts and budgets, which peers are not enforced, relaunching terminal Claude implementers, declaring a headless implementer, deliverables, AC ids, `ahub settings edit`, the busy-retry message, and restarting the hub and codex-review. The 0.14.0 section is kept below it. |
|
|
58
|
+
| `docs/security.md` | corrected | What always-ask enforces and its limits. Classed calls are excluded from hub-tool auto-approval and `--unattended`. Structural `instances` editing. Terminal execution-root proof. The headless approval path (fails closed, allow-once only, `[withheld]` before `[cut, N chars]`). Deliverable hashing. Kimi wire-log counts only. |
|
|
59
|
+
| `docs/operations.md` | corrected | Kimi usage rows are `native`. Jcode is not enforced. The headless implementer hook asks. The startup ceiling is still open. `ahub settings edit` for never-editable keys. The console `c` and `R` keys and the dashboard Structure group. The deliverable refusal text. The backlog list owner count. The 525-3/4/5 slices are shipped; 525-2 and the plan-author rule are still planned. |
|
|
60
|
+
| `src/cli/help.ts` | corrected | Every command, subcommand and flag compared with main.ts, launch.ts, settings-edit.ts and the native and configured-ACP entries. Added `backlog list --color`; corrected the `ui --settings` and `route explain` descriptions. |
|
|
61
|
+
| `docs/agent-notes/adapters.md` | corrected | Fixed-builtin-only fields include `identity.currentChild`, `headlessVariant` and the implementer port. `definitionOf` picks the headless variant. `OwnedPrintChild` is the only print-child spawn path. A headless implementer section. Scope gains `action-enforce.ts` and `permission-payload.ts`. |
|
|
62
|
+
| `docs/agent-notes/daemon.md` | corrected | The writer declaration rule replaces "refused until #525-4". `peer_stop` covers print reviewers and the implementer. The `role_stages` floor. Facts for the implementer child and worktree instances. Reads go through `readClaudeLaunchProof`. Execution-root proof. Tools-socket admission. `retryLaunchConnect` limits. Scope gains the config-edit modules and `claude-launch-proof.ts`. |
|
|
63
|
+
| `docs/agent-notes/bus.md` | corrected | Hot paths read only pending journal state (#741). |
|
|
64
|
+
| `docs/agent-notes/budget.md` | corrected | Headless variants share the base kind's account; the roll-up's 20 ms slice. Scope gains the Kimi count files. |
|
|
65
|
+
| `docs/agent-notes/benchmarks.md` | no change | The driver passes no `actionGate`, so ACP benchmark behavior is unchanged. |
|
|
66
|
+
| `docs/agent-notes/tasks.md` | corrected | The #738 temporary refusal is removed. Declared-extra admission covers every implementer-owned class. I-2 reaches the person only when it removed every eligible reviewer. New rules for `unmetCriteria`, owned-child authority rechecks and deliverables. Scope gains `workflow.ts`, `deliverables.ts`, `deliverable-files.ts` and four listed files. |
|
|
67
|
+
| `docs/agent-notes/tests.md` | corrected | The hub-home preload replaces `KIMI_CODE_HOME`. Conformance enrolls `:implementer` variants. Headless implementer tests use the fake with a temporary HOME and never start the real `claude`. |
|
|
68
|
+
| `docs/agent-notes/README.md` | corrected | Background only: why I-2 is the last reviewer check. No instructions. |
|
|
69
|
+
|
|
70
|
+
The AGENTS.md area lists and the `docs/verified.json` paths gain the release's new files: `action-enforce.ts`, `permission-payload.ts`, `config-tier.ts`, `config-edit.ts`, `config-edit-host.ts`, `claude-launch-proof.ts`, `kimi-wire-usage.ts`, `kimi-usage.ts`, `token-window.ts`, `workflow.ts`, `deliverables.ts` and `deliverable-files.ts`.
|
|
71
|
+
|
|
72
|
+
## Package contents
|
|
73
|
+
|
|
74
|
+
#746 committed a mutation-test backup, `src/hub/deliverable-files.ts.bak`, with the aggregate size limit disabled. The release branch removes it so it does not ship under `src/`.
|
|
75
|
+
|
|
76
|
+
## Known gaps, not blocking
|
|
77
|
+
|
|
78
|
+
- `ahub status` reports always-ask on a headless Claude implementer as "adapter integration pending", although its hook and approvals enforce the classes. It under-reports and never over-claims. Follow-up task.
|
|
79
|
+
- `ahub projects` and `queue list` accept `--full` without effect.
|
|
80
|
+
- The live legs are a person's: a real Claude Code `ask` prompt (#743), a real-account headless implementer turn (#747) and a multi-instance CPU check (#742).
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# Daemon responsiveness, 2026-10-23
|
|
2
|
+
|
|
3
|
+
## Read-only live evidence
|
|
4
|
+
|
|
5
|
+
The running released 0.14.0 daemon was sampled for five seconds without restart, mutation or signalling unrelated processes. Of 3,898 main-thread samples, 2,860 were kernel waits. SQLite appeared in 504 samples, including 303 sorter/merge samples; guarded pwrite appeared in 240 leaf samples. These native stacks lack JavaScript symbol attribution. The initial process listing showed lifetime-average CPU 83.9% and RSS about 1.4 GB, while the sample reported a smaller current physical footprint; those are different measurements, not evidence of a sustained current 83.9% load or a GC cause.
|
|
6
|
+
|
|
7
|
+
Bounded read-only queries found 2,051 delivery rows (only three accepted), with about 8.7 MB of originals/out JSON. `list()` and `snapshot()` sorted full payload rows through a temporary B-tree. The released one-second supervision path called `queueList()` (list plus snapshot for revision) and `knownPeers()` (another full list). Held-row/status and superseded-delivery paths added further whole-history reads. A capped read-only SQL probe measured 16.49 ms for the sorted full read versus 5.56 ms unsorted, excluding JSON parsing.
|
|
8
|
+
|
|
9
|
+
The board had 398 tasks, seven active/non-backlog tasks and at most 28 history entries per task; planner-WIP probes were below 0.2 ms. Usage tables were small (39 native-rollup and 256 token-rollup rows), and the persisted log offset was only 472 bytes behind the 51.1 MB events file. These observations make those queries weaker explanations for the sampled sustained sorter activity. They do not rule out a cold-start fold stall.
|
|
10
|
+
|
|
11
|
+
## Candidate and synthetic comparison
|
|
12
|
+
|
|
13
|
+
The candidate uses pending-state metadata/rows on periodic roster, supervision and held-delivery paths, with a pending-state index. Queue revision is read as metadata; integrity calculations that need queues omit the journal snapshot. Explicit queue/history and recovery snapshots retain terminal history. Usage passes retain their byte cap and atomic rows/offset transaction and stop at a 20 ms boundary between whole records. One record and the existing corrupt-line skip remain indivisible. Launch-only connections retry transport timeouts/unclean closes up to 15 seconds with one busy notice; ordinary three-second connect defaults and terminal authentication/protocol/identity refusals remain.
|
|
14
|
+
|
|
15
|
+
A fresh synthetic journal contained 2,048 terminal and three pending rows with 2 KiB envelope bodies. Ten measured iterations followed two warm-ups, using the same data and process:
|
|
16
|
+
|
|
17
|
+
| Query bundle | Median ms | Max ms |
|
|
18
|
+
| --- | ---: | ---: |
|
|
19
|
+
| Former roster/list/revision-snapshot reads | 67.413 | 69.536 |
|
|
20
|
+
| Pending metadata/rows and direct revision | 0.125 | 0.135 |
|
|
21
|
+
|
|
22
|
+
This is an isolated query-bundle comparison, not a claim about installed daemon CPU, RSS, total request latency or an improvement factor for the whole application. No live database was copied into the fixture.
|
|
23
|
+
|
|
24
|
+
## Regression evidence
|
|
25
|
+
|
|
26
|
+
- Reintroducing full-history roster reads or recovery-snapshot revision reads fails a named no-throw assertion against a journal that refuses those hot-path calls. Explicit history still returns its 513 fixture rows.
|
|
27
|
+
- Removing the fold time boundary fails the named byte-offset assertion for a zero-budget slice. Complete Unicode record boundaries and rebuild parity remain checked.
|
|
28
|
+
- A real daemon with a cold log larger than 50 MiB starts a launch socket inside its actual catch-up pass and answers the authenticated status request. This end-to-end check is separate from the deterministic slice regression; it does not claim an old implementation always exceeded three seconds.
|
|
29
|
+
- A fake-clock test exhausts the launch budget at exactly 15 seconds, checks backoff and a single busy notice, and proves immediate unreachable-listener, authentication, wire, instance and unclassified refusals are not retried.
|
|
30
|
+
- Focused five-file verification passed 45 tests and 253 expectations on pinned Bun 1.4.2 after the fixture-size correction. The initial fixture-size assertion was retained; its data was increased above 50 MiB.
|
|
31
|
+
|
|
32
|
+
Installed-runtime CPU/RSS and account-backed native launches remain unverified for this candidate. The existing live daemon was left running unchanged.
|
|
33
|
+
|
|
34
|
+
The first complete changed gate passed 3,366 tests but exposed one real regression: retrying immediate connection refusal made three failed-launch ownership checks exceed their unchanged 20-second test deadline. The code now treats an unreachable listener as terminal and retries the busy timeout/unclean-close classes only. The original recovery test and timeout are unchanged.
|
|
35
|
+
|
|
36
|
+
After that fix, the native six-file focused run passed 63 tests/392 expectations using the gate's normal isolated identity/color/Git environment, including the unchanged three-failed-launch ownership test. A prior direct invocation retained agent markers and got two fixture-init refusals; those tests and product authority checks were not changed. The corrected invocation uses exactly the environment clearing already present in `scripts/check.sh`.
|
|
37
|
+
|
|
38
|
+
## Native reviewer and final gate
|
|
39
|
+
|
|
40
|
+
On this macOS machine, the candidate daemon served a synthetic 56,500,109-byte event log and 2,048 terminal journal rows. Its actual authenticated console `start codex-review` path admitted an explicitly declared fresh reviewer: state `idle`, observed CLI 0.146.0, start 469.61 ms. A fresh production preparation using that isolated daemon's same context completed in 397.64 ms and returned 14 evidence entries with `readOnly`, `strictMcp`, `ephemeral` and `current` true. The production 2-second per-command and 12-second total proof budgets were unchanged.
|
|
41
|
+
|
|
42
|
+
The probe used an empty temporary HOME/CODEX_HOME and no credentials, login or model execution. It did not replace the installed daemon or demonstrate an account-backed model review. Initial probe-only setup mistakes (attempting to instrument the frozen backend object, then omitting the required fresh-instance declaration) were corrected without changing product code. All owned fixture processes and temporary homes were cleaned up.
|
|
43
|
+
|
|
44
|
+
Final native pinned-Bun gate on runtime `b0a2d4b1293fe39c6e4ac89b1a658fc35dba0247`: `scripts/check.sh --changed` ended `check: OK (changed)`, 3,368 pass, 0 fail, 166,362 expectations across 259 files in 747.15 seconds; no current-invocation daemon leaks. Typecheck, committed-bundle freshness and tarball checks passed. Remote Linux verification could not start because its SSH route was unreachable, so this receipt uses the permitted native fallback; no Linux pass is claimed for this candidate.
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# Headless Claude permission transport receipt
|
|
2
|
+
|
|
3
|
+
Date: 2026-10-23. Scope: #525 R5a, slice 525-4. Native binary: Claude Code 2.1.309, 275,923,296 bytes, SHA-256 `5eadc0009cdcdbc0d06e58110d7b2baf88ced6088b1c33a60a21217fe410619c`.
|
|
4
|
+
|
|
5
|
+
## Method
|
|
6
|
+
|
|
7
|
+
The installed native binary ran with an isolated HOME and CLAUDE_CONFIG_DIR, a disposable work directory, one fixture stdio MCP server, an empty settings-source selection and managed fixture settings. No personal authentication files or live sessions were used. A deterministic loopback HTTP server supplied a synthetic model-protocol response requesting one Write, then a completion response after a tool result. This exercised the real native permission dispatch without a provider, model inference, login or real credential. Synthetic provider usage in this fixture is not measured account usage.
|
|
8
|
+
|
|
9
|
+
The launch used this form, with fixture paths and a fixture permission tool:
|
|
10
|
+
|
|
11
|
+
```sh
|
|
12
|
+
claude -p --output-format stream-json --verbose --strict-mcp-config \
|
|
13
|
+
--mcp-config <fixture-mcp.json> --setting-sources '' \
|
|
14
|
+
--settings <fixture-settings.json> --permission-mode default \
|
|
15
|
+
--permission-prompts host --permission-prompt-tool mcp__fixture__approve \
|
|
16
|
+
--model claude-sonnet-4-5 <fixture-prompt>
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
No `--bare`, `acceptEdits`, `dontAsk` or `bypassPermissions` was used. Native and fixture children belonged to an owned process group, which was stopped and reaped after every case. The temporary probe driver's SHA-256 was `173c108ff5e0289434c7794e985a48b612c23df81e10d0fc2abe48a297de9ae5`. The recorded receipt and driver hashes agreed when this document was prepared. The driver is a local diagnostic, not a shipped runtime dependency or a startup receipt gate.
|
|
20
|
+
|
|
21
|
+
## Observations
|
|
22
|
+
|
|
23
|
+
| Fixture case | Native result |
|
|
24
|
+
| --- | --- |
|
|
25
|
+
| Prompt tool allows the Write | One MCP permission call; target file written |
|
|
26
|
+
| Prompt tool denies | No write; one permission denial |
|
|
27
|
+
| Prompt tool missing from MCP inventory | No write; native exit 1 |
|
|
28
|
+
| PreToolUse command exits 1, prompt tool denies | Hook decides nothing; one MCP permission call; no write |
|
|
29
|
+
| PreToolUse command exits 1, prompt tool allows | Hook decides nothing; one MCP permission call; file written |
|
|
30
|
+
| MCP permission request returns a JSON-RPC error | No write; native tool-result error |
|
|
31
|
+
| MCP server disconnects during permission request | No write; native tool-result error |
|
|
32
|
+
| MCP permission reply remains pending | No write observed before the external 25-second owned-group stop; native internal timeout not established |
|
|
33
|
+
| Simulated approval deadline returns deny after 100 ms | One MCP permission call; no write; native exit 0; observed elapsed 844 ms |
|
|
34
|
+
|
|
35
|
+
The last row simulates the hub's deny response. It does not measure the real hub approval scheduler or a person's console interaction. Separate adapter fixtures cover allow, deny, externally bounded timeout, tool error and disconnect; those fixtures do not constitute native-client evidence by themselves.
|
|
36
|
+
|
|
37
|
+
The native prompt request contained `tool_name: "Write"`, the original `input` object and `tool_use_id`. The fixture allow response was an MCP text content item containing JSON with `behavior: "allow"` and `updatedInput`; the deny response used `behavior: "deny"` and `message: "no person answered"`. Fixture paths and text are omitted here.
|
|
38
|
+
|
|
39
|
+
## Host behavior and ceilings
|
|
40
|
+
|
|
41
|
+
The production permission tool is `mcp__agent-hub__hub_permission_request`. Its current-child launch and generation fence, privacy screening, person-only approval and timeout denial remain host responsibilities. A failed facts hook supplies no decision: a subsequent valid person allow is permitted. A failed permission prompt, timeout, disconnect or mismatched child authority never supplies an automatic allow.
|
|
42
|
+
|
|
43
|
+
The native probe certifies the permission transport on this binary and version. It does not certify real provider authentication, a real model's tool selection, a person's approval interaction, every native tool type, native internal permission timeout, or filesystem sandbox isolation. The pending fixture was bounded externally. No model turn using a real account was run. Native version admission and binary fencing remain runtime checks; this dated receipt is evidence for the supported contract, not a per-start runtime receipt check.
|
|
44
|
+
|
|
45
|
+
The exact-head package gate, daemon integration and both-OS CI are recorded separately in the PR handoff. This document claims no gate or CI result for the current candidate.
|
|
46
|
+
|
|
47
|
+
The MCP wire does not authenticate whether a schema-valid permission call came from native permission dispatch or was selected directly by the model. `tool_use_id` is a shape check, not such a certificate. Either path still requires a fresh person allow-once for its original arguments; it changes no permission default and creates no reusable grant. A model-selected call can prompt the person but cannot turn its returned text into authority for a later native call. Strong dispatch-origin provenance would need a separately proven native protocol, rather than treating a caller-supplied id as evidence.
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# Terminal Claude execution-root receipt
|
|
2
|
+
|
|
3
|
+
Date: 2026-10-23. Native version: Claude Code 2.1.309. Scope: #525 R5b, slice 525-5.
|
|
4
|
+
|
|
5
|
+
## Native cwd evidence
|
|
6
|
+
|
|
7
|
+
An isolated HOME and CLAUDE_CONFIG_DIR, empty of authentication, loaded one fixture stdio MCP server. The native session ran from a separate fixture cwd with:
|
|
8
|
+
|
|
9
|
+
```sh
|
|
10
|
+
claude --bare --print --input-format stream-json --output-format stream-json --verbose --strict-mcp-config --mcp-config <fixture.json> --no-session-persistence --tools ''
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
The driver sent exactly one `control_request` with `request.subtype: initialize` and no user messages. The native control response was success. The fixture observed MCP initialize and tools/list. The MCP process's canonical cwd matched the native session cwd. Stderr was empty. The owned native session group was terminated and reaped afterwards; no fixture MCP process remained. No model request, login, real credential HOME or person's live session was used.
|
|
14
|
+
|
|
15
|
+
A separate `claude mcp list` health check from two different fixture directories also started the server in each caller's canonical cwd. The actual session initialization, rather than that health check alone, is the basis for hello cwd.
|
|
16
|
+
|
|
17
|
+
## Host admission and limits
|
|
18
|
+
|
|
19
|
+
The launcher and daemon independently use the existing managed-worktree resolver. A matching launch id, private record executionCwd, native hello cwd and validated noncanonical worktree are all required. The proof is tied to the attached socket and claim generation. Missing or mismatched root stays unisolated; explicit routing refuses a write owner. A launch replacement or detach invalidates proof. Facts use the verified root, and recovery revalidates it against the declaration.
|
|
20
|
+
|
|
21
|
+
The native observation covers this installed version's initialize-only session. It does not certify a real implementation turn, native --worktree behavior, a user hook that changes cwd, other native versions or kernel write isolation. The daemon rejects differing reported cwd regardless of those reasons. A real account/model turn remains the manual smoke leg.
|
|
22
|
+
|
|
23
|
+
Runtime proof revalidates the worktree before owner reads/effects, sharing evidence only within synchronous code in one event-loop turn. This uses the existing resolver's aggregate 5-second Git budget per peer (up to four Git subprocesses). No terminal Claude implementer is declared in this repository, so this receipt makes no live multi-instance CPU claim. The existing resolver's ponytail applies: an asynchronous validation/admission boundary or correctly invalidated semantic inventory cache is the upgrade if that cost becomes material.
|
|
24
|
+
|
|
25
|
+
## Verification
|
|
26
|
+
|
|
27
|
+
Candidate checks are recorded in the PR and task handoff at the exact head. Focused tests cover positive ownership/facts, absent and mismatched evidence, replacement/detach, private-record and size fences, native launch cwd versus canonical hub root, and terminal recovery root/identity drift.
|
|
28
|
+
|
|
29
|
+
Native candidate validation with pinned Bun 1.4.2: `scripts/check.sh --changed` passed 3,618 tests across 285 files, 194,424 assertions, 0 failures (753.24 seconds). The gate ended `check: no current-invocation agent-hub daemon leaks` and `check: OK (changed)`. Bundle freshness and npm package contents passed. The new mismatch test fails on a named assertion when the cwd comparison is removed, then passes with the source restored. CI on both OSes remains a separate exact-head review gate; no CI pass is claimed here.
|
|
30
|
+
|
|
31
|
+
## R1 follow-up
|
|
32
|
+
|
|
33
|
+
The review found that verifier-only declarations bypassed the implementer-only facts guard. Every declared worktree now requires current owner-root proof before facts permission or tree observations; absent/revoked proof returns no grant and no canonical-tree fallback. The regression establishes a real hook generation, changes permission through the console, then checks revoked and missing roots under both ask-when-needed and never-ask. It fails against the former facts guard.
|
|
34
|
+
|
|
35
|
+
The channel resolves its cwd best-effort on each connection. A deleted native cwd omits root evidence while preserving hub messaging; an actual removed-directory reconnect regression fails against the former unguarded lookup and passes with the fix. This never upgrades missing evidence into owner isolation.
|
|
36
|
+
|
|
37
|
+
The readonly-glob seed now targets the verified-root expression and still removes only readonly policy enforcement. Shard 14/64 passed all seven sequential green-to-named-assertion detections, including that seed.
|
|
38
|
+
|
|
39
|
+
The original macOS CI failure at 9dc3cf03 was `hdiutil create` returning 1 before the HFS+ sandbox body ran, rather than an accepted forbidden write. This PR changes no sandbox/deny implementation or HFS+ test. The unchanged named HFS+ test passed three consecutive native runs (307 assertions each) on the R1 candidate. This does not establish the new head's GitHub macOS result; both-OS exact-head CI remains required.
|
|
40
|
+
|
|
41
|
+
R1 local gate with pinned Bun 1.4.2: `scripts/check.sh --changed` passed 3,634 tests across 286 selected files, 194,501 assertions, 0 failures (762.35 seconds), no current-invocation daemon leaks, `check: OK (changed)`. The watchdog used the hosted macOS 1,260-second setting; per-test timeout stayed 20 seconds. This was the changed gate, not a 506-file full-suite claim. New-head CI remains unobserved until the reviewer reads its results.
|
package/docs/verified.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"schemaVersion": 1,
|
|
3
3
|
"documents": {
|
|
4
4
|
"README.md": {
|
|
5
|
-
"verifiedAgainst": "
|
|
5
|
+
"verifiedAgainst": "ea32305fafd9bdac6b5e6f9d9048006f3c1ba060",
|
|
6
6
|
"paths": [
|
|
7
7
|
"package.json",
|
|
8
8
|
"src/",
|
|
@@ -11,14 +11,14 @@
|
|
|
11
11
|
]
|
|
12
12
|
},
|
|
13
13
|
"docs/security.md": {
|
|
14
|
-
"verifiedAgainst": "
|
|
14
|
+
"verifiedAgainst": "ea32305fafd9bdac6b5e6f9d9048006f3c1ba060",
|
|
15
15
|
"paths": [
|
|
16
16
|
"src/",
|
|
17
17
|
"templates/"
|
|
18
18
|
]
|
|
19
19
|
},
|
|
20
20
|
"docs/operations.md": {
|
|
21
|
-
"verifiedAgainst": "
|
|
21
|
+
"verifiedAgainst": "ea32305fafd9bdac6b5e6f9d9048006f3c1ba060",
|
|
22
22
|
"paths": [
|
|
23
23
|
"package.json",
|
|
24
24
|
"src/",
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
]
|
|
36
36
|
},
|
|
37
37
|
"docs/quickstart.md": {
|
|
38
|
-
"verifiedAgainst": "
|
|
38
|
+
"verifiedAgainst": "ea32305fafd9bdac6b5e6f9d9048006f3c1ba060",
|
|
39
39
|
"paths": [
|
|
40
40
|
"package.json",
|
|
41
41
|
"src/",
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
]
|
|
44
44
|
},
|
|
45
45
|
"docs/agent-notes/adapters.md": {
|
|
46
|
-
"verifiedAgainst": "
|
|
46
|
+
"verifiedAgainst": "ea32305fafd9bdac6b5e6f9d9048006f3c1ba060",
|
|
47
47
|
"paths": [
|
|
48
48
|
"src/adapters/",
|
|
49
49
|
"src/pi/",
|
|
@@ -69,11 +69,13 @@
|
|
|
69
69
|
"src/cli/configured-acp-entry.ts",
|
|
70
70
|
"src/cli/preview.ts",
|
|
71
71
|
"src/hub/roster.ts",
|
|
72
|
-
"src/hub/instances.ts"
|
|
72
|
+
"src/hub/instances.ts",
|
|
73
|
+
"src/hub/action-enforce.ts",
|
|
74
|
+
"src/hub/permission-payload.ts"
|
|
73
75
|
]
|
|
74
76
|
},
|
|
75
77
|
"docs/agent-notes/benchmarks.md": {
|
|
76
|
-
"verifiedAgainst": "
|
|
78
|
+
"verifiedAgainst": "ea32305fafd9bdac6b5e6f9d9048006f3c1ba060",
|
|
77
79
|
"paths": [
|
|
78
80
|
"scripts/benchmarks/",
|
|
79
81
|
"test/benchmarks/",
|
|
@@ -85,7 +87,7 @@
|
|
|
85
87
|
]
|
|
86
88
|
},
|
|
87
89
|
"docs/agent-notes/budget.md": {
|
|
88
|
-
"verifiedAgainst": "
|
|
90
|
+
"verifiedAgainst": "ea32305fafd9bdac6b5e6f9d9048006f3c1ba060",
|
|
89
91
|
"paths": [
|
|
90
92
|
"src/hub/budget.ts",
|
|
91
93
|
"src/cli/statusline-tee.ts",
|
|
@@ -100,11 +102,14 @@
|
|
|
100
102
|
"src/hub/instance-budget.ts",
|
|
101
103
|
"src/hub/claude-state.ts",
|
|
102
104
|
"src/adapters/definitions/native-channel-state.ts",
|
|
103
|
-
"src/hub/usage-rollup.ts"
|
|
105
|
+
"src/hub/usage-rollup.ts",
|
|
106
|
+
"src/adapters/kimi-wire-usage.ts",
|
|
107
|
+
"src/hub/kimi-usage.ts",
|
|
108
|
+
"src/hub/token-window.ts"
|
|
104
109
|
]
|
|
105
110
|
},
|
|
106
111
|
"docs/agent-notes/bus.md": {
|
|
107
|
-
"verifiedAgainst": "
|
|
112
|
+
"verifiedAgainst": "ea32305fafd9bdac6b5e6f9d9048006f3c1ba060",
|
|
108
113
|
"paths": [
|
|
109
114
|
"src/hub/bus.ts",
|
|
110
115
|
"src/hub/envelope.ts",
|
|
@@ -119,7 +124,7 @@
|
|
|
119
124
|
]
|
|
120
125
|
},
|
|
121
126
|
"docs/agent-notes/daemon.md": {
|
|
122
|
-
"verifiedAgainst": "
|
|
127
|
+
"verifiedAgainst": "ea32305fafd9bdac6b5e6f9d9048006f3c1ba060",
|
|
123
128
|
"paths": [
|
|
124
129
|
"src/hub/daemon.ts",
|
|
125
130
|
"src/hub/control-client.ts",
|
|
@@ -178,7 +183,11 @@
|
|
|
178
183
|
"src/cli/memory.ts",
|
|
179
184
|
"src/adapters/definitions/native-channel-state.ts",
|
|
180
185
|
"src/hub/task-code-group.ts",
|
|
181
|
-
"src/cli/status-lines.ts"
|
|
186
|
+
"src/cli/status-lines.ts",
|
|
187
|
+
"src/hub/config-tier.ts",
|
|
188
|
+
"src/hub/config-edit.ts",
|
|
189
|
+
"src/hub/config-edit-host.ts",
|
|
190
|
+
"src/hub/claude-launch-proof.ts"
|
|
182
191
|
]
|
|
183
192
|
},
|
|
184
193
|
"docs/agent-notes/local-worker.md": {
|
|
@@ -202,7 +211,7 @@
|
|
|
202
211
|
]
|
|
203
212
|
},
|
|
204
213
|
"docs/agent-notes/tasks.md": {
|
|
205
|
-
"verifiedAgainst": "
|
|
214
|
+
"verifiedAgainst": "ea32305fafd9bdac6b5e6f9d9048006f3c1ba060",
|
|
206
215
|
"paths": [
|
|
207
216
|
"src/hub/tasks.ts",
|
|
208
217
|
"src/hub/board.ts",
|
|
@@ -231,11 +240,14 @@
|
|
|
231
240
|
"src/hub/review-findings.ts",
|
|
232
241
|
"src/hub/plan-conformance.ts",
|
|
233
242
|
"src/hub/sdlc-metrics.ts",
|
|
234
|
-
"src/hub/spec-read.ts"
|
|
243
|
+
"src/hub/spec-read.ts",
|
|
244
|
+
"src/hub/workflow.ts",
|
|
245
|
+
"src/hub/deliverables.ts",
|
|
246
|
+
"src/hub/deliverable-files.ts"
|
|
235
247
|
]
|
|
236
248
|
},
|
|
237
249
|
"docs/agent-notes/tests.md": {
|
|
238
|
-
"verifiedAgainst": "
|
|
250
|
+
"verifiedAgainst": "ea32305fafd9bdac6b5e6f9d9048006f3c1ba060",
|
|
239
251
|
"paths": [
|
|
240
252
|
"test/",
|
|
241
253
|
"scripts/check.sh",
|
|
@@ -254,7 +266,7 @@
|
|
|
254
266
|
]
|
|
255
267
|
},
|
|
256
268
|
"docs/agent-notes/README.md": {
|
|
257
|
-
"verifiedAgainst": "
|
|
269
|
+
"verifiedAgainst": "ea32305fafd9bdac6b5e6f9d9048006f3c1ba060",
|
|
258
270
|
"paths": [
|
|
259
271
|
"src/cli/console-state.ts",
|
|
260
272
|
"src/cli/attention.ts",
|
|
@@ -263,7 +275,7 @@
|
|
|
263
275
|
]
|
|
264
276
|
},
|
|
265
277
|
"src/cli/help.ts": {
|
|
266
|
-
"verifiedAgainst": "
|
|
278
|
+
"verifiedAgainst": "ea32305fafd9bdac6b5e6f9d9048006f3c1ba060",
|
|
267
279
|
"paths": [
|
|
268
280
|
"src/cli/main.ts",
|
|
269
281
|
"src/cli/launch.ts",
|
package/package.json
CHANGED