From 26b44d9e73160d1a1593d533d529b610ba2bb3c2 Mon Sep 17 00:00:00 2001 From: James Brink Date: Fri, 15 May 2026 19:45:18 -0700 Subject: [PATCH] docs: sync website + README + CLAUDE.md with current code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Bump documented schema_version from 2 → 3 (matches src/index.rs). - Add src/stats.rs to the modules table in CLAUDE.md and architecture.md. - Drop completions from the src/commands/*.rs list — it's a helper in main.rs, not a module file. - Add codex to the README subcommands table as a hyperlink. - Tighten guide/index.md "Every read command" claims so they correctly call out that models/turns/prs/files are index-only and codex reads ~/.codex directly without touching the Claude Code index. - Note in CLAUDE.md that codex is the single exception to the index pipeline and list the actual state file (state_5.sqlite). --- CLAUDE.md | 6 ++++-- README.md | 2 +- website/guide/architecture.md | 19 ++++++++++--------- website/guide/index.md | 14 +++++++++++--- 4 files changed, 26 insertions(+), 15 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 1fc02b2..eefcedd 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -137,7 +137,7 @@ All documented in `website/guide/installation.md`: ▼ store::SessionStore (discovery + path decoding) ▼ parser::parse_session / stream_records (streaming JSONL → SessionStats) ▼ -~/.claudex/index.db (SQLite, schema_version=2, created on demand) +~/.claudex/index.db (SQLite, schema_version=3, created on demand) │ ▼ index::IndexStore::ensure_fresh / sync_now / force_rebuild ▼ @@ -151,9 +151,10 @@ commands::::run → stdout (tables + palette via ui module, JSON via --j - `src/store.rs` — locates session files, decodes project directory names (`/.hidden` ↔ `--hidden`, `/seg` ↔ `-seg`), and canonicalises worktree paths (`…/.claude/worktrees/` aggregates to the parent project). `SessionStore::at(path)` is a test-only constructor. - `src/parser.rs` — `SessionStats` accumulator; `stream_records` reads JSONL one record at a time so large sessions don't balloon memory. - `src/types.rs` — `TokenUsage` and `ModelPricing` (Opus/Sonnet/Haiku pricing tiers; default is Sonnet). `cost_for_model` is the single source of truth for pricing math. +- `src/stats.rs` — small numeric helpers shared across commands (e.g. `percentile_sorted` used by `turns` and the session drill-down). - `src/index.rs` — `IndexStore` (SQLite via `rusqlite`, bundled). Tables: `sessions`, `token_usage`, `tool_calls`, `turn_durations`, `pr_links`, `file_modifications`, `thinking_usage`, `stop_reasons`, `attachments`, `permission_changes`, plus an FTS virtual table `messages_fts`. Incremental sync keys on `(file_path, file_size, file_mtime)`. `IndexStore::open_at(path)` is a test-only constructor. - `src/ui.rs` — **single home for every presentation concern**: palette (semantic helpers like `project`, `cost`, `cell_project`, `cell_cost`), `table()` builder (minimal style, dynamic width via `terminal_size`), `Spinner` (TTY-gated, stderr), number formatters (`fmt_cost` → `$12,345.67` with sub-cent fallback to 4 decimals, `fmt_count` → `326,297`), and `ColorChoice` / `apply_color_choice`. -- `src/commands/*.rs` — one module per subcommand: `sessions`, `cost`, `search`, `tools`, `watch`, `summary`, `export`, `index`, `turns`, `prs`, `files`, `models`, `update`, `completions` (via helper in `main.rs`). +- `src/commands/*.rs` — one module per subcommand: `sessions`, `session`, `cost`, `search`, `tools`, `watch`, `summary`, `export`, `index`, `turns`, `prs`, `files`, `models`, `update`, `codex`. (`completions` is generated by a helper directly in `main.rs`, not a module here.) - `tests/index_tests.rs` — unit-style tests against parser/types/store. - `tests/index_store_tests.rs` — integration tests against every `IndexStore` query method using `TempDir` + `open_at`/`at`. - `tests/cli_tests.rs` — end-to-end subprocess tests against the compiled binary with a fixture `$HOME`. Exercises every subcommand's indexed and `--no-index` paths, JSON and text output, and the `--color` flag. @@ -166,6 +167,7 @@ commands::::run → stdout (tables + palette via ui module, JSON via --j - **Schema migrations**: bumping `SCHEMA_VERSION` in `src/index.rs` triggers a rebuild on next open. Add new columns/tables inside the `CREATE TABLE IF NOT EXISTS` block and bump the version. - **Worktree aggregation**: always key on `canonical_project_path(&decoded)` when grouping by project, and use `display_project_name` for user-facing labels (renders worktree sessions as `"projectname (worktree)"`). - **Pricing math lives in `types.rs`**. Do not inline per-token multipliers in commands — call `TokenUsage::cost_for_model` so the Opus/Sonnet/Haiku tiers stay consistent. +- **`codex` is the one exception to the index pipeline.** It scans `~/.codex/sessions/**` (and `~/.codex/archived_sessions/`) directly on every invocation, plus an optional read-only open of `~/.codex/state_5.sqlite` and `~/.codex/session_index.jsonl` — no `~/.claudex/` writes, no `--no-index` flag, no staleness window. Keep it that way unless you also build a parallel ingest path; do not silently route Codex data through `IndexStore`. ### Adding a new subcommand diff --git a/README.md b/README.md index 1039447..a0d2942 100644 --- a/README.md +++ b/README.md @@ -65,7 +65,7 @@ Source builds require Rust 1.95+. Prebuilt binaries have no runtime dependencies | Command | What it does | | ------------------------------------------------------------------------- | ------------------------------------------------------------------------- | | [`summary`](https://utensils.io/claudex/commands/summary) | Dashboard — sessions, cost, top projects/tools, model mix | -| `codex` | Codex CLI session/state stats from `~/.codex` | +| [`codex`](https://utensils.io/claudex/commands/codex) | Codex CLI session/state stats from `~/.codex` | | [`sessions`](https://utensils.io/claudex/commands/sessions) | List sessions grouped by project | | [`session `](https://utensils.io/claudex/commands/session) | Drill into one session: cost, tools, files, PRs, turns, stop reasons | | [`cost`](https://utensils.io/claudex/commands/cost) | Token usage and approximate cost per project or per session | diff --git a/website/guide/architecture.md b/website/guide/architecture.md index 1cab6c1..a0bd2fc 100644 --- a/website/guide/architecture.md +++ b/website/guide/architecture.md @@ -25,15 +25,16 @@ ui::table() / palette — comfy-table with dynamic width + owo-colors ## Modules -| Module | Purpose | -| ------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `src/main.rs` | clap parser, dispatches to `commands::*::run`. Pre-parses `--color` from argv before `Cli::parse()` so clap-generated help/errors honor the flag. | -| `src/store.rs` | Locates session files, decodes project-directory names (`/.hidden` ↔ `--hidden`, `/seg` ↔ `-seg`), canonicalizes worktree paths (`…/.claude/worktrees/` aggregates to the parent project). | -| `src/parser.rs` | `SessionStats` accumulator; `stream_records` reads JSONL one record at a time. | -| `src/types.rs` | `TokenUsage`, `ModelPricing` (Opus/Sonnet/Haiku tiers). `cost_for_model` is the single source of truth for pricing math. | -| `src/index.rs` | `IndexStore` (SQLite). Relational report tables plus an FTS5 virtual table. Incremental sync keyed on `(file_path, file_size, file_mtime)`. | -| `src/ui.rs` | Palette, `table()` builder, number formatters (`fmt_cost`, `fmt_count`), `Spinner`, `ColorChoice`. Everything presentation. | -| `src/commands/*.rs` | One file per subcommand: `sessions`, `cost`, `search`, `tools`, `watch`, `summary`, `session`, `export`, `index`, `turns`, `prs`, `files`, `models`, `codex`, `update`, `completions`. | +| Module | Purpose | +| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `src/main.rs` | clap parser, dispatches to `commands::*::run`. Pre-parses `--color` from argv before `Cli::parse()` so clap-generated help/errors honor the flag. | +| `src/store.rs` | Locates session files, decodes project-directory names (`/.hidden` ↔ `--hidden`, `/seg` ↔ `-seg`), canonicalizes worktree paths (`…/.claude/worktrees/` aggregates to the parent project). | +| `src/parser.rs` | `SessionStats` accumulator; `stream_records` reads JSONL one record at a time. | +| `src/types.rs` | `TokenUsage`, `ModelPricing` (Opus/Sonnet/Haiku tiers). `cost_for_model` is the single source of truth for pricing math. | +| `src/stats.rs` | Small numeric helpers shared across commands — `percentile_sorted` powers the p50/p95/max columns in `turns` and the per-session drill-down. | +| `src/index.rs` | `IndexStore` (SQLite). Relational report tables plus an FTS5 virtual table. Incremental sync keyed on `(file_path, file_size, file_mtime)`. | +| `src/ui.rs` | Palette, `table()` builder, number formatters (`fmt_cost`, `fmt_count`), `Spinner`, `ColorChoice`. Everything presentation. | +| `src/commands/*.rs` | One file per subcommand: `sessions`, `cost`, `search`, `tools`, `watch`, `summary`, `session`, `export`, `index`, `turns`, `prs`, `files`, `models`, `codex`, `update`. (`completions` is generated by a helper in `main.rs`, not a module here.) | ## Key invariants diff --git a/website/guide/index.md b/website/guide/index.md index 43837b4..493b7dd 100644 --- a/website/guide/index.md +++ b/website/guide/index.md @@ -24,12 +24,20 @@ questions of_. Every read command: -- Uses the index by default (incremental sync, 5-minute staleness window). -- Supports `--no-index` to bypass the index and scan JSONL files directly — the - fallback path always matches the indexed path. - Supports `--json` to emit a stable, machine-readable shape. - Honors `--color auto|always|never` (and `NO_COLOR`) for color output. +Most Claude Code reports also: + +- Use the index by default (incremental sync, 5-minute staleness window). +- Support `--no-index` to bypass the index and scan JSONL files directly — the + fallback path always matches the indexed path. + +Two caveats: `models`, `turns`, `prs`, and `files` are derived from the index +only and don't accept `--no-index`. And `claudex codex` is a separate reader — +it scans `~/.codex/` directly and never touches the Claude Code index. See the +[flag support matrix](/commands/) for the per-command breakdown. + ## Who is it for? You already use Claude Code and want to: