Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
435a5b0
fix(usage): catch the "<synthetic>" placeholder even without isApiErr…
pacphi Aug 6, 2026
073f342
feat(dashboard): date-windowed Observability History browsing
pacphi Aug 6, 2026
0bd5c12
docs: propose the System area — ADR-0025, machine-footprint domain, d…
pacphi Aug 6, 2026
ed6047f
docs: propose the About area — ADR-0026, component-directory domain, …
pacphi Aug 6, 2026
f15ba90
feat(about): component directory, ak about, and a registry parity gate
pacphi Aug 6, 2026
ede6159
feat(system): machine-footprint collectors incl. first-class Windows …
pacphi Aug 6, 2026
6054ec1
feat(system): GET /api/system, snapshot persistence, and the ak syste…
pacphi Aug 6, 2026
bbfb1f3
feat(dashboard): About and System primary areas
pacphi Aug 6, 2026
4ee806d
docs: mark ADR-0025/0026 implemented and document About and System
pacphi Aug 6, 2026
d6995b3
fix(dashboard): strip mock annotations, report every version, unbreak…
pacphi Aug 7, 2026
2306659
fix(dashboard): correct foldKnownVersions' JSDoc so tsc --checkJs passes
pacphi Aug 7, 2026
76bdd28
test(ui): defuse the dated fixture corpus, and match the hero's new c…
pacphi Aug 7, 2026
2387a35
feat(system): wire the footprint collectors, fix a hard hang, expand …
pacphi Aug 7, 2026
fdd7052
feat(dashboard): one project census, current models, reworked System …
pacphi Aug 8, 2026
9811341
fix(dashboard): loosen the System layout and plainen the Advisory copy
pacphi Aug 8, 2026
8ab85bd
feat(dashboard): sortable headers on the System project footprints table
pacphi Aug 8, 2026
097ecf2
fix(test): canonicalise fixture roots the way the collectors do, and …
pacphi Aug 8, 2026
ea160f6
fix(footprint): the cloud-placeholder rule condemned every file on Wi…
pacphi Aug 8, 2026
7fb0c4e
fix(footprint): the same POSIX-blocks assumption in two more places
pacphi Aug 8, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,9 @@ ak status read-only dashboard: what's true, what's drifted [--json] [--d
ak sync converge to good: upgrade + heal + verify [--dry-run] [--no-upgrade]
ak dashboard open the local web dashboard (auto-opens your browser)
[--port N] [--no-open] [--live-source 'surface=path']
ak about what each installed component is and why it's there
ak system machine footprint: install size, runtime, storage, catalog, projects
[--deep] [--json]
ak usage inspect/refresh offline provider account analytics
status | refresh openrouter
ak host manage execution hosts, routing, and provider bindings
Expand Down
4 changes: 4 additions & 0 deletions bin/agentic-kit.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ const PORCELAIN = Object.assign(Object.create(null), {
dashboard: () => import('../src/commands/x/dashboard.mjs'),
admin: () => import('../src/commands/x/admin.mjs'),
usage: () => import('../src/commands/usage.mjs'),
system: () => import('../src/commands/system.mjs'),
about: () => import('../src/commands/about.mjs'),
run: () => import('../src/commands/run.mjs'),
host: () => import('../src/commands/x/host.mjs'),
uninstall: () => import('../src/commands/uninstall.mjs'),
Expand Down Expand Up @@ -49,6 +51,8 @@ Usage (ak = alias of agentic-kit):
ak dashboard open the local web dashboard (localhost; auto-opens browser) [--port N] [--no-open]
ak admin maintainer-only telemetry admin (localhost; GitHub/npm egress) [--port N] [--no-open]
ak usage inspect/refresh offline provider analytics [status|refresh openrouter]
ak system what this stack occupies on your machine [--deep] [--json]
ak about what agentic-kit installs and configures, and why [--category N]
ak run execute a host-neutral activity pipeline [template "task"] [--dry-run]
ak host manage agent hosts, routing, and provider bindings [status|pick|refresh|off]
ak uninstall leave cleanly [--this-project] [--purge]
Expand Down
227 changes: 214 additions & 13 deletions docs/DASHBOARD.md

Large diffs are not rendered by default.

29 changes: 20 additions & 9 deletions docs/PROVIDERS.md
Original file line number Diff line number Diff line change
Expand Up @@ -231,12 +231,24 @@ Defaults (all overridable; your edits are marked `custom` and never re-seeded):
|---|---|---|
| specification, review, release | claude | `claude-sonnet-5` |
| architecture, design, debugging, security-analysis | claude | `claude-opus-5` |
| implementation, testing, security-scan | codex | `gpt-5.4` |
| documentation, packaging | codex | `gpt-5.3-codex` |
| implementation, testing, security-scan | codex | `gpt-5.6-terra` |
| documentation, packaging | codex | `gpt-5.6-luna` |

*(packaging & release are `ak`-added — ruflo ships templates for feature/security/refactor only.)*

**Known-good model choices** (verified 2026-07; any model your host CLI accepts also works):
**Retired codex models.** `gpt-5.4` and `gpt-5.4-mini` retire from Codex on **2026-08-31**, and
`gpt-5.3-codex` is already withdrawn for ChatGPT sign-in
([Codex models](https://developers.openai.com/codex/models)) — which is why the execution defaults
above moved to the 5.6 line. `ak` substitutes a retired model at read time, so no run dispatches to
one even if your `kit.json` still names it, and `ak sync` rewrites `seeded` routes that do. A `user`
pin is reported but never rewritten on disk (see
[ADR-0003](adr/0003-auto-seed-dual-host-provenance.md)).

`claude-opus-4-8` is **not** retired — it carries no deprecation notice and stays pinnable. It is
merely no longer the default, which `ak status` reports as routing *divergence*: a trade for you to
weigh, cleared with `ak x host refresh` if you want the newer default.

**Known-good model choices** (verified 2026-08; any model your host CLI accepts also works):

> **Per-token price ≠ per-task cost.** A model that needs more agentic turns costs more
> per task at the same per-token price. On subscription (`claude-code` oauth) billing the
Expand All @@ -245,15 +257,14 @@ Defaults (all overridable; your edits are marked `custom` and never re-seeded):

| Host | Model | When to use |
|---|---|---|
| claude | `claude-opus-5` | new top Opus — same per-token price as 4.8, but ~2–3× the agentic turns on routine work; earns it at the hard end |
| claude | `claude-opus-5` | top Opus — the deepest reasoning, at ~2–3× the agentic turns of a balanced model on routine work; earns it at the hard end |
| claude | `claude-sonnet-5` | near-Opus capability at a lower per-token price — review, spec, release |
| claude | `claude-fable-5` | top capability (Mythos-class, above Opus 5) — hardest problems |
| claude | `claude-haiku-4-5-20251001` | cheap/fast — high-volume mechanical work |
| claude | `claude-opus-4-8` | prior Opus generation — same per-token price, roughly half the turns on routine work |
| codex | `gpt-5.4` | coding + reasoning + agentic — recommended execution default |
| codex | `gpt-5.6-sol` | newest line; first-class max reasoning effort |
| codex | `gpt-5.3-codex` | pure coding-tuned — mechanical implementation & docs |
| codex | `gpt-5-codex-mini` | smallest/cheapest — escalation floor, high volume |
| claude | `claude-opus-4-8` | prior Opus generation — same per-token price as Opus 5, roughly half the agentic turns on routine work |
| codex | `gpt-5.6-sol` | flagship 5.6 — strongest on complex coding, computer use and security work; first-class max reasoning effort |
| codex | `gpt-5.6-terra` | balanced 5.6 — everyday implementation and testing at a materially lower per-token price than sol; the gpt-5.4 replacement |
| codex | `gpt-5.6-luna` | fastest/cheapest 5.6 — mechanical implementation, docs and packaging; the gpt-5.4-mini replacement |

> **Where Opus 5 sits** ([announcement](https://www.anthropic.com/news/claude-opus-5), July 2026):
> same $5/$25 per-Mtok pricing as Opus 4.8 with roughly double the Frontier-Bench
Expand Down
60 changes: 30 additions & 30 deletions docs/TRANSCRIPTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,12 @@ rewritten; rule 3 of the module header, `usage-index.mjs:22-29`):

| Host | Store | Discovered by |
|---|---|---|
| Claude Code | `~/.claude/projects/<encoded-project-dir>/<sessionId>.jsonl` | `listClaude` (`usage-index.mjs:684`) — exactly one level of project directories |
| Codex CLI | `~/.codex/sessions/<yyyy>/<mm>/<dd>/rollout-<ts>-<uuid>.jsonl` | `listCodex` (`usage-index.mjs:705`) — the `yyyy/mm/dd` tree walk |
| Claude Code | `~/.claude/projects/<encoded-project-dir>/<sessionId>.jsonl` | `listClaude` (`usage-index.mjs:786`) — exactly one level of project directories |
| Codex CLI | `~/.codex/sessions/<yyyy>/<mm>/<dd>/rollout-<ts>-<uuid>.jsonl` | `listCodex` (`usage-index.mjs:758`) — the `yyyy/mm/dd` tree walk |

Roots come from `defaultRoots()` (`usage-index.mjs:697-701`) and are injectable
Roots come from `defaultRoots()` (`usage-index.mjs:750-754`) and are injectable
for tests. A malformed line is skipped, never fatal (`jsonLines`,
`usage-index.mjs:328-334` — one corrupt line must not cost a whole file).
`usage-index.mjs:381-387` — one corrupt line must not cost a whole file).

Host evidence is not inference-provider proof. A Claude transcript may describe Anthropic-,
OpenRouter-, or Ollama-served inference. ADR-0016 defines separate
Expand All @@ -52,34 +52,34 @@ transcript host/parser identity unless other evidence grounds the inference prov
### 1.1 Claude entry vocabulary

Each line has a top-level `type`. The parser (`parseClaude`,
`usage-index.mjs:427-510`) reads:
`usage-index.mjs:480-563`) reads:

| `type` | What the parser takes from it |
|---|---|
| `ai-title` | The model-written session title (`usage-index.mjs:435`) — preferred over the first-prompt fallback |
| `ai-title` | The model-written session title (`usage-index.mjs:488`) — preferred over the first-prompt fallback |
| `user` | A user-**role** turn — which is *not* the same as "the human"; see §3 |
| `assistant` | A model turn: `model` id, per-turn `usage` token counts, `tool_use` blocks (`usage-index.mjs:455-498`) |
| any | Side-band fields read regardless of type: `attributionSkill`/`attributionPlugin` (`usage-index.mjs:436-437`), `isSidechain` (`usage-index.mjs:438`), `cwd` for project derivation |
| `assistant` | A model turn: `model` id, per-turn `usage` token counts, `tool_use` blocks (`usage-index.mjs:508-551`) |
| any | Side-band fields read regardless of type: `attributionSkill`/`attributionPlugin` (`usage-index.mjs:489-490`), `isSidechain` (`usage-index.mjs:491`), `cwd` for project derivation |

An assistant entry with `isApiErrorMessage: true` is a **local placeholder**
Claude Code writes when a request dies before a real completion (connection
drop, rate limit, auth failure — `model: "<synthetic>"`, all-zero usage). It
is real engaged time but not a model attempt: counted as an *exception*, never
pushed into `models` or priced (`usage-index.mjs:498-517`; the full story is
pushed into `models` or priced (`usage-index.mjs:551-570`; the full story is
[`USAGE-SCORECARD-METRICS.md`](USAGE-SCORECARD-METRICS.md) §10).

### 1.2 Codex entry vocabulary

Codex rollout lines carry `type` + `payload`. The parser (`parseCodex`,
`usage-index.mjs:527-628`) reads:
`usage-index.mjs:580-681`) reads:

| `type` / `payload.type` | What the parser takes from it |
|---|---|
| `session_meta` | Authoritative session id, `cwd`, and `thread_source` (`usage-index.mjs:539-544`) — `"subagent"` marks a thread_spawn replay whose tokens are excluded from aggregation (`usage-index.mjs:609`; `USAGE-SCORECARD-METRICS.md` Appendix A, Bug B) |
| `turn_context` | The model id in effect from this point on (`usage-index.mjs:545`) |
| `event_msg` → `token_count` | A **cumulative** usage snapshot; only the last one is kept (`usage-index.mjs:609-611`) |
| `event_msg` → `user_message` | A real human prompt — Codex does not route tool output through this event (`usage-index.mjs:584-592`) |
| `event_msg` → `agent_message` | A model response (`usage-index.mjs:594-605`) |
| `session_meta` | Authoritative session id, `cwd`, and `thread_source` (`usage-index.mjs:592-597`) — `"subagent"` marks a thread_spawn replay whose tokens are excluded from aggregation (`usage-index.mjs:662`; `USAGE-SCORECARD-METRICS.md` Appendix A, Bug B) |
| `turn_context` | The model id in effect from this point on (`usage-index.mjs:598`) |
| `event_msg` → `token_count` | A **cumulative** usage snapshot; only the last one is kept (`usage-index.mjs:662-664`) |
| `event_msg` → `user_message` | A real human prompt — Codex does not route tool output through this event (`usage-index.mjs:637-645`) |
| `event_msg` → `agent_message` | A model response (`usage-index.mjs:647-658`) |

Codex tool calls and tool outputs travel in event types the parser does not
surface as turns at all — so a Codex transcript renders as a prompt/response
Expand All @@ -95,8 +95,8 @@ The same parsers serve two very different callers, switched by `withTurns`:

| Path | Entry point | `withTurns` | Message bodies | Cached? |
|---|---|---|---|---|
| **Scan** — the aggregate index behind the Scorecard/Findings/Sessions views | `buildIndex` → `parseFile` (`usage-index.mjs:693`) | `false` | never held — holding them would balloon memory across 3,000+ files (`usage-index.mjs:437-440`) | yes: per-file derived records in `~/.config/agentic-kit/usage-index.json`, keyed `(path, mtime, size)`, invalidated wholesale by `SCHEMA_VERSION` (`usage-index.mjs:51`) |
| **Reader** — one transcript for the Transcript view | `readSession` (`usage-index.mjs:1310`) | `true` | full turn list built | **never** — every call re-reads and re-parses the one file |
| **Scan** — the aggregate index behind the Scorecard/Findings/Sessions views | `buildIndex` → `parseFile` (`usage-index.mjs:746`) | `false` | never held — holding them would balloon memory across 3,000+ files (`usage-index.mjs:490-493`) | yes: per-file derived records in `~/.config/agentic-kit/usage-index.json`, keyed `(path, mtime, size)`, invalidated wholesale by `SCHEMA_VERSION` (`usage-index.mjs:51`) |
| **Reader** — one transcript for the Transcript view | `readSession` (`usage-index.mjs:1363`) | `true` | full turn list built | **never** — every call re-reads and re-parses the one file |

![Figure: one parser, two read paths — the scan path (withTurns false) caches per-file records keyed by path, mtime and size; the reader path (withTurns true) builds full turns and is never cached](assets/transcript-read-paths.svg)

Expand All @@ -117,11 +117,11 @@ recorded in `USAGE-SCORECARD-METRICS.md` Appendix A).
|---|---|---|
| `role` | all | `"user"` or `"assistant"` — the **Messages-API role**, not the author (see below) |
| `at` | all | ISO timestamp |
| `text` | all | Flattened display text (`claudeText`, `usage-index.mjs:384` — binary payloads dropped: a pasted screenshot renders as `[image]`, a tool result is prefixed `[tool result]`) |
| `model` | assistant | The model id; the literal string `exception` for an API-error placeholder turn (`usage-index.mjs:473`) |
| `text` | all | Flattened display text (`claudeText`, `usage-index.mjs:437` — binary payloads dropped: a pasted screenshot renders as `[image]`, a tool result is prefixed `[tool result]`) |
| `model` | assistant | The model id; the literal string `exception` for an API-error placeholder turn (`usage-index.mjs:526`) |
| `tools` | assistant | Tool names invoked in the turn |
| `prompt` | user | `isHumanPrompt`'s verdict (`usage-index.mjs:388-397`) — drives the **prompt counts** |
| `kind` | user | `'prompt'` \| `'tool-result'` \| `'context'` — drives the **attribution label** (`userTurnKind`, `usage-index.mjs:415-426`) |
| `prompt` | user | `isHumanPrompt`'s verdict (`usage-index.mjs:441-450`) — drives the **prompt counts** |
| `kind` | user | `'prompt'` \| `'tool-result'` \| `'context'` — drives the **attribution label** (`userTurnKind`, `usage-index.mjs:468-479`) |
| `exception` | assistant | `true` on API-error placeholder turns |
| `truncated`, `originalChars` | any | Present **only** when the turn was abridged (§4.3) |

Expand All @@ -141,7 +141,7 @@ story is [Appendix A](#appendix-a--fix-history).)

### 3.2 `kind` — the attribution field

`userTurnKind` (`usage-index.mjs:451-455`) classifies every user-role turn:
`userTurnKind` (`usage-index.mjs:523-528`) classifies every user-role turn:

| `kind` | Test | Meaning |
|---|---|---|
Expand All @@ -164,7 +164,7 @@ Two deliberate subtleties:
- **`tool-result` outranks `context`**: a `tool_result` block on an `isMeta`
entry is still tool feedback.

Codex user turns are `kind: 'prompt'` by construction (`usage-index.mjs:584-592`)
Codex user turns are `kind: 'prompt'` by construction (`usage-index.mjs:710`)
— rollouts only record real prompts as `user_message` events (§1.2).

Coverage: `tests/kit/usage-index.test.mjs` — "user-role turns carry a kind"
Expand All @@ -175,18 +175,18 @@ and image-only pastes get the right kind" (the two edges).

## 4. The `readSession` pipeline — how one session becomes a payload

`readSession(id, opts)` (`usage-index.mjs:1297-1385`) is the only way
`readSession(id, opts)` (`usage-index.mjs:1350-1438`) is the only way
transcript content leaves the module, and every step is a gate:

### 4.1 Locate, contain, bound

1. **Id grammar before any filesystem access** — `VALID_ID`
(`/^[A-Za-z0-9._-]{1,128}$/`, `usage-index.mjs:83`) rejects traversal
shapes with `ERR_INVALID_SESSION_ID` (`usage-index.mjs:1329-1333`).
2. **Locate by id** across both roots (`locate`, `usage-index.mjs:1339`),
shapes with `ERR_INVALID_SESSION_ID` (`usage-index.mjs:1382-1386`).
2. **Locate by id** across both roots (`locate`, `usage-index.mjs:1392`),
consulting the scan cache when present but never requiring it —
`readSession` works with no prior `buildIndex`.
3. **Realpath containment** (`usage-index.mjs:1335-1349`) — the resolved file
3. **Realpath containment** (`usage-index.mjs:1388-1402`) — the resolved file
must live under a transcript root *after* `realpathSync` collapses
symlinks; a symlink planted inside a root pointing at `/etc/anything`
passes a lexical `startsWith` but fails this. Roots are realpath'd too so
Expand All @@ -198,8 +198,8 @@ transcript content leaves the module, and every step is a gate:
### 4.2 Parse and price

The file is parsed with `withTurns: true` by the provider's parser
(`usage-index.mjs:1430-1437`), and `meta` is assembled
(`usage-index.mjs:1414-1442`) with the same fields the Sessions view rows
(`usage-index.mjs:1483-1490`), and `meta` is assembled
(`usage-index.mjs:1467-1495`) with the same fields the Sessions view rows
carry — `prompts`, `responses`, `exceptions`, `sidechain`, `threadSource`,
`models`, `tools`, `skill`/`plugin`, worktree — plus a `cost` priced from the
same per-model usage rows `aggregate()` uses (the header used to render a
Expand All @@ -211,7 +211,7 @@ Every turn body is passed through `maskSecrets` (`usage-index.mjs:196` — the
23 secret shapes) **server-side, before
serialization**, then length-capped at `MAX_TURN_CHARS` (40,000,
`usage-index.mjs:77`) with the marker appended
(`usage-index.mjs:1477-1487`). Two invariants:
(`usage-index.mjs:1530-1540`). Two invariants:

- **Presence is the signal.** `truncated`/`originalChars` are emitted only
when the slice fired, so a complete turn cannot be misread as abridged.
Expand Down
15 changes: 15 additions & 0 deletions docs/UPGRADING.md
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,21 @@ sources establish facts with observed, configured, inferred, or unknown provenan
not silently create, adopt, or rewrite these bindings, and credentials remain environment-only.
See [ADR-0016](adr/0016-capability-driven-integration-adapters.md).

## `ak system --json` fields removed in 4.0.0-alpha.41

Two fields left the runtime census. If you parse `ak system --json` (or `GET /api/system`), read
them defensively or drop them:

| Removed | Where | Why |
|---|---|---|
| `runtime.daemons.budget` | daemon census | No local source exists for ruflo's launch budget — not circumstantially, structurally — so the field could only ever read `unknown`. A permanently unknowable quantity is removed rather than reported as degraded ([ADR-0023](adr/0023-fail-closed-operations-and-explicit-degradation.md) §9). `ruflo daemon budget` remains the way to ask. |
| `runtime.childProcessCount` | runtime census | Still counted by the process survey — it is what makes the per-host rows correct — but no longer republished. As a rendered figure it was a bare number with no denominator, no history and no action attached. |

Nothing else was removed. `storage.topSessions` rows **gained** `projectLabel` and
`projectResolved`; the raw `project` key is unchanged. `catalog.items` now also covers
project-scoped `.claude/skills|agents|commands` across every project on disk, so the list is
longer — the shape is identical and deduplication by `(kind, name)` is unchanged.

## QE-Court configs created before agentic-qe 3.13.3

`agentic-qe` 3.13.3 fixed its shipped QE-Court default and made configuration validation
Expand Down
Loading
Loading