Session MetricsBLOCK
Shared starter template configuration and CLAUDE.md memory bank system for Claude Code
Overview
From the repository's own README, as read at the audited commit. Badges and raw HTML are left out.
Files in this tree are checked into the repo so the HTML export works fully offline (no CDN round-trip, no runtime ~/.cache/ writes). manifest.json lists each file's expected SHA-256; session-metrics.py verifies the hash before inlining the JS (and CSS, for libraries that need it).
Layout
vendor/charts/ manifest.json — version, SHA-256, license per library highcharts/v12/ — non-commercial license (see LICENSE.txt) highcharts.js highcharts-3d.js exporting.js export-data.js uplot/v1/ — MIT (see LICENSE.txt) uPlot.iife.min.js uPlot.min.css chartjs/v4/ — MIT (see LICENSE.txt) chart.umd.js
Refreshing the vendored files
cd scripts/vendor/charts/highcharts/v12 for f in highcharts.js highcharts-3d.js; do curl -fsSL -o "$f" "https://cdn.jsdelivr.net/npm/highcharts@12/$f" done for f in exporting.js export-data.js; do curl -fsSL -o "$f" "https://cdn.jsdelivr.net/npm/highcharts@12/modules/$f" done shasum -a 256 *.js # update manifest.json with the new digests cd ../../uplot/v1 curl -fsSL -o uPlot.iife.min.js https://cdn.jsdelivr.net/npm/uplot@1/dist/uPlot.iife.min.js curl -fsSL -o uPlot.min.css https://cdn.jsdelivr.net/npm/uplot@1/dist/uPlot.min.css shasum -a 256 *.js *.css cd ../../chartjs/v4 curl -fsSL -o chart.umd.js https://cdn.jsdelivr.net/npm/chart.js@4/dist/chart.umd.js shasum -a 256 *.js
Bump the version directory (v12 → v13, etc.) if the major release changes; the script auto-discovers via the manifest.
Licenses
279fe3d84db5OBSERVED · 2026-10-08Install
Commands as the repository documents them. They are shown, not run.
uv run python ${CLAUDE_SKILL_DIR}/scripts/session-metrics.py --session ${CLAUDE_SESSION_ID}uv run python ${CLAUDE_SKILL_DIR}/scripts/session-metrics.py --session <uuid>uv run python ${CLAUDE_SKILL_DIR}/scripts/session-metrics.py --slug=-home-user-projects-myappuv run python ${CLAUDE_SKILL_DIR}/scripts/session-metrics.py --listuv run python ${CLAUDE_SKILL_DIR}/scripts/session-metrics.py --project-costuv run python ${CLAUDE_SKILL_DIR}/scripts/session-metrics.py --quiet --output jsonHost compatibility
What the documentation claims. We have not run a compatibility test.
| Host | Status | Notes |
|---|---|---|
| claude-code | mentioned | |
| codex | mentioned | |
| cursor | mentioned |
What it tells the agent
The instruction file, verbatim from the audited commit — this is the text the model reads, and the surface the audit's instruction layer examines. Quoted here so you can judge it without cloning anything.
---
name: session-metrics
effort: medium
description: >
Tally Claude Code session token usage and cost estimates from the raw JSONL
conversation log. Trigger when the user asks about session cost, token usage,
API spend, cache hit rate, input/output tokens, or wants a breakdown of how
much a Claude Code session has cost. Also trigger for "how much have we spent",
"show me token usage", "session summary", "cost so far", or any request to
analyse or display per-turn metrics from the current or a past session.
Do NOT auto-dispatch compare mode (--compare / --compare-prep / --compare-run
/ --count-tokens-only) from natural-language phrases. The skill body uses
$ARGUMENTS[0] as the dispatch key — if the first positional argument is not
literally "compare", "compare-prep", "compare-run", or "count-tokens", route
to the default single-session report.
---
# Session Metrics
Runs `scripts/session-metrics.py` against the Claude Code JSONL log to produce
a timeline-ordered cost summary with per-turn and cumulative totals.
## Dispatch — how to route this invocation
**First positional argument received:** `$ARGUMENTS[0]`
**Full argument string:** `$ARGUMENTS`
Read `$ARGUMENTS[0]` above and match it by **literal equality** against the
table below. Claude Code already tokenized the arguments shell-style, so no
parsing is required — just compare strings.
| `$ARGUMENTS[0]` | Route | Then read |
|---------------------|-------------------------------------------|-----------|
| `all-projects` | Instance-wide dashboard aggregating every project under `~/.claude/projects` | `## Instance dashboard (all projects)` below |
| `compare` | Two-session compare on JSONLs that already exist | `## Model comparison` below, then [`references/model-compare.md`](references/model-compare.md) before running |
| `compare-run` | Fully automated capture: spawns two `claude -p` sessions, feeds the suite, then runs `--compare` | `## Model comparison` below, then [`references/model-compare.md`](references/model-compare.md) "Workflow A — automated" |
| `compare-prep` | Print manual capture protocol + 10-prompt suite (fallback when headless is unavailable) | `## Model comparison` below |
| `count-tokens` | API-key-only tokenizer check | `## Model comparison` below |
| `export` | Natural-language export shortcut — scan full arg string to determine session vs project scope | `## Export shortcuts` below |
| `project` | All sessions for the current project — timeline + per-session subtotals + grand total | `## Quick usage` below (`--project-cost`); also scan remaining args for `--output` format flags |
| `project-cost` | Alias for `project` | `## Quick usage` below (`--project-cost`); also scan remaining args for `--output` format flags |
| *(empty, or any other value)* | Default single-session report | `## Quick usage` below |
This is the single gate that keeps compare mode off the natural-language
path. **Do not infer the route from the user's chat history; only use the
literal value of `$ARGUMENTS[0]` above.**
When the skill auto-triggers from a natural-language question ("how much did
this session cost?", "show me token usage"), there are no positional
arguments — `$ARGUMENTS[0]` is empty — and you always route to the default.
Phrases like "compare 4.6 vs 4.7 cost" arriving as natural language do NOT
produce `$ARGUMENTS[0] = compare` and must not route into compare mode;
answer them by running the default report on the current session and
suggesting `/session-metrics compare-prep` if the user wants a real
benchmark.
## Pre-flight context
- skill-dir: ${CLAUDE_SKILL_DIR}
- session-id: ${CLAUDE_SESSION_ID}
## Export shortcuts
Reached when `$ARGUMENTS[0]` is `export`. Scan the **full argument string** (not just `$ARGUMENTS[0]`) to determine scope and formats. Apply these checks **in order** (first match wins):
1. Full arg string contains `all-projects` → `--all-projects --output <formats>`
2. Full arg string contains `project` (and not already caught above) → `--project-cost --output <formats>`
3. Otherwise → current session `--session ${CLAUDE_SESSION_ID} --output <formats>`
Infer format flags from the argument string: `html` → `html`, `csv` → `csv`, `md` or `markdown` → `md`. Always add `json` alongside any requested format per the post-export audit convention (see `## Optional post-export audit` below).
**Always add `--quiet` to session and project export commands.** When exporting, the per-turn detail lives in the written HTML/JSON, so the full stdout timeline is redundant — and at project scope (or for a long session) it can run to thousands of lines, spilling the run into a harness overflow file that buries the `[export]` path lines you need. `--quiet` collapses stdout to the legend + grand total + footer (plus the `[export]` lines), keeping the run inline. Do **not** add `--quiet` for `--all-projects` — its instance dashboard text is already compact and the flag has no effect there.
**Examples:**
| Full argument string | Command |
|---|---|
| `export session` | `--session ${CLAUDE_SESSION_ID} --quiet --output json` |
| `export session to html` | `--session ${CLAUDE_SESSION_ID} --quiet --output html json` |
| `export session metrics to html` | `--session ${CLAUDE_SESSION_ID} --quiet --output html json` |
| `export to html` | `--session ${CLAUDE_SESSION_ID} --quiet --output html json` |
| `export project` | `--project-cost --quiet --output json` |
| `export project to html` | `--project-cost --quiet --output html json` |
| `export project sessions` | `--project-cost --quiet --output json` |
| `export project sessions to html` | `--project-cost --quiet --output html json` |
| `export entire project's session metrics to html` | `--project-cost --quiet --output html json` |
| `export project metrics to html csv` | `--project-cost --quiet --output html csv json` |
Trust audit
BLOCKgrade D · trust 68/100 Do not install this without reading the findings. The audit found something that could harm you or your machine.
| Layer | What it checks | Result |
|---|---|---|
| L0 | Provenance & inventory | PASS |
| L1 | Static analysis of the code | FAIL |
| L2 | Instruction surface (what it tells the agent) | PASS |
| L3 | Class-specific surface | PASS |
| L4 | Behavioural (sandbox) | SKIPPED |
What the source does
- Filesystem
- declared (1 observation(s))
- Network
- declared (8 observation(s))
- Shell
- declared (2 observation(s))
- Dependencies
- pinned
- Secrets in source
- none-found
Findings (14)
return pickle.load(fh)
exec(src, ns) # trusted skill-shipped code — no sandbox
'<button data-theme="theme-beacon">Beacon</button>'
'if(!/^(beacon|console|lattice|pulse)$/.test(t))t="console";'
hdr = (f" {'#':>3} {'A input':>8} {'B input':>8} {'Δin':>6} "f"{'A out':>7} {'B out':>7} {'Δout':>6} "f"{'A cost':>9} {'B cost':>9} {'Δcost':>6}{extras}")path_hash = hashlib.sha1(abs_path.encode("utf-8")).hexdigest()[:8]_ph = hashlib.sha1(_abs.encode("utf-8")).hexdigest()[:8]return hashlib.sha1(canon.encode("utf-8")).hexdigest()[:16]return hashlib.sha1(head.encode("utf-8")).hexdigest()*/function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e(t._Highcharts,t._Highcharts.AST,t._Highcharts.Chart):"function"==typeof define&&define.amd?define("highcharts/modules*/function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t(e._Highcharts,e._Highcharts.AST,e._Highcharts.Chart):"function"==typeof define&&define.amd?define("highcharts/modules> **Invocation note for the AI.** Don't pass `--tz` or `--utc-offset` unless the user explicitly asks for a specific timezone. The script auto-detects the user's system tz and renders all human-facing
Gates applied: no_behavioural_pass.
279fe3d84db5full audit observations/trust-audit/skill/centminmod__session-metrics.json · Report an issue / request a re-scanAudit history
Every audit this skill has had.
| Date | Source | Verdict | Grade | Score | Change |
|---|---|---|---|---|---|
| 2026-10-08 | 279fe3d84db5 | BLOCK | D | 68 | first audit |
Questions
What does the Session Metrics skill do?
Shared starter template configuration and CLAUDE.md memory bank system for Claude Code
Is Session Metrics safe to install?
No — not without reading the findings first. The audit graded it D (68/100) and found 2 critical or high issues in the source. Each one is listed on this page with the file and line it is on.
What can Session Metrics access on my machine?
The audit observed that it reaches the network, runs shell commands and reads or writes files. Each of those is consistent with what it says it does. Secrets in the source: none found.
Which assistants does Session Metrics work with?
Its documentation mentions claude-code, codex and cursor. That is what the text claims, not a compatibility test we ran.
How current is this page?
The grade is for one exact copy of the source (279fe3d84db5), read on 2026-10-08. The repository is watched, and a new audit runs when it changes — this is the first audit.