Atlas / Skills / centminmod / Session Metrics

Session MetricsBLOCK

skills/centminmod/session-metrics

Shared starter template configuration and CLAUDE.md memory bank system for Claude Code

Verdict
BLOCK
Grade
D
Trust score
68 /100
Version
—
Hosts
3 documented
License
MIT
Stars
2,657
01

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

Read from source at commit 279fe3d84db5OBSERVED · 2026-10-08
02

Install

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-myapp
uv run python ${CLAUDE_SKILL_DIR}/scripts/session-metrics.py --list
uv run python ${CLAUDE_SKILL_DIR}/scripts/session-metrics.py --project-cost
uv run python ${CLAUDE_SKILL_DIR}/scripts/session-metrics.py --quiet --output json
03

Host compatibility

What the documentation claims. We have not run a compatibility test.

HostStatusNotes
claude-codementioned
codexmentioned
cursormentioned
04

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` |
05

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.

LayerWhat it checksResult
L0Provenance & inventoryPASS
L1Static analysis of the codeFAIL
L2Instruction surface (what it tells the agent)PASS
L3Class-specific surfacePASS
L4Behavioural (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)

HIGHCode injection · code.deserialize · CWE-78, CWE-94, CWE-95
scripts/_data.py:392
return pickle.load(fh)
Why it matters. deserialises untrusted bytes into live objects
Fix. use json or yaml.safe_load
HIGHCode injection · code.eval_exec · CWE-78, CWE-94, CWE-95
scripts/session_metrics_compare.py:1543
exec(src, ns)   # trusted skill-shipped code — no sandbox
Why it matters. evaluates text as code
Fix. remove; use a parser or a dispatch table
MEDIUMNetwork egress · net.beacon_words · CWE-200, CWE-319
scripts/_html_sections.py:4227
'<button data-theme="theme-beacon">Beacon</button>'
MEDIUMNetwork egress · net.beacon_words · CWE-200, CWE-319
scripts/_html_sections.py:4246
'if(!/^(beacon|console|lattice|pulse)$/.test(t))t="console";'
MEDIUMObfuscation / stealth · obf.homoglyph · CWE-506, CWE-94
scripts/session_metrics_compare.py:1884
hdr = (f"  {'#':>3}  {'A input':>8} {'B input':>8} {'Δin':>6}   "
MEDIUMObfuscation / stealth · obf.homoglyph · CWE-506, CWE-94
scripts/session_metrics_compare.py:1885
f"{'A out':>7} {'B out':>7} {'Δout':>6}   "
MEDIUMObfuscation / stealth · obf.homoglyph · CWE-506, CWE-94
scripts/session_metrics_compare.py:1886
f"{'A cost':>9} {'B cost':>9} {'Δcost':>6}{extras}")
LOWInsecure crypto · crypto.weak_hash · CWE-327, CWE-338
scripts/_data.py:358
path_hash = hashlib.sha1(abs_path.encode("utf-8")).hexdigest()[:8]
LOWInsecure crypto · crypto.weak_hash · CWE-327, CWE-338
scripts/_data.py:425
_ph = hashlib.sha1(_abs.encode("utf-8")).hexdigest()[:8]
LOWInsecure crypto · crypto.weak_hash · CWE-327, CWE-338
scripts/_turn_parser.py:517
return hashlib.sha1(canon.encode("utf-8")).hexdigest()[:16]
LOWInsecure crypto · crypto.weak_hash · CWE-327, CWE-338
scripts/session_metrics_compare.py:157
return hashlib.sha1(head.encode("utf-8")).hexdigest()
LOWObfuscation / stealth · obf.decode_call · CWE-506, CWE-94
scripts/vendor/charts/highcharts/v12/export-data.js:14
*/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
LOWObfuscation / stealth · obf.decode_call · CWE-506, CWE-94
scripts/vendor/charts/highcharts/v12/exporting.js:13
*/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
INFOPrompt injection · prompt.conditional_escalation · CWE-94, CWE-1427
SKILL.md:168
> **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.

Audited 2026-10-08 · audit v0.4.1 · source sha 279fe3d84db5full audit observations/trust-audit/skill/centminmod__session-metrics.json · Report an issue / request a re-scan
06

Audit history

Every audit this skill has had.

DateSourceVerdictGradeScoreChange
2026-10-08279fe3d84db5BLOCKD68first audit
07

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.

Advertisement