@staix/agent-hub 0.12.45 → 0.13.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.
Files changed (99) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/README.md +83 -116
  3. package/docs/agent-notes/README.md +6 -0
  4. package/docs/agent-notes/adapters.md +10 -7
  5. package/docs/agent-notes/budget.md +6 -1
  6. package/docs/agent-notes/bus.md +6 -4
  7. package/docs/agent-notes/daemon.md +6 -1
  8. package/docs/agent-notes/local-worker.md +2 -1
  9. package/docs/agent-notes/tasks.md +10 -0
  10. package/docs/agent-notes/tests.md +4 -2
  11. package/docs/dogfood.md +92 -0
  12. package/docs/events.md +14 -1
  13. package/docs/operations.md +250 -19
  14. package/docs/profiles.md +2 -2
  15. package/docs/quickstart.md +8 -2
  16. package/docs/sdlc.md +36 -6
  17. package/docs/security.md +20 -11
  18. package/docs/smoke.md +9 -4
  19. package/docs/specs/2026-09-19-agent-hub-design.md +759 -8
  20. package/docs/verification/2026-10-19-reviewer-isolation.md +2 -0
  21. package/docs/verification/2026-10-22-code-facts.md +78 -0
  22. package/docs/verification/2026-10-22-codex-reviewer-isolation.md +47 -0
  23. package/docs/verification/2026-10-22-kimi-qwen-compat.md +79 -0
  24. package/docs/verification/2026-10-23-0.13.0.md +89 -0
  25. package/docs/verification/dogfood/2026-10-22.md +3109 -0
  26. package/docs/verified.json +14 -14
  27. package/package.json +1 -1
  28. package/plugins/agent-hub/.claude-plugin/plugin.json +1 -1
  29. package/plugins/agent-hub/server.js +613 -329
  30. package/src/adapters/agy/entry.ts +5 -4
  31. package/src/adapters/claude-channel.ts +20 -9
  32. package/src/adapters/codex-appserver.ts +18 -2
  33. package/src/adapters/codex-review-isolation.ts +12 -5
  34. package/src/adapters/compat.ts +140 -0
  35. package/src/adapters/definitions/builtin-metadata.ts +2 -1
  36. package/src/adapters/definitions/native-cli-doctor.ts +12 -5
  37. package/src/adapters/definitions/native-cli-entry-jcode.ts +9 -6
  38. package/src/adapters/definitions/native-cli-jcode-mcp.ts +9 -2
  39. package/src/adapters/definitions/native-cli-preview-common.ts +2 -0
  40. package/src/adapters/definitions/native-cli-preview-jcode.ts +8 -2
  41. package/src/adapters/definitions/native-cli-preview-qwen.ts +2 -1
  42. package/src/adapters/definitions/qwen-native.ts +7 -3
  43. package/src/adapters/definitions/qwen.ts +2 -1
  44. package/src/adapters/jcode.ts +72 -31
  45. package/src/adapters/kimi-review.ts +6 -3
  46. package/src/adapters/registry-types.ts +3 -1
  47. package/src/adapters/registry.ts +1 -0
  48. package/src/cli/agents.ts +40 -0
  49. package/src/cli/console-review.ts +54 -0
  50. package/src/cli/console-state.ts +124 -29
  51. package/src/cli/console-symbols.ts +74 -0
  52. package/src/cli/console-usage.ts +89 -0
  53. package/src/cli/console.ts +26 -1
  54. package/src/cli/help.ts +16 -6
  55. package/src/cli/identity.ts +29 -6
  56. package/src/cli/init.ts +109 -11
  57. package/src/cli/main.ts +122 -11
  58. package/src/cli/output.ts +44 -1
  59. package/src/cli/preview.ts +1 -1
  60. package/src/cli/sdlc-release-guard.ts +82 -0
  61. package/src/hub/action-class.ts +362 -0
  62. package/src/hub/action-policy.ts +106 -0
  63. package/src/hub/board.ts +43 -8
  64. package/src/hub/budget.ts +71 -2
  65. package/src/hub/bus.ts +43 -3
  66. package/src/hub/checks.ts +80 -31
  67. package/src/hub/code-facts.ts +223 -0
  68. package/src/hub/config-apply.ts +10 -1
  69. package/src/hub/config-trust.ts +7 -4
  70. package/src/hub/daemon.ts +237 -22
  71. package/src/hub/dogfood-read.ts +199 -0
  72. package/src/hub/dogfood.ts +163 -0
  73. package/src/hub/envelope.ts +1 -1
  74. package/src/hub/events.ts +11 -2
  75. package/src/hub/hub-tools.ts +24 -2
  76. package/src/hub/inbox-polling.ts +25 -0
  77. package/src/hub/instances.ts +73 -1
  78. package/src/hub/profiles.ts +7 -2
  79. package/src/hub/release-worktree.ts +56 -0
  80. package/src/hub/review-brief.ts +36 -0
  81. package/src/hub/sdlc-queue.ts +31 -9
  82. package/src/hub/sdlc-release-authorization.ts +173 -0
  83. package/src/hub/sdlc.ts +49 -11
  84. package/src/hub/settings.ts +5 -2
  85. package/src/hub/snapshots.ts +93 -8
  86. package/src/hub/symbol-normalizer.ts +26 -0
  87. package/src/hub/task-code-symbols.ts +90 -0
  88. package/src/hub/task-sweep.ts +3 -2
  89. package/src/hub/tasks.ts +292 -54
  90. package/src/hub/test-integrity.ts +162 -0
  91. package/src/hub/usage-rollup.ts +361 -0
  92. package/src/local/sandbox.ts +5 -3
  93. package/src/ui/index.html +1 -0
  94. package/templates/AGENTS.block.md +1 -1
  95. package/templates/profiles/dev.json +6 -1
  96. package/templates/profiles/general.json +6 -1
  97. package/templates/profiles/research.json +6 -1
  98. package/templates/profiles/writing.json +6 -1
  99. package/templates/release-guard.block.md +6 -0
@@ -8,7 +8,7 @@ Scope: tests, fakes and the test gate. Read before adding or changing a test or
8
8
  - A test timeout that fires while `Bun.spawnSync` runs can start the next test inside spawnSync's own event loop (Bun 1.3.14 and 1.4.2; background: README). `scripts/check.sh` runs tests with a 20 s timeout and under `scripts/hang-watch.sh`; a test that spawns and reads the process table gets a timeout of its own, never above 20 s: an explicit larger timeout overrides the gate's `--timeout 20000`, so shorten the scenario instead.
9
9
  - Sandboxed commands and the MLX server get a fixed environment (`PATH`, `HOME` and their own keys), so test knobs for their fakes travel in a wrapper script or argv, not in `process.env`; native peer children inherit the hub's environment minus the agent markers (`peerChildEnv`).
10
10
  - Bind agent identity markers explicitly in native/CLI fixture children. The full gate starts the test runner without inherited agent markers (including `AGENTHUB_DELIVERY_ONLY`) and without an `ahub claude` session's hub variables (`AGENTHUB_PROJECT_DIR`, `AGENTHUB_STATE_DIR`, `AGENTHUB_INSTANCE_ID`, `AGENTHUB_LAUNCH_ID`); a new variable a native session exports and a fixture child reads joins that `env -u` list in `scripts/check.sh`. Never weaken production marker detection to make them pass.
11
- - `bunfig.toml` preloads `test/hub-home.ts`, which first clears inherited `AMEM_HOME` and gives every test run (the gate and `bun test <file>` alike) a temp `AGENTHUB_HOME` unless one is set; scoped tests may set their own `AMEM_HOME` after preload. Hub memory (#258) is on with any project config, and no test may write the person's `~/.agenthub`. Do not remove it; a test that needs its own home sets and restores the variable.
11
+ - `bunfig.toml` preloads `test/hub-home.ts`, which first clears inherited `AMEM_HOME` and gives every test run (the gate and `bun test <file>` alike) a temp `AGENTHUB_HOME` unless one is set; scoped tests may set their own `AMEM_HOME` after preload. Hub memory (#258) is on with any project config, and no test may write the person's `~/.agenthub`. Do not remove it; a test that needs its own home sets and restores the variable. The preload keeps an inherited `AGENTHUB_HOME`, which an agent shell exports as the person's hub home and `scripts/check.sh` does not unset: run `bun test` and the gate with `env -u AGENTHUB_HOME`.
12
12
  - `test/registry-guard.test.ts` statically scans `src/` against the committed `test/registry-guard.baseline.json` (#451); a test never writes, regenerates or repairs that baseline, and a failing guard is fixed in the source by moving the policy into a definition (rule: `docs/agent-notes/adapters.md`); the baseline stays `[]`. Scanner behavior is pinned on inline sources in `test/registry-guard-fixtures.test.ts`, never on edits to real files.
13
13
  - A fixture that needs a port takes it from a free-port probe, never a fixed number, which collides with whatever holds it on a shared runner (#548). The probe binds `127.0.0.1`, matching the loopback server that takes the port (#232).
14
14
  - `ahub upgrade` without `--to` asks the registry (`npm view`) and hands a target newer than the CLI to `bun x` (#272): a test that reaches either puts a fake `npm` first on `PATH` and a recording stand-in for `process.execPath`, as `test/upgrade-cli.test.ts` does. The interactive screens are tested through a scripted `ScreenIO`; a CLI test that needs them marks `process.stdin` and `process.stdout` as terminals in a wrapper script.
@@ -23,10 +23,12 @@ Scope: tests, fakes and the test gate. Read before adding or changing a test or
23
23
  - The whole-suite watchdog is `AHUB_CHECK_HANG_S` (default in `scripts/check.sh`, hosted values for both OSes in `.github/workflows/check.yml`; #378, #593): raise it only when the suite was still progressing at the cutoff, never for a hung test, and keep the per-test 20 s timeout. The check job's `timeout-minutes` must leave room above that value for setup: raise them together.
24
24
  - A seed's named test must run on Linux, where the seeded job runs: a darwin-only test reports no result there and fails the job (#382). Cover a macOS-only protection with its regression test instead.
25
25
 
26
+ - A test of `runCheck` (`src/hub/checks.ts`, #558) injects a `CheckSpawn` (argv and options in, `{ pid, exited, signalCode, stdout, stderr }` out) and never patches `node:child_process`: the runner reads a child's exit and pipes as values through `Bun.spawn`, because node's event layer can report a quick child's exit inside `spawn()` before a listener exists under load on macOS (oven-sh/bun#45483). Keep the `ended` fixtures for the already-ended case, and do not raise the 5 s limit or the 1 s kill grace to fix a flake.
27
+
26
28
  - Keep CI's Bun version sourced from `.bun-version` through the pinned setup-bun action; update the version file rather than adding per-job version literals.
27
29
  - Release verification requires both OS checks and the aggregate `seeded guards` success for an identical tree, a tag matching `package.json` on `origin/main`, and fresh ancestor-bound documentation stamps. Preserve the separate npm OIDC publish job and GitHub Release write job; neither job gets the other's credential authority.
28
30
  - `test/conformance/` runs real adapters against fake transports. The shared kit and the transport fakes live in `src/adapters/conformance/` (public `@staix/agent-hub/conformance`); `test/conformance/kit.ts` and the matching `test/fakes/*.ts` only re-export them, so change the packaged file, and `--changed` runs everything for it; `test/conformance/enrollment.ts` enrolls every `ADAPTERS` definition and each `:reviewer` variant. Record a case that does not apply in its `UNSUPPORTED` or `UNSUPPORTED_LEGS` map with a concrete reason naming the dedicated coverage, never `test.skip` or synthetic success, and never change native production behavior to satisfy a generic case.
29
31
 
30
32
  - Keep the CI admission lock around the whole controller workflow, not just its decision job, in its per-PR (`check-pr-<number>`, `queue: single`: a newer pending run replaces the older) or main (`check-main`, `queue: max`) group, never with `cancel-in-progress: true` beside `queue: max` (GitHub refuses it) (#609); two groups admitting one tree at once is an accepted duplicate run, never a reason to fail closed on another tree. Preserve successful identical-tree full proof and required job names; a skipped job, pending controller or unavailable active inventory is never a successful full gate. In `readFullGateAdmission`, lost successful proof (404, malformed proof, a per-read timeout) only means a fresh gate runs; unknown active coverage and the global read ceilings (`GateReadLimitError`) stay unknown and refuse. CI checks out the PR head (`pull_request.head.sha`), not a merge with main: after a fix lands on main, merge main into the branch before reading CI as proof. CI reuse tests use fixed metadata fixtures and never dispatch real duplicate workflows.
31
33
 
32
- - Headless-reviewer tests run `test/fakes/fake-claude-print.ts` through `command` or a PATH stand-in, and fresh Codex reviewer tests run `test/fakes/fake-codex-reviewer.ts` through `codex_bin`; a test that reaches the daemon's reviewer start must never run the real `claude` or `codex`. The fake's sandbox markers test host admission only, never native isolation. Fresh Kimi reviewer tests set and restore `KIMI_CODE_HOME` to a fixture native home (the backend links that home's `credentials/`, `oauth/` and `device_id`, else the person's `~/.kimi-code`) and run `test/fakes/fake-kimi-reviewer.ts` through `command` or a PATH stand-in, never the real `kimi`. agy tests put a fake `agy` first on PATH and set `HOME` to a temp dir before any transcript readback (`readAgyTranscript` reads `$HOME/.gemini`).
34
+ - Headless-reviewer tests run `test/fakes/fake-claude-print.ts` through `command` or a PATH stand-in, and fresh Codex reviewer tests run `test/fakes/fake-codex-reviewer.ts` through `codex_bin`; a test that reaches the daemon's reviewer start must never run the real `claude` or `codex`. The fake's sandbox markers test host admission only, never native isolation. Fresh Kimi reviewer tests set and restore `KIMI_CODE_HOME` to a fixture native home (the backend links that home's `credentials/`, `oauth/` and `device_id`, else the person's `~/.kimi-code`) and run `test/fakes/fake-kimi-reviewer.ts` through `command` or a PATH stand-in, never the real `kimi`. agy tests put a fake `agy` first on PATH and set `HOME` to a temp dir before any transcript readback (`readAgyTranscript` reads `$HOME/.gemini`). Code-facts tests build `new CodeFacts({ env })` with a PATH whose first `ripwire` is a wrapper around `test/fakes/fake-ripwire.ts` (`FAKE_RIPWIRE_MODE` selects its failures), or inject Tasks' `prepareReviewBrief`; never rely on an installed ripwire, which CI does not have.
@@ -0,0 +1,92 @@
1
+ # Dogfooding: agent-hub on agent-hub
2
+
3
+ agent-hub is developed with agent-hub. This page lists every feature, whether it runs in this repository's own hub, and how its real-use behaviour and performance are measured. The tracking issue is #687.
4
+
5
+ - **State:** `on` runs here; `advise` runs and reports without blocking; `off` is available but not enabled here, with the reason; `pending` is not built yet (its issue).
6
+ - **Measured by:** the command or record that shows, from real use, whether the feature works and what it costs. The weekly scorecard (#687) collects these into `docs/verification/dogfood/`.
7
+ - **Rule:** a PR that adds or changes a user-facing feature updates its row here: whether it runs on this repository, and the metric that shows it works.
8
+
9
+ ## Coordination
10
+
11
+ | Feature | State here | Measured by |
12
+ | --- | --- | --- |
13
+ | Message bus, digests, priorities | on | `ahub report`: messages, digests, overflow, undeliverable; delivery latency from events |
14
+ | Task board, routing, roles | on (claude planner and reviewer; codex, jcode, agy implementers) | board history: lead time from propose to approve, review rounds, escalations |
15
+ | Overlap notices | on; plan symbols match by normalized name (arguments stripped, a bare name matches the last segment, two qualified names must be equal; #682 phase 1b) | `ahub report`: overlap warnings, task pairs; false-overlap rate, and symbol-only matches on bare common names (#682) |
16
+ | Planner WIP caps and backlog pull (#655) | on (`tasks.wip_limits.codex = 2`) | held-ready entries, offers refused for capacity |
17
+ | Task sweep (stalls, idle owners) | on | stall and sweep events per week |
18
+ | Turn-free coordination | off: experimental; needs a separate measured trial | coordination events, conflict notices |
19
+ | Pull-only peers (agy) | on; `hub_inbox` drains to 64 KiB (#713) | unread offers, empty-inbox polling (#681); queued count and oldest queued age per pull-only peer in `ahub status`; reads that said `N more waiting` |
20
+ | Completed-change notices, grouped and superseding (#713) | on after release; accepted tasks only | queued `is done and touches` notices per peer (one per done, not per task and per repeat); `superseded completed-change notice` discards; `ahub queue discard` uses |
21
+
22
+ ## Review and lifecycle
23
+
24
+ | Feature | State here | Measured by |
25
+ | --- | --- | --- |
26
+ | Optional changed-symbol advice (#682, #684 phase 1a) | on after release when ripwire 0.6.7 is installed; change kinds unknown | review brief symbol observations/unknowns; deleted definitions not covered, no gate |
27
+ | Head-bound task symbol observations (#684 phase 2a) | on after release with optional code facts; observed names only | task/UI receipts and completed-change labels; unknown/filtered evidence keeps ordinary overlap, deleted definitions not covered |
28
+ | Console changed-symbols block (#684 phase 2b) | on with 2a data; matching, unplanned and untouched against the plan; overlap lines follow in #379; related-note count remains phase 4 | task detail shows the block or `unknown (no code facts)`; no block for a private task |
29
+ | Console review guidance (#711) | on after release; `r` verdict choice, hints, visible result, agent-shell cause line, notice names the console | a person approving from the console without a failed first try; refusals that named the cause; `ahub review` calls from agent shells that were refused |
30
+ | Console symbol-overlap advice (#684, #379) | on after release; read-only task detail, observed names only | other task IDs/shared paths and screened different-symbol verdict; no pair involving PII, no claim on unknown/incomplete evidence |
31
+ | Review brief, review findings, Important gate (#481 S3) | advise | Important findings per PR, rounds to approval |
32
+ | Spec acceptance (#481 S1) | advise | build entries without acceptance |
33
+ | Lifecycle identity linked by the hub (#694) | on in advise | tasks still showing `issue identity missing` or `PR identity missing` at review |
34
+ | Planner plan review (#481 S9) | advise | plans reviewed before build |
35
+ | Plan conformance (#481 S2) | advise | PRs with files outside the plan |
36
+ | Test integrity for bug fixes (#481 S4) | advise | bug PRs without a red-first receipt, modified pre-existing tests |
37
+ | Required checks | advise (`check (ubuntu-latest)`, `check (macos-latest)`, `seeded guards`) | first-pass CI rate, same-head reruns (`hub_sdlc_costs`) |
38
+ | Release authorization (#481 S6) | pending (#199) | releases with a receipt |
39
+ | SDLC metrics and control bands (#481 S7) | pending (#200) | its own report |
40
+ | Fresh headless reviewers (#223, #519) | off: needs an `instances` entry in the person's `config.local.json` | reviews by fresh sessions, findings they add |
41
+ | Completion checks per class | off: the implementer already runs `scripts/check.sh`; a hub-run copy would double the heavy-slot use | time to verdict when on |
42
+
43
+ ## Memory and knowledge
44
+
45
+ | Feature | State here | Measured by |
46
+ | --- | --- | --- |
47
+ | Shared memory through amem, briefs, recall preface | on | notes saved per week, brief hits, fails that prevented a retry |
48
+ | `ahub ask` | on | answers with cited ids |
49
+ | Code structure in the memory graph (#684) | pending | stale anchors, briefs with related notes |
50
+
51
+ ## Models, budget and safety
52
+
53
+ | Feature | State here | Measured by |
54
+ | --- | --- | --- |
55
+ | Quota budgets and pauses | on | pauses, resets, time paused (#683) |
56
+ | Token usage per peer and task | `ahub report` and, from the roll-up in `hub.db`, `ahub usage [--by peer\|task\|issue\|pr\|release\|day\|model]`, `usage limits` and `usage total` (#683 U2); console and dashboard views pending (U3, U4) | tokens per merged PR |
57
+ | Context gate | off: `context.gate = 0` | context-pressure events |
58
+ | Always-ask action classes (#636) | foundation only; enforcement pending (#312, #313) | classed calls asked, budget refusals |
59
+ | Permission modes | on, person-chosen | approval prompts and their wait times |
60
+ | Pi and the local worker on DGX | off: DGX unreachable recently; Pi is off the roster | turns served on-prem, relay errors |
61
+ | PII routing | on | PII tasks and where they ran |
62
+ | Multiple Jcode instances (#685) | pending | turns per instance |
63
+
64
+ ## Operations
65
+
66
+ | Feature | State here | Measured by |
67
+ | --- | --- | --- |
68
+ | Dogfood scorecard (#687) | on after release; read-only weekly receipt | `ahub report --dogfood --since 7d --json`; bounded evidence and explicit unknowns |
69
+ | Console and dashboard | on | control-request latency, connection timeouts in `hub.log` |
70
+ | Usage view (#683) | CLI (`ahub usage`, U2) and console Usage tab `7` (U3) shipped; dashboard panel pending (U4) | its own panels |
71
+ | Settings reload | on | reloads applied, pending restarts |
72
+ | Config editing from the console and dashboard (#689) | pending; hand edits of `config.local.json` meanwhile | edits applied, refused by validation, pending restarts |
73
+ | Upgrade and recovery | on, per release | upgrade receipts in `docs/verification/` |
74
+ | Agent CLI version policy and trust (#691) | on after the release: Codex 0.163.0 verified by the [2026-10-22 receipt](verification/2026-10-22-codex-reviewer-isolation.md); Kimi 2.3.0 and Qwen 0.26.0 verified by the [model-free receipt](verification/2026-10-22-kimi-qwen-compat.md), with account/provider live legs unverified; agy 1.4.4 in-line | model-free isolation receipts, `ahub agents` verdicts, versions trusted per machine, lead time from an `agent-compat` issue to a receipt |
75
+ | Benchmarks (#251, #637) | off: `bench.enabled = false`; routing gate pending | bench receipts |
76
+
77
+ ## Decisions
78
+
79
+ - 2026-10-22: SDLC mode `advise` (`.agenthub/sdlc.toml`, machine-local). Move to `enforce` after one week of advise data, when the person decides that the false-blocker rate is low. Record the decision here.
80
+
81
+ ## Weekly scorecard
82
+
83
+ Run `ahub report --dogfood --since 7d --json` against this repository's own hub before the weekly review and each release. It has the same read-only authority as `ahub report`, so the planner can produce the receipt. Save the result and its source commit under `docs/verification/dogfood/YYYY-MM-DD.md`. Run it once at the work boundary; do not create a polling loop.
84
+
85
+ - The scorecard exports ids, timestamps, counts and coverage only. PII tasks are counted without titles. GitHub reads exclude their known PRs. It never runs a model or creates an issue or task.
86
+ - `null` in JSON means unknown; the text format prints `unknown`. Source availability and completeness are separate. Partial event data is an observed subset, not a complete token bill; event, usage and attribution coverage are separate.
87
+ - Flow is scoped to at most 16 merged PRs found by a capped GitHub read. PR lead time runs from the earliest linked task proposal to the last linked task approval. Missing task links remain unknown. Review rounds reuse `costMetrics`' board handoff definition. CI reads use `head_sha=<recorded-head>&created=<since>..<until>` so unrelated weekly or lifetime runs cannot consume a PR's 100-run page. Only a fully enumerated commit/review/head SHA set is used, including when REST omits PR associations. At most eight heads per PR and 32 CI requests across the 16 selected PRs run under the shared 20 s deadline and 128 KiB response cap. Missing/truncated metadata, a failed or truncated head response, duplicate run ids, more than 100 combined PR runs or an exceeded request/deadline budget keeps that PR's CI unknown. Recent merged PRs are read first. First-pass CI needs the first run's original conclusion and a PR opened within the window; older or unknown PR opening times stay unknown because earlier runs may be outside the window. A later rerun's success does not certify the first result. Same-head reruns count actual `run_attempt - 1`, not duplicate workflows.
88
+ - Connector counts are review threads first opened by that bot after all linked tasks were approved, not a severity classification. Bug counts use explicit cross-references and the `bug` label; they show association, not proven causality, and include the observation age up to 14 days.
89
+ - Each input event/log file has a 16 MiB read cap. The board has row, per-cell and total bounds. GitHub has a 20 s deadline, a 16-PR cap, 100-node pages and 128 KiB responses. Missing, malformed or truncated evidence remains incomplete; the report does not silently call it zero.
90
+ - Digest and held counts describe retained journal rows created in the window. The journal prunes terminal rows, so these are not historical totals. It does not record the first delivery timestamp: `updatedAt` must not be used as delivery latency.
91
+ - Control latency, connection timeouts, CPU/RSS history, actual snapshot exhaustion totals and the adjudicated real-blocker rate currently have no durable source and remain unknown. Snapshot budget notices count one log diagnostic per affected burst. Error classes and advise-gate matches are fixed-pattern log counts; no raw line is exported.
92
+ - Adoption row ids are the 1-based table-row order in this document at the feature-table source commit recorded in the receipt. A matching event is evidence of that leg's use, not proof that the entire feature was enabled or correct. Rows without a dedicated observable leg stay unknown.
package/docs/events.md CHANGED
@@ -40,7 +40,7 @@ marked `private: true`, and PII tasks `pii: true`.
40
40
  | `turn_start` | `peer`, `turn` (`<peer>#<hub run>.<n>`, unique across restarts). A turn follows the adapter: pausing a busy peer does not end it |
41
41
  | `turn_end` | `peer`, `turn`, `ms`, `tokens` (when the adapter reported any during the turn), `files` and `snapshotMs` (when snapshots are on: how many files the turn changed, and the time both snapshots took); optional numeric `task`, `attribution` (`delivery`, `single_open`, `unattributed`) frozen at turn start, `pii: true` for an attributed PII task |
42
42
  | `tokens` | `peer`, `n` (tokens added since the previous report), optional numeric `task`, `attribution` (`delivery`, `single_open`, `unattributed`), `pii: true` for an attributed PII task |
43
- | `usage` | `peer`, `source` (`omniroute`, `claude_transcript`), opaque `id`, optional `measuredAt` (provider/source time), the `requestedModel`, `servedModel` and `provider` labels, and any provider-reported counters (`inputTokens`, `outputTokens`, `cacheReadTokens`, `cacheWriteTokens`, `totalTokens`); optional numeric `task`, `attribution` (`delivery`, `single_open`, `unattributed`), `pii: true` for an attributed PII task. Missing counters stay unknown. |
43
+ | `usage` | `peer`, `source` (`omniroute`, `claude_transcript`, `codex_appserver`), opaque `id`, optional `measuredAt` (provider/source time), the `requestedModel`, `servedModel` and `provider` labels, and any provider-reported counters (`inputTokens`, `outputTokens`, `cacheReadTokens`, `cacheWriteTokens`, `reasoningTokens`, `totalTokens`); optional numeric `task`, `attribution` (`delivery`, `single_open`, `unattributed`), `pii: true` for an attributed PII task. Missing counters stay unknown. |
44
44
  | `task` | `id`, `event` (the board history event, e.g. `proposed`, `assigned`, `done`, `check failed`, `blocked`, `ready`), `by`, `state`, `owner`, `reviewer`, `class`, `pii`, and `reason` when the board recorded a move reason (`manual`, `budget`, `offline`, `idle`, `rejections`, `declined`, `inference_failed`, `delivery_failed`) |
45
45
  | `overlap` | `task`, `owner`, `others` (`task`, `owner`, `paths`, and `symbols` when plans name the same symbol; a name that matches a PII pattern is left out, so either list can be empty), the structured twin of the console notice |
46
46
  | `permission_mode` | `peer`, `from`, `to` (`ask`, `ask-when-needed`, `never-ask`): a person set a peer's permission mode (`from` equals `to` when it was already in force) or confirmed a never-ask default (issue #242) |
@@ -49,6 +49,9 @@ marked `private: true`, and PII tasks `pii: true`.
49
49
  | `pii_screen` | `task` (absent for a budget hand-off or a note not about a task), `item` (`task`, `summary`, `review note`, `handoff`, `note`), `label` (`pii`, `clear`), `source` (`regex`: a pattern matched and no call was made; `screen`; `unknown`: no verdict, handled as PII), `category` (`name`, `student_id`, `phone`, `address`, `grade`, `health`, `other`), `miss` (why there was no verdict: `too long`, `off campus`, `timeout`, `unreadable`, `failed`), `ms` (absent for `regex`): one PII screen verdict while `signals.pii_screen = "local"` (issue #198); never the text |
50
50
  | `context_pressure` | `peer`, `source` (`claude_statusline`, `codex_token_usage`, `acp_usage_update`), `measuredAt` (epoch ms of the reading), `used` (the fraction of the context window in use, 0 to 1), `window` (its size in tokens, or null): a fresh reading of a peer's native context reached `context.gate`. Recorded once per crossing, until a reading below the gate or a new native session rearms it, and not while the peer is paused or offline or the hub is in recovery or stopping |
51
51
  | `quota` | `peer`, `windows` (`id`, `used`, `resetsAt`), `hard`, `measuredAt` (when the reading was taken, if not when it arrived: Claude's numbers come through a file) |
52
+ | `budget_pause` | `peer` (the account), `reason` (the coordinator's own text: window id, percent and source), `window` (`5h`, `week`, `tokens` or `unknown`), `resetsAt` (epoch ms), `by` (`hub`). Written where the pause record is written (#683). |
53
+ | `budget_resume` | the same fields; `reason` says why it ended and `by` is `hub` (the window reset, or usage fell back under the gate) or `person` (an `ahub budget resume` override). A pause replaced by a new one after its window reset gets a `budget_resume` first (reason `replaced by a new pause after its window reset`). `ahub reset` clears pauses without writing one, because it keeps `events.jsonl` untouched. |
54
+ | `quota_reset` | `peer`, `window`, `cause` (`resets_at_moved`: the window's `resetsAt` moved forward by more than 15 minutes, since a provider's `resetsAt` wobbles by seconds inside one window; `used_dropped`: `used` fell by 0.5 or more inside one window id), `resetsAt`, `previousResetsAt`, `used`, `previousUsed`, optional `measuredAt`. Derived from two readings, one entry per peer, window and `resetsAt`, also across a restart. |
52
55
  | `conflict` | `peer`, `task` (its task in progress, when it had one), `other` (the other owner's open task), `owner`, `paths` (names that match a PII pattern left out, so it can be empty), `concurrent` (another peer worked during the turn), `turns` (the two turn ids, when two overlapping turns' snapshots both hold the change) |
53
56
 
54
57
  Token usage by adapter:
@@ -63,6 +66,12 @@ Token usage by adapter:
63
66
  compaction estimates, usage-limit refreshes and the replay to a reattaching connection add nothing. A thread
64
67
  started under the hub counts from zero; a resumed thread's first update is its history and only sets the
65
68
  baseline. The model call of a compaction itself is real usage and counts.
69
+ Each update that adds tokens also writes a `usage` event with source `codex_appserver`, beside the unchanged `tokens`
70
+ event: `inputTokens`, `cacheReadTokens` (cached input), `outputTokens` and `reasoningTokens` are the growth of
71
+ Codex's own counters, with the same baseline rule, and `totalTokens` is the growth of `totalTokens`. Codex counts
72
+ cached input inside input and reasoning inside output, so `inputTokens + outputTokens` equals `totalTokens` and the
73
+ other two are shares of those, never added again. Replaying 55 real updates of a recorded Codex 0.163.0 session through the proxy handler gave the same totals as the recorded counters, with 98 percent of the input cached. Codex 0.163.0 also reports `cacheWriteInputTokens` (0 in every update of that session); the hub does not read it yet, so a nonzero value would be missing from the breakdown until a later slice adds it. The id is unique per hub run, peer and sequence and never carries the native thread, since usage telemetry has no session id. The ledger events
74
+ carry ids, windows and numbers only: no checkpoint text, summary or task title.
66
75
  - Pi: the assistant usage its extension forwards at each `message_end`, tool-loop messages included, is recorded as
67
76
  increments, each usage id once; a message without a usable count adds nothing.
68
77
  - Claude native transcript usage is optional and keyed by an opaque hash of session and message identity; streamed records with the same message id count once. The status line tee still carries quota percentages only.
@@ -70,6 +79,10 @@ Token usage by adapter:
70
79
  - `ahub report` deduplicates usage records by peer, source and id. Coverage counts distinguish calls with provider usage from calls where usage was absent. Token counters are provider-reported values; the report never derives a price or treats missing spend as zero. Estimated price and measured provider spend remain unknown unless a future source reports them.
71
80
  - Usage telemetry has no prompt, completion, task text, credential, Access header, session id or transcript path.
72
81
 
82
+ ## The usage roll-up (#683)
83
+
84
+ `ahub usage` does not read `events.jsonl` on each call. The daemon folds it into `hub.db`: `usage_rollup` (day, peer, model, source, task and the private mark, with the sum of each provider counter and how many records carried it), `token_rollup` (the hub's own `tokens` increments), `limit_events` (every `budget_pause`, `budget_resume` and `quota_reset`, without the reason text) and `rollup_state` (the byte offset and the first event's time). Each `usage` record is counted once by peer, source and id, as `ahub report` counts it. The roll-up holds ids and numbers only, so a title cannot reach it. A sum is shown only where at least one record carried the counter, otherwise it is unknown.
85
+
73
86
  ## Per-task usage reports
74
87
 
75
88
  `ahub report --by task` (also `--json` and `--since`) reads only `events.jsonl`.