Skill v1.0.1
currentAutomated scan100/100+1 new
version: "1.0.1" name: telemetry license: MIT description: >- Unified telemetry hub. Shows current session cost, today's spend, all-time totals, hook activity, trust level, and a directory of every telemetry command available. Also the control surface to toggle telemetry on/off and tune thresholds. Single entry point for anyone asking "what does this cost" or "what telemetry does Citadel have". user-invocable: true auto-trigger: false trigger_keywords:
- telemetry
- what did this cost
- session cost
- how much did that cost
- how much have I spent
- what hooks fired
- trust level
- show me telemetry
- spending
- session stats
- what telemetry
- verify audit
- audit integrity
- check audit
- tampered records
last-updated: 2026-04-09
/telemetry — Telemetry Hub
When to Use
- "What does Citadel track?" / "What telemetry does it have?"
- "What did this session cost?" / "How much have I spent?"
- "How do I turn off the cost alerts?" / "Can I disable telemetry?"
- "Show me hook activity" / "What hooks fired?"
- "What trust level am I at?"
- Directly:
/telemetry
Routed here by /do for: "telemetry", "what did this cost", "session stats", "session cost", "how much did that cost", "what hooks fired", "trust level", "show me telemetry", "cost breakdown", "spending".
Commands
| Command | Behavior | |
|---|---|---|
/telemetry | Full hub — stats + command directory + settings | |
/telemetry --costs | Cost section only: session, today, all-time, by campaign | |
/telemetry --hooks | Hook activity only: last 20 fires with timing and outcomes | |
/telemetry --verify | Telemetry and artifact integrity check: verify hashes/signatures, flag tampered records, report legacy records | |
/telemetry --config | Show current telemetry settings from harness.json | |
/telemetry off | Disable session summary, reduce hook verbosity | |
/telemetry on | Re-enable all telemetry | |
/telemetry --threshold N | Set cost alert threshold step (e.g. --threshold 10 = alert every $10) |
Protocol
Step 1: COLLECT DATA
Read the following in parallel. All are optional — treat missing files as zero/empty.
Live session cost:
- Run
node scripts/session-tokens.js --today 2>/dev/null— captures real token data - If unavailable, read
.planning/telemetry/cost-tracker-state.jsonfor burn rate - Real cost is always preferred over estimated. Mark clearly:
$X.XXvs$X.XX (est)
Historical costs:
- Run
node scripts/session-tokens.js --all 2>/dev/nullfor all-time real totals - Read last 20 lines of
.planning/telemetry/session-costs.jsonlfor recent sessions - For each entry: prefer
real_cost>override_cost>estimated_cost
Hook activity:
- Read last 20 lines of
.planning/telemetry/hook-timing.jsonl - For each
event: "timing"entry: extracthook,duration_ms,timestamp - For each
event: "counter"entry: extracthook,metric - Check
.planning/telemetry/hook-errors.jsonl(last 20 lines) for recent blocks
Trust level:
- Read
.claude/harness.json→trustobject - Compute: novice (sessions < 5), familiar (5-19), trusted (20+ with 2+ campaigns)
- If
trust.overrideset, use that
Settings:
- Read
.claude/harness.json→telemetryobject - Show current values with defaults if missing
Step 2: RENDER HUB
Output this format. Omit a section only if the data source is completely unavailable.
=== Citadel Telemetry ===CURRENT SESSIONCost: $X.XX [real] | $X.XX (est)Duration: N min | $X.XX/min burn rateTokens: NNK input | NK output | NK cache read | NK cache writeMessages: NAgents: N spawnedHooks fired: N (today)TODAY$X.XX across N sessionsMost expensive: {slug or "unattached"} — $X.XXALL TIME$X.XX across N sessions, N campaignsCache savings: ~$X.XX (cache reads vs full input price)BY CAMPAIGN (recent 5){slug}: $X.XX — N sessions_unattached: $X.XX — N sessionsHOOK ACTIVITY (last 10 fires){relative time} | {hook} | {duration_ms}ms | {outcome}(no hook timing recorded yet)TRUST LEVELLevel: {novice | familiar | trusted}Sessions: N completedCampaigns: N completed(novice = 0-4 sessions | familiar = 5-19 | trusted = 20+ with 2+ campaigns)TELEMETRY SETTINGSEnabled: {true | false}Session summary: {auto | always | off} ← the [session] line at session endCost alerts: {on | off} at thresholds: {list or "default ($5,$15,$30...)"}Hook timing: {on | off}Audit log: {on | off}— or, when harness.json is absent —(harness.json not found — defaults active)→ Run /do setup to unlock cost tracking, configure thresholds, and register your install.COMMAND DIRECTORY/telemetry This screen/telemetry --costs Cost breakdown only/telemetry --hooks Hook activity only/telemetry --verify Telemetry/artifact integrity check (hash/signature verification)/cost Deep cost exploration by session/campaign/week/dashboard Full harness state (campaigns, fleet, all costs)node scripts/session-tokens.js --today Today's sessions with exact token countsnode scripts/session-tokens.js --all All-time totals (real data, not estimates)cat .planning/telemetry/session-costs.jsonl Raw session cost logcat .planning/telemetry/hook-timing.jsonl Raw hook execution logcat .planning/telemetry/audit.jsonl Raw tool call audit logCONTROLS/telemetry off Disable session summary + reduce verbosity/telemetry on Re-enable/telemetry --threshold N Alert every $N (writes to harness.json)/telemetry --config Edit settings interactively
Step 3: SUB-COMMAND HANDLING
`/telemetry off`: Set telemetry.sessionSummary = "off" and telemetry.costAlerts = false in harness.json. Output: "Telemetry summary disabled. Hook safety checks remain active." Safety hooks (protect-files, circuit-breaker, external-action-gate) are never disabled.
`/telemetry on`: Set telemetry.sessionSummary = "auto" and telemetry.costAlerts = true. Output: "Telemetry re-enabled."
`/telemetry --threshold N`: Validate N is positive. Generate [N, N*2, N*5, N*10, N*20, N*50, N*100] (capped at 500). Write to harness.json under policy.costTracker.thresholds.
`/telemetry --verify`: Run the project verifier:
node scripts/verify-telemetry-integrity.js
The verifier scans .planning/telemetry/*.jsonl and .planning/artifacts/*.jsonl. Display verified, signed, legacy, tampered, invalid, and signature-warning counts. Use --strict-legacy only when old unsigned records should fail the check.
Output format:
=== Telemetry Integrity ===file.jsonlTotal records: NVerified (hash): NVerified (signed): NLegacy (no hash): NTAMPERED: NInvalid JSON: NSignature warnings: NStatus: CLEAN or FAILED
If any tampered records: list each with timestamp, event, and both the stored and expected hash (first 16 chars each). Tampering can indicate log corruption, manual edits, or a bug — not necessarily malicious.
If only legacy records (no tampered): note "Legacy records were written before telemetry integrity hashing was added. New telemetry and artifact records are hashed automatically."
`/telemetry --config`: Show current settings with the node -e "..." command to change each — don't auto-apply.
Step 4: ACCURACY BADGES
Always mark data source clearly:
[real]— data from Claude Code's native session JSONL (exact)(est)— estimated from the fallback model ($1 base + $0.50/agent + $0.10/min)(override)— manually entered by the user
Never blend real and estimated in the same total without flagging it.
What Telemetry Covers
Covered: session cost (real token data), duration/burn rate/message count, agent spawn count, hook timing and outcomes, campaign cost attribution, trust level.
Not covered (by design): per-tool-call cost, per-subagent cost isolation, real-time streaming token count.
Safety hooks always on (cannot be disabled): protect-files, external-action-gate, circuit-breaker, quality-gate.
OTLP Export
The JSONL files under .planning/telemetry/ stay canonical. For standard observability stacks, scripts/telemetry-otlp-export.js translates new records into OTLP/HTTP JSON metrics and POSTs them to a collector. Byte offsets per source file live in .planning/telemetry/otlp-export-state.json, so repeat runs export only new records.
# Preview the OTLP payload without sending or advancing statenode scripts/telemetry-otlp-export.js --dry-run# Export new records to a local collector (/v1/metrics appended when the url has no path)node scripts/telemetry-otlp-export.js --endpoint http://localhost:4318
| Metric | Type | Source file | |
|---|---|---|---|
citadel.session.cost.usd | sum (delta), session.id / cost.source attributes | session-costs.jsonl | |
citadel.session.tokens | sum (delta), token.type attribute | session-costs.jsonl | |
citadel.hook.duration.ms | gauge, hook.name attribute | hook-timing.jsonl | |
citadel.agent.runs | sum (delta), run.status / run.event attributes | agent-runs.jsonl |
--reset clears the offsets for a full re-export. On a non-2xx response or network error the exporter exits 1 without advancing state, so the next run retries the same records. Data point timestamps come from the JSONL records, never the current clock. Test with node scripts/test-telemetry-otlp.js.
Local collector demo: examples/otel-collector/ contains a ready-made collector config (OTLP HTTP receiver on 4318, debug exporter to stdout) and a README with the two-command flow: docker run with the config mounted, then node scripts/telemetry-otlp-export.js --endpoint http://localhost:4318. Without Docker, --dry-run prints the exact OTLP payload instead.
Quality Gates
- Never show raw JSONL to the user — always parse and format
- Cost totals must be labeled with their source (real / est / mixed)
/telemetry offmust NOT disable safety hooks — make this explicit in output- Relative timestamps required — no raw ISO strings in output
- If all data sources are missing, show the empty-state version with setup hint
Fringe Cases
- `.planning/telemetry/` missing: Show empty state with "Run
/do setupto initialize telemetry." - `session-tokens.js` unavailable: Fall back to session-costs.jsonl; mark
(est). - harness.json missing: Show "(harness.json not found — defaults active)" and "→ Run /do setup to unlock cost tracking."
- `telemetry.enabled: false`: Show banner "Telemetry is disabled. Run
/telemetry onto re-enable." - `--verify` with missing files: Report "No telemetry or artifact JSONL files found." Not an error.
- `--verify` when `scripts/verify-telemetry-integrity.js` is unavailable: Report that the verifier is missing and show the raw file paths to inspect; do not claim hash verification ran.
Contextual Gates
Disclosure: Read-only by default. --threshold, off, on, --config write harness.json. Reversibility: amber — harness.json writes; undo with git checkout .claude/harness.json. Trust gates: Any — no restrictions.
Exit Protocol
/telemetry does not produce a HANDOFF block. It is a read-only observability tool (except for --threshold, off, on, --config which write harness.json). After displaying output, wait for the next user command.