ckforensics 0.2.1 → 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,206 @@
1
+ ---
2
+ name: ck:forensics
3
+ description: "Forensic analysis of Claude Code sessions — token cost, context map, audit manifest, skill recommendations. Use when user asks 'what did Claude touch', 'where did my tokens go', 'how much did this session cost', 'show last session', 'what skill should I have used', or wants post-hoc review of CC work."
4
+ category: dev-tools
5
+ keywords: [claude-code, audit, forensics, observability, token-cost, context, skill-recommender, session-review]
6
+ argument-hint: "summary|sessions|audit|map|suggest|skills|ingest [args]"
7
+ metadata:
8
+ author: phong28zk
9
+ version: "0.2.1"
10
+ upstream: "https://github.com/phong28zk/ckforensics"
11
+ ---
12
+
13
+ # ck:forensics — Claude Code Session Forensics
14
+
15
+ Read-only post-hoc analysis of `~/.claude/projects/**/*.jsonl` transcripts. Surfaces:
16
+ - **What was burned:** tokens, $, time, by tool/skill/file
17
+ - **What changed:** files touched, diff, reasoning trail, subagent attribution
18
+ - **What lives in context:** heatmap of items by category (tool_result, message, ...)
19
+ - **What you missed:** skills that would have replaced repeated manual sequences
20
+
21
+ Powered by the `ckforensics` CLI (npm `ckforensics@^0.2.1`). Local-only, no telemetry.
22
+
23
+ ---
24
+
25
+ ## Default (No Arguments)
26
+
27
+ If invoked without arguments, use `AskUserQuestion` to present operations:
28
+
29
+ | Operation | Description |
30
+ |-----------|-------------|
31
+ | `summary` | Token + cost rollup (last 7d default) |
32
+ | `sessions` | List recent sessions with cost/duration |
33
+ | `audit` | Per-session change manifest (files, diff, reasoning) |
34
+ | `map` | Context-window heatmap (what eats tokens?) |
35
+ | `suggest` | Skills that would have helped (pattern detection) |
36
+ | `skills` | List/search indexed skills with usage stats |
37
+ | `ingest` | Refresh DB from `~/.claude/projects/` |
38
+
39
+ Present via `AskUserQuestion` with header "Forensics" and question "Which analysis?".
40
+
41
+ ---
42
+
43
+ ## Installation Check
44
+
45
+ Before running any command, ensure CLI is installed:
46
+
47
+ ```bash
48
+ command -v ckforensics >/dev/null || {
49
+ echo "ckforensics not installed. Install with: npm i -g ckforensics"
50
+ exit 1
51
+ }
52
+ ```
53
+
54
+ If missing, ask user to install before proceeding.
55
+
56
+ ---
57
+
58
+ ## Workflows
59
+
60
+ | Workflow | Reference |
61
+ |----------|-----------|
62
+ | End-of-day session review | `references/workflow-eod.md` |
63
+ | Pre-commit audit | `references/workflow-pre-commit.md` |
64
+ | Weekly cost retro | `references/workflow-weekly-retro.md` |
65
+ | Command reference | `references/commands.md` |
66
+ | Output interpretation | `references/interpretation.md` |
67
+
68
+ ---
69
+
70
+ ## Core Commands
71
+
72
+ ### `summary [--days N]`
73
+
74
+ Token/cost rollup. Default 7 days.
75
+
76
+ ```bash
77
+ ckforensics summary # last 7 days
78
+ ckforensics summary --days 1 # today
79
+ ckforensics summary --days 30 # this month
80
+ ckforensics summary --json # for piping to jq
81
+ ```
82
+
83
+ **Cost interpretation:** API-rate equivalent. Subscription users (Pro/Max) pay flat fee — treat as "value extracted", not actual bill. See `references/interpretation.md`.
84
+
85
+ ### `audit [--last|<session-id>] [--out FILE]`
86
+
87
+ Per-session change manifest:
88
+ - Header (model, duration, cost, total events)
89
+ - Files changed (with chronological edits + reasoning quotes)
90
+ - Subagent dispatches + recursive cost breakdown
91
+ - Reasoning correlator: each tool call linked to preceding assistant text
92
+
93
+ ```bash
94
+ ckforensics audit --last # most recent session
95
+ ckforensics audit <session-id> --out review.md # for PR review
96
+ ckforensics audit --last --format json | jq # script-friendly
97
+ ```
98
+
99
+ ### `map [--last|<session-id>] [--top N]`
100
+
101
+ Context-window heatmap. Shows what categories eat the most tokens:
102
+ - `tool:Bash` → shell output
103
+ - `tool:Read` / `tool:Edit` → file ops
104
+ - `assistant` / `user` → messages
105
+ - `unknown` → unattributable
106
+
107
+ Use `--simulate-compact` to project what survives next auto-compact.
108
+
109
+ ```bash
110
+ ckforensics map --last --top 20
111
+ ckforensics map --simulate-compact --target-pct 50
112
+ ```
113
+
114
+ ### `suggest [--session ID|--last|--days N] [--min-confidence 70]`
115
+
116
+ Skill recommendations: detects repeated tool patterns and matches against `~/.claude/skills/` catalog. Suggests skills that would have replaced manual work.
117
+
118
+ ```bash
119
+ ckforensics suggest --last # for most recent session
120
+ ckforensics suggest --days 7 --min-confidence 30 # weekly retro
121
+ ```
122
+
123
+ ### `sessions [--project SLUG] [--limit N]`
124
+
125
+ List recent sessions with cost/duration. Filter by project.
126
+
127
+ ```bash
128
+ ckforensics sessions --limit 10
129
+ ckforensics sessions --project ckforensics --limit 50
130
+ ```
131
+
132
+ ### `skills [--unused|--used] [--search QUERY] [--refresh]`
133
+
134
+ List indexed skills. `--unused` shows skills you have but never invoked. Discoverability tool.
135
+
136
+ ```bash
137
+ ckforensics skills --refresh # re-scan ~/.claude/skills/
138
+ ckforensics skills --unused | head # what am I missing?
139
+ ```
140
+
141
+ ### `ingest`
142
+
143
+ Refresh DB from `~/.claude/projects/`. Incremental — only new jsonl content.
144
+
145
+ ```bash
146
+ ckforensics ingest # one-shot
147
+ ckforensics ingest --watch # poll every 5s
148
+ ```
149
+
150
+ ---
151
+
152
+ ## When to Use This Skill
153
+
154
+ **After CC session:** Run `audit --last` to review what Claude changed.
155
+
156
+ **Cost review:** Run `summary` to see token burn vs subscription value.
157
+
158
+ **Habit improvement:** Run `suggest --days 7` weekly to find skill opportunities.
159
+
160
+ **Context optimization:** Run `map --last` when session hits compaction wall — see what eats tokens.
161
+
162
+ **Pre-commit:** Run `audit --last --out review.md` then `redact review.md --in-place` before sharing.
163
+
164
+ ---
165
+
166
+ ## Output Interpretation
167
+
168
+ | Pattern | Meaning |
169
+ |---------|---------|
170
+ | `tool:Bash` >40% of map | Heavy shell output; consider piping to `tail`/`head` |
171
+ | `tool:Read` repeats on same dir | `/ck:scout` candidate |
172
+ | Subagent cost > main cost | Runaway subagent — review prompt scope |
173
+ | Cost in red (>$10) | High-value session; worth saving manifest for retro |
174
+ | Suggest confidence <50% | Probably noise; only act on ≥70% |
175
+
176
+ See `references/interpretation.md` for full guide.
177
+
178
+ ---
179
+
180
+ ## Important Notes
181
+
182
+ - **All operations are read-only.** Never modifies `~/.claude/projects/`.
183
+ - **Cost is API-rate estimate** (Nov 2025 Anthropic pricing); subscription users see flat fee.
184
+ - **±20% attribution margin** on context map (heuristic-based).
185
+ - **Cache local at** `~/.local/share/ckforensics/store.db` (mode 0600).
186
+ - **Logs at** `~/.local/state/ckforensics/logs/` (Linux), `~/Library/Logs/ckforensics/` (macOS).
187
+
188
+ ## Token Efficiency
189
+
190
+ - Activate `ck:context-engineering` skill if running `audit` or `map` on very long sessions (output can be 100k+ tokens of markdown — pipe to file).
191
+ - Use `--json` for downstream tools; avoids markdown formatting overhead.
192
+ - For routine ingest, cron handles it: `0 * * * * ckforensics ingest >> ~/.local/state/ckforensics/logs/ingest.log 2>&1`.
193
+
194
+ **Sacrifice grammar for concision when reporting findings to user.**
195
+
196
+ ---
197
+
198
+ ## Quick Start (User's First Run)
199
+
200
+ ```bash
201
+ npm i -g ckforensics # install
202
+ ckforensics doctor # verify
203
+ ckforensics ingest # populate DB (~20s for 1000+ jsonl)
204
+ ckforensics summary # see weekly totals
205
+ ckforensics audit --last | head -50 # review last session
206
+ ```
@@ -0,0 +1,108 @@
1
+ # ck:forensics — Command Reference
2
+
3
+ Quick reference for every `ckforensics` subcommand exposed via `/ck:forensics`.
4
+
5
+ ## Global flags
6
+
7
+ | Flag | Default | Description |
8
+ |------|---------|-------------|
9
+ | `--db <path>` | XDG data dir | Override SQLite path |
10
+ | `--no-color` | off | Disable ANSI |
11
+ | `-v, --verbose` | off | Info-level logging to stderr |
12
+ | `--debug` | off | Debug-level logging |
13
+ | `--log-dir <path>` | XDG state dir | Override log dir |
14
+ | `--json` | off | Force JSON output globally |
15
+
16
+ ## Subcommands
17
+
18
+ ### `summary [--days N] [--format text|md|json]`
19
+
20
+ Aggregate token/cost/files across a rolling window.
21
+
22
+ **Output fields:**
23
+ - `sessionCount`
24
+ - `totalInputTokens`, `totalOutputTokens`, `totalCacheRead`, `totalCacheCreate`
25
+ - `estimatedCostUsd` (API-rate equivalent)
26
+ - `filesTouched`, `editOps`
27
+ - `oldestSession`, `newestSession`
28
+
29
+ ### `sessions [--project SLUG] [--limit N] [--format text|md|csv|json]`
30
+
31
+ List recent sessions ordered by `started_at DESC`.
32
+
33
+ **Columns:** ID, Project, Started, Model, Events, Cost, Duration
34
+
35
+ Cost color-coded: red >$10, yellow $1-10, green <$1, dim — for null.
36
+
37
+ ### `audit [<session-id>|--last] [--out FILE] [--format md|json]`
38
+
39
+ Per-session change manifest.
40
+
41
+ **Sections:**
42
+ 1. Header (session ID, project, model, duration, cost, total events)
43
+ 2. Summary (files changed, lines +/-, edit ops, tokens, cache read)
44
+ 3. File Changes (chronological edits, reasoning quotes, unified diff)
45
+ 4. Subagent Dispatches (each Agent() / Task() with input + duration)
46
+ 5. Subagent Cost Breakdown (nested table with tokens + cost per agent)
47
+
48
+ Exit codes: 0 success, 3 session not found.
49
+
50
+ ### `map [<session-id>|--last] [--top N=20] [--simulate-compact] [--target-pct N=50]`
51
+
52
+ Context window heatmap by category.
53
+
54
+ **Categories:** `tool:<Name>`, `assistant`, `user`, `system_prompt`, `memory`, `skill_load`, `unknown`
55
+
56
+ Each row: ASCII bar + percentage + token count + item count.
57
+
58
+ **`--simulate-compact`:** projects which items survive next auto-compact based on documented heuristic.
59
+
60
+ **Sub-commands:**
61
+ - `ckforensics map --save NAME` — persist snapshot
62
+ - `ckforensics map list` — list saved snapshots
63
+ - `ckforensics map diff <A> <B>` — token movement between snapshots
64
+ - `ckforensics map --pin ITEM_ID --emit-manifest [FILE]` — pinned items → paste-ready markdown
65
+
66
+ ### `suggest [<session-id>|--last|--days N=7] [--min-confidence N=70] [--top N=3] [--format text|md|json]`
67
+
68
+ Detect repeated tool patterns and recommend skills.
69
+
70
+ **Patterns detected:**
71
+ - `read-fanout`: ≥5 Reads within 3 adjacent turns on same dir
72
+ - `test-loop`: ≥3 Bash test runs
73
+ - `manual-diff-cycle`: read→edit→read ≥2 cycles
74
+ - `grep-walk`: ≥4 Grep+Read pairs
75
+ - `subagent-skip`: ≥20 main-thread tool calls, no Agent/Task
76
+
77
+ **Output per rec:** invocation hint (`/ck:scout`), confidence %, est savings (tokens + USD), evidence turns.
78
+
79
+ ### `skills [--unused|--used] [--search QUERY] [--refresh] [--format text|md|csv|json]`
80
+
81
+ List indexed skills from `~/.claude/skills/`.
82
+
83
+ - `--refresh` — re-scan SKILL.md frontmatter
84
+ - `--unused` — show skills you've never invoked
85
+ - `--used` — show skills you've activated, with usage count
86
+ - `--search "pattern"` — keyword search
87
+
88
+ ### `ingest [--watch]`
89
+
90
+ Parse `~/.claude/projects/**/*.jsonl` → SQLite. Idempotent + incremental.
91
+
92
+ - `--watch` polls every 5s (for cron alternative)
93
+
94
+ ### `redact <file> [--in-place] [--force]`
95
+
96
+ Apply 9 redaction rules (sk-ant, GH tokens, AWS, JWT, etc.) to a markdown/text file. Use before sharing audit exports.
97
+
98
+ ### `export <view> --format md|json|csv [--out FILE]`
99
+
100
+ Pipe-friendly export: `summary`, `sessions`, `audit`.
101
+
102
+ ### `doctor`
103
+
104
+ Health check: DB exists + version, JSONL dir readable, last ingest mtime, log dir writeable, Bun version.
105
+
106
+ ### `path`
107
+
108
+ Print resolved paths (DB, data dir, JSONL source, log dir, config dir).
@@ -0,0 +1,81 @@
1
+ # ck:forensics — Output Interpretation Guide
2
+
3
+ How to read what ckforensics tells you, and when to act on it.
4
+
5
+ ## Cost interpretation
6
+
7
+ | Display | Meaning |
8
+ |---------|---------|
9
+ | `$X.XX` (green) | <$1 — typical small session |
10
+ | `$X.XX` (yellow) | $1-10 — substantive work |
11
+ | `$X.XX` (red) | >$10 — high-value session, worth saving manifest |
12
+ | `unknown` / `—` | Cost not estimable (missing model in DB, pre-pricing-fix) |
13
+ | `*` footnote | API-rate equivalent, not actual subscription bill |
14
+
15
+ **Two cost numbers compared:**
16
+ - ckforensics `Estimated Cost`: token count × Anthropic published rates
17
+ - CC live statusline: real-time `cost.total_cost_usd` from CC's internal calc
18
+
19
+ Discrepancy expected (CC may exclude some cache pricing). Within 30% = normal.
20
+
21
+ **For subscription users:** the cost number = "value extracted from your $X/mo plan", not a bill.
22
+
23
+ ## Map heatmap thresholds
24
+
25
+ | Pattern | Diagnostic | Action |
26
+ |---------|-----------|--------|
27
+ | `tool:Bash` >40% | Heavy shell output | Pipe to `head`/`tail`, redirect logs, or limit verbose flags |
28
+ | `tool:Read` >30% | Excessive file reads | Use `/ck:scout` for batched discovery |
29
+ | `tool:Edit` >30% | Lots of edits | Normal for code-heavy session; check for thrashing |
30
+ | `assistant` >40% | Very long replies | Verbose mode, summarisation overhead |
31
+ | `unknown` >10% | Attribution failure | Schema drift; report to ckforensics issues |
32
+
33
+ ## Suggest confidence brackets
34
+
35
+ | Confidence | Meaning | Action |
36
+ |------------|---------|--------|
37
+ | 80-100% | Strong signal, multi-pattern match | Try the skill next session |
38
+ | 60-80% | Plausible, single pattern | Worth reading description |
39
+ | 40-60% | Weak — likely keyword coincidence | Skip unless desperate |
40
+ | <40% | Noise | Ignore |
41
+
42
+ Default threshold = 70. Lower with `--min-confidence 30` if seeing no recs.
43
+
44
+ ## Audit manifest sections
45
+
46
+ ### Files changed
47
+
48
+ Each file shows chronological edits with reasoning quote. **Read the reasoning** — it's the assistant's intent text before the tool call, not post-hoc explanation. Useful for:
49
+ - Understanding *why* an edit was made
50
+ - Catching scope creep (intent vs action mismatch)
51
+ - Composing PR descriptions (reasoning often is the PR body)
52
+
53
+ ### Subagent Cost Breakdown
54
+
55
+ Nested table. Top-level rows = direct Agent()/Task() calls from main thread. Indented rows = nested (subagent inside subagent).
56
+
57
+ **Red flags:**
58
+ - Single subagent with >$5 cost in <10 tool calls = runaway
59
+ - "open" duration → subagent still running (session paused?)
60
+ - Many small subagents (≤2 calls each) = excessive fanout
61
+
62
+ ### Reasoning correlator
63
+
64
+ Each tool call gets a "Reasoning:" quote. If reasoning is empty/unhelpful:
65
+ - Assistant didn't narrate (rare)
66
+ - Tool fired in middle of multi-block message (correlator picks last text block)
67
+ - Subagent invocation (reasoning belongs to parent dispatch)
68
+
69
+ ## Sessions list signals
70
+
71
+ - Same project, multiple short sessions same day → context flushing too often
72
+ - Single 10+ hour session → consider checkpointing via context map
73
+ - Cost trending up week-over-week → instrument with `summary --days N`
74
+
75
+ ## When ingest finds nothing
76
+
77
+ If `ckforensics ingest` reports 0 new events:
78
+ 1. Check `ckforensics doctor` — last ingest mtime
79
+ 2. Verify `~/.claude/projects/` has recent jsonl: `ls -lt ~/.claude/projects/*/*.jsonl | head`
80
+ 3. CC may be on different config dir (CLAUDE_CONFIG_DIR env var) — set `--db` accordingly
81
+ 4. Force re-ingest from scratch: `rm ~/.local/share/ckforensics/store.db && ckforensics ingest`
@@ -0,0 +1,56 @@
1
+ # End-of-Day Session Review Workflow
2
+
3
+ Pattern: after a substantial Claude Code session, run forensics to know what shipped, what burned, what to remember.
4
+
5
+ ## Flow
6
+
7
+ ```
8
+ 1. ckforensics ingest # refresh DB
9
+ 2. ckforensics summary --days 1 # today's totals
10
+ 3. ckforensics audit --last --out eod.md # capture manifest
11
+ 4. ckforensics suggest --last # skills that would have helped
12
+ 5. ckforensics map --last --top 15 # what ate the context
13
+ ```
14
+
15
+ ## When Claude runs this skill
16
+
17
+ User says one of:
18
+ - "wrap up this session"
19
+ - "what did I do today"
20
+ - "end of day review"
21
+ - "summary of last session"
22
+ - "did Claude do anything weird"
23
+
24
+ ## What Claude should do
25
+
26
+ 1. Run the 5 commands above (or relevant subset).
27
+ 2. **Summarise**, don't paste raw output to user. Surface:
28
+ - Total cost (API-rate) + duration
29
+ - Top 3 files changed (by lines or by importance from reasoning quotes)
30
+ - Any subagent that cost >$1 (flag for review)
31
+ - Top 1-2 skill recommendations with confidence ≥70
32
+ - Context map insight: what ate most tokens
33
+ 3. **Offer next actions:**
34
+ - "Save audit manifest as PR description?" → use `eod.md`
35
+ - "Dismiss low-value skill recs?" → `~/.config/ckforensics/dismissed.json`
36
+ - "Schedule cron for daily ingest?" → crontab snippet
37
+
38
+ ## Example response template
39
+
40
+ ```
41
+ Today's session burned $X.XX over Y hours. Modified Z files (top: A, B, C).
42
+
43
+ Notable:
44
+ - Subagent "P11 log infra" cost $28 — runaway, worth reviewing
45
+ - Skill /ck:scout would have replaced 23× Read on src/audit/* (saves ~12k tokens)
46
+ - Context map: tool:Bash 40%, tool:Edit 16% — heavy shell + editing
47
+
48
+ Manifest saved to eod.md. Want me to draft a commit message from it?
49
+ ```
50
+
51
+ ## Anti-patterns
52
+
53
+ - ❌ Paste full audit markdown (1000+ lines) to user
54
+ - ❌ Run all 5 commands when user only asked "cost today"
55
+ - ❌ Recommend skills with confidence <70 without flagging confidence
56
+ - ❌ Skip subagent cost breakdown — that's the highest-signal section
@@ -0,0 +1,63 @@
1
+ # Pre-Commit Audit Workflow
2
+
3
+ Pattern: before user runs `git commit`, generate a manifest of what Claude touched and use it as commit/PR body draft.
4
+
5
+ ## Flow
6
+
7
+ ```
8
+ 1. ckforensics ingest # ensure DB current
9
+ 2. ckforensics audit --last --out review.md # capture this session's manifest
10
+ 3. ckforensics redact review.md --in-place # strip secrets before sharing
11
+ 4. (user opens review.md, copies relevant sections to commit body)
12
+ ```
13
+
14
+ ## When Claude runs this skill
15
+
16
+ User says one of:
17
+ - "ready to commit"
18
+ - "draft a commit message from this session"
19
+ - "what should the PR description say"
20
+ - "review what I just did before committing"
21
+
22
+ ## What Claude should do
23
+
24
+ 1. Run `audit --last` to get the manifest.
25
+ 2. Pipe through `redact` (always, never skip — secrets risk).
26
+ 3. Extract from manifest:
27
+ - **Files changed** + line counts (for `git diff --stat` equivalent)
28
+ - **Reasoning quotes** per file (often makes the PR body)
29
+ - **Subagent contributions** (mention if subagents did significant work)
30
+ 4. **Draft conventional commit**:
31
+ ```
32
+ <type>(<scope>): <subject>
33
+
34
+ <body — TLDR of what changed and why, from reasoning>
35
+
36
+ <body — files affected, key decisions>
37
+ ```
38
+ 5. **Surface anything suspicious:**
39
+ - Files touched in unexpected directories
40
+ - Reasoning that doesn't match the actions (intent drift)
41
+ - Subagents with high cost (worth mentioning in PR)
42
+
43
+ ## Integration with ck:git
44
+
45
+ After draft, hand off to `/ck:git cm` for execution:
46
+ ```
47
+ ckforensics audit --last --out review.md
48
+ ckforensics redact review.md --in-place
49
+ # Claude reads review.md, drafts commit message
50
+ # Hand to /ck:git cm — user reviews + executes
51
+ ```
52
+
53
+ Or pipe directly (v0.5 phase 12 will support this):
54
+ ```
55
+ ckforensics commit --phase last | ck:git cm --message-stdin
56
+ ```
57
+
58
+ ## Anti-patterns
59
+
60
+ - ❌ Skip redaction — manifests can contain edited file contents = secrets risk
61
+ - ❌ Paste raw manifest as commit body (too long, unstructured)
62
+ - ❌ Auto-commit — always show draft, let user approve via /ck:git
63
+ - ❌ Forget to mention subagents — they did work that deserves credit/audit
@@ -0,0 +1,72 @@
1
+ # Weekly Retro Workflow
2
+
3
+ Pattern: every Sunday (or Monday morning), look back at the week — cost trends, skill discovery, runaway sessions.
4
+
5
+ ## Flow
6
+
7
+ ```
8
+ 1. ckforensics ingest # ensure DB current
9
+ 2. ckforensics summary --days 7 # weekly rollup
10
+ 3. ckforensics sessions --limit 20 # week's sessions
11
+ 4. ckforensics suggest --days 7 --min-confidence 50 # patterns to fix
12
+ 5. ckforensics skills --unused | head -20 # discovery
13
+ ```
14
+
15
+ ## When Claude runs this skill
16
+
17
+ User says one of:
18
+ - "weekly retro"
19
+ - "what did I spend on Claude Code this week"
20
+ - "any patterns I should fix in my workflow"
21
+ - "show me sessions ranked by cost"
22
+ - "what skills should I learn"
23
+
24
+ ## What Claude should do
25
+
26
+ 1. **Summary numbers first** — cost, session count, vs previous week if possible (`--days 14` then compute delta).
27
+ 2. **Top 5 most expensive sessions** with project + duration. Flag anything over $50.
28
+ 3. **Recurring patterns** from `suggest --days 7`:
29
+ - List top 3 skill recommendations
30
+ - Group by pattern type (e.g. "read-fanout detected 4× this week")
31
+ 4. **Skill discovery**:
32
+ - From `skills --unused`, pick 3-5 that match user's project work (filter by keyword overlap with recent session topics)
33
+ - Format as "consider trying: /ck:xyz — <description>"
34
+ 5. **Anomaly check**:
35
+ - Any single session >$100? Flag for review.
36
+ - Any subagent that ran >1h? Worth investigating.
37
+ 6. **Optional: write retro to docs/**:
38
+ - `docs/retros/YYYY-MM-DD-week-N.md`
39
+ - Auto-fill summary + recommendations sections
40
+ - User edits notes manually after
41
+
42
+ ## Example response template
43
+
44
+ ```
45
+ Weekly retro (Mon 2026-05-04 → Sun 2026-05-10):
46
+
47
+ 📊 Totals: $733 API-equivalent across 19 sessions, 967M tokens
48
+ vs prev week: +180% (last week $260 / 12 sessions)
49
+
50
+ 🔥 Top sessions:
51
+ 1. project-noname 18h56m $1102 (Tue, 4082 events)
52
+ 2. MQL5 2h21m $29 (Tue)
53
+ 3. career-launchpad 19h $32 (Wed)
54
+
55
+ 📚 Skill recommendations:
56
+ - /ck:scout (4× read-fanout patterns this week — 50k tok save)
57
+ - /ck:test (3× test-loop patterns — 15k tok save)
58
+
59
+ 💡 Try these unused skills:
60
+ - /ck:retro — auto-generate this report (would replace this manual flow)
61
+ - /ck:journal — capture session reflections automatically
62
+ - /ck:debug — systematic debugging when stuck
63
+
64
+ ⚠️ Notable: session #1 was 18h Opus — consider checkpointing context mid-way.
65
+ ```
66
+
67
+ ## Anti-patterns
68
+
69
+ - ❌ Compare cost to subscription price as if it's the bill — it's API-equivalent, frame as "value extracted"
70
+ - ❌ Recommend ALL unused skills (150+) — filter to relevant per project context
71
+ - ❌ Skip anomaly check — outliers are the highest-signal items
72
+ - ❌ Long bullet lists — keep tight, 3-5 items per category max
@@ -0,0 +1,165 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ session-overview.py — One-shot session report for ck:forensics skill.
4
+
5
+ Runs multiple `ckforensics` CLI commands and stitches a single JSON
6
+ report. Saves Claude from chaining 4-5 Bash calls when answering
7
+ "summarize this session" prompts.
8
+
9
+ Usage:
10
+ python3 session-overview.py [--session-id ID] [--days N]
11
+ python3 session-overview.py --last # default — most recent session
12
+
13
+ Output: JSON on stdout with shape:
14
+ {
15
+ "schema": "ck-forensics-overview-v1",
16
+ "generatedAt": "ISO8601",
17
+ "scope": {"sessionId": "...", "days": 7, "lastOnly": true},
18
+ "summary": { ... }, # `ckforensics summary --json` data
19
+ "session": { ... }, # one row from `ckforensics sessions --json`
20
+ "audit": { ... }, # `ckforensics audit --json` (manifest)
21
+ "suggest": [ ... ], # top recs from `ckforensics suggest --json`
22
+ "map": { ... } # context map heatmap
23
+ }
24
+
25
+ Errors are reported as {"schema": "error", "error": "..."} with exit 1.
26
+
27
+ Stdlib only — no third-party deps required. Compatible with Python 3.8+.
28
+ """
29
+
30
+ import argparse
31
+ import json
32
+ import shutil
33
+ import subprocess
34
+ import sys
35
+ from datetime import datetime, timezone
36
+
37
+
38
+ def check_cli_installed() -> None:
39
+ """Verify ckforensics CLI is on PATH; exit 1 with clear error if not."""
40
+ if shutil.which("ckforensics") is None:
41
+ emit_error(
42
+ "ckforensics CLI not installed. "
43
+ "Install with: npm i -g ckforensics"
44
+ )
45
+ sys.exit(1)
46
+
47
+
48
+ def run_cli(args: list) -> dict:
49
+ """
50
+ Run `ckforensics <args>` with --json and return parsed output.
51
+ Raises CalledProcessError on non-zero exit (caller decides whether to ignore).
52
+ """
53
+ cmd = ["ckforensics", *args, "--json"]
54
+ result = subprocess.run(
55
+ cmd,
56
+ capture_output=True,
57
+ text=True,
58
+ check=False,
59
+ timeout=30,
60
+ )
61
+ if result.returncode != 0:
62
+ # Many subcommands exit 3 when no data — return empty rather than fail
63
+ if result.returncode == 3:
64
+ return {}
65
+ raise subprocess.CalledProcessError(
66
+ result.returncode, cmd, result.stdout, result.stderr
67
+ )
68
+ return json.loads(result.stdout) if result.stdout.strip() else {}
69
+
70
+
71
+ def emit_error(msg: str) -> None:
72
+ """Write error envelope to stdout."""
73
+ print(json.dumps({"schema": "error", "error": msg}), flush=True)
74
+
75
+
76
+ def collect_overview(session_id: str | None, days: int, last: bool) -> dict:
77
+ """Gather all sections; failures in individual sections become null."""
78
+ overview = {
79
+ "schema": "ck-forensics-overview-v1",
80
+ "generatedAt": datetime.now(timezone.utc).isoformat(),
81
+ "scope": {"sessionId": session_id, "days": days, "lastOnly": last},
82
+ "summary": None,
83
+ "session": None,
84
+ "audit": None,
85
+ "suggest": None,
86
+ "map": None,
87
+ }
88
+
89
+ # 1. Summary — rolling window
90
+ try:
91
+ overview["summary"] = run_cli(["summary", "--days", str(days)]).get("data")
92
+ except Exception as e:
93
+ overview["summary"] = {"error": str(e)}
94
+
95
+ # 2. Session metadata — pick from list or by id
96
+ try:
97
+ sessions_envelope = run_cli(["sessions", "--limit", "1"])
98
+ sessions = sessions_envelope.get("data", [])
99
+ if session_id:
100
+ # Filter to specific session if requested
101
+ sessions = [s for s in sessions if s.get("id") == session_id]
102
+ overview["session"] = sessions[0] if sessions else None
103
+ except Exception as e:
104
+ overview["session"] = {"error": str(e)}
105
+
106
+ # 3. Audit manifest — uses --last unless explicit id given
107
+ audit_args = ["audit", "--last"] if last or not session_id else ["audit", session_id]
108
+ try:
109
+ overview["audit"] = run_cli(audit_args)
110
+ except Exception as e:
111
+ overview["audit"] = {"error": str(e)}
112
+
113
+ # 4. Suggest — same scope as audit
114
+ suggest_args = ["suggest", "--last", "--min-confidence", "30", "--top", "3"]
115
+ if session_id and not last:
116
+ suggest_args = ["suggest", "--session", session_id, "--min-confidence", "30", "--top", "3"]
117
+ try:
118
+ overview["suggest"] = run_cli(suggest_args).get("data", [])
119
+ except Exception as e:
120
+ overview["suggest"] = {"error": str(e)}
121
+
122
+ # 5. Map — top-10 heatmap categories
123
+ map_args = ["map", "--last", "--top", "10"]
124
+ if session_id and not last:
125
+ map_args = ["map", session_id, "--top", "10"]
126
+ try:
127
+ overview["map"] = run_cli(map_args).get("data")
128
+ except Exception as e:
129
+ overview["map"] = {"error": str(e)}
130
+
131
+ return overview
132
+
133
+
134
+ def parse_args() -> argparse.Namespace:
135
+ p = argparse.ArgumentParser(
136
+ prog="session-overview",
137
+ description="Unified session report — runs multiple ckforensics commands and merges output.",
138
+ )
139
+ p.add_argument("--session-id", help="Explicit session UUID (defaults to --last)")
140
+ p.add_argument("--days", type=int, default=7, help="Summary window in days (default 7)")
141
+ p.add_argument(
142
+ "--last",
143
+ action="store_true",
144
+ default=True,
145
+ help="Use most recent session (default behavior)",
146
+ )
147
+ return p.parse_args()
148
+
149
+
150
+ def main() -> int:
151
+ check_cli_installed()
152
+ args = parse_args()
153
+ last = args.last and not args.session_id
154
+
155
+ try:
156
+ overview = collect_overview(args.session_id, args.days, last)
157
+ print(json.dumps(overview, indent=2, default=str))
158
+ return 0
159
+ except Exception as e:
160
+ emit_error(f"unexpected error: {e}")
161
+ return 1
162
+
163
+
164
+ if __name__ == "__main__":
165
+ sys.exit(main())
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ckforensics",
3
- "version": "0.2.1",
3
+ "version": "0.2.2",
4
4
  "module": "index.ts",
5
5
  "type": "module",
6
6
  "bin": {
@@ -16,6 +16,8 @@
16
16
  "files": [
17
17
  "bin/",
18
18
  "scripts/postinstall.js",
19
+ "scripts/install-claudekit-skill.js",
20
+ ".claude/skills/",
19
21
  "README.md",
20
22
  "LICENSE"
21
23
  ],
@@ -0,0 +1,74 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * install-claudekit-skill.js — Install the bundled `/ck:forensics` skill into
4
+ * the user's ClaudeKit skill directory (`~/.claude/skills/ckforensics/`).
5
+ *
6
+ * Called from postinstall.js. Designed to be silent on success and never
7
+ * fail the parent install — skill is a nice-to-have, not a hard dependency.
8
+ *
9
+ * Behavior:
10
+ * - Copies `<pkg>/.claude/skills/ckforensics/` to `~/.claude/skills/ckforensics/`.
11
+ * - Skip when source dir missing (e.g. dev install without the bundle).
12
+ * - Skip on opt-out: `CKFORENSICS_SKIP_SKILL_INSTALL=1`.
13
+ * - Existing skill dir is overwritten (idempotent re-install / version upgrade).
14
+ * - Warnings to stderr only; never exits non-zero.
15
+ */
16
+
17
+ import { existsSync, mkdirSync, cpSync, statSync } from "node:fs";
18
+ import { homedir } from "node:os";
19
+ import { join, dirname } from "node:path";
20
+ import { fileURLToPath } from "node:url";
21
+
22
+ const __dirname = dirname(fileURLToPath(import.meta.url));
23
+ const PKG_ROOT = join(__dirname, "..");
24
+ const SKILL_SOURCE = join(PKG_ROOT, ".claude", "skills", "ckforensics");
25
+ const SKILL_TARGET = join(homedir(), ".claude", "skills", "ckforensics");
26
+
27
+ function log(msg) {
28
+ // Single-line dim format to fit cleanly in npm install output
29
+ process.stderr.write(`[ckforensics:skill] ${msg}\n`);
30
+ }
31
+
32
+ function shouldSkip() {
33
+ // Explicit opt-out
34
+ if (process.env.CKFORENSICS_SKIP_SKILL_INSTALL === "1") {
35
+ log("skipped via CKFORENSICS_SKIP_SKILL_INSTALL=1");
36
+ return true;
37
+ }
38
+ // Source missing — dev install or trimmed tarball
39
+ if (!existsSync(SKILL_SOURCE)) {
40
+ log(`skill source not bundled (${SKILL_SOURCE}); skipping`);
41
+ return true;
42
+ }
43
+ return false;
44
+ }
45
+
46
+ function copySkill() {
47
+ // Ensure parent dir exists; cpSync recursive handles the rest.
48
+ mkdirSync(dirname(SKILL_TARGET), { recursive: true });
49
+
50
+ // Detect upgrade vs first install for friendlier message
51
+ const existing = existsSync(SKILL_TARGET);
52
+ cpSync(SKILL_SOURCE, SKILL_TARGET, {
53
+ recursive: true,
54
+ force: true,
55
+ // Don't overwrite if user has customised it (mtime-based heuristic)
56
+ // — but that's risky and confusing. For now: always overwrite, matches
57
+ // CLI versioning semantics (skill version pinned to CLI version).
58
+ });
59
+
60
+ const action = existing ? "updated" : "installed";
61
+ log(`${action} skill at ${SKILL_TARGET}`);
62
+ log("activate next Claude Code session: /ck:forensics");
63
+ }
64
+
65
+ try {
66
+ if (shouldSkip()) {
67
+ process.exit(0);
68
+ }
69
+ copySkill();
70
+ } catch (err) {
71
+ // Never fail parent install over skill copy
72
+ log(`warning: skill install failed (${err.message}); continuing`);
73
+ process.exit(0);
74
+ }
@@ -234,4 +234,19 @@ async function main() {
234
234
  console.log(`[ckforensics] Run: ckforensics --help`);
235
235
  }
236
236
 
237
- main().catch((e) => fatal(String(e)));
237
+ async function installSkill() {
238
+ // Best-effort: invoke the dedicated skill installer module. Failures here
239
+ // never block the binary install. Module handles its own opt-out + missing-
240
+ // source cases.
241
+ try {
242
+ await import("./install-claudekit-skill.js");
243
+ } catch (err) {
244
+ process.stderr.write(
245
+ `[ckforensics:skill] warning: failed to load skill installer (${err.message})\n`
246
+ );
247
+ }
248
+ }
249
+
250
+ main()
251
+ .then(installSkill)
252
+ .catch((e) => fatal(String(e)));