Recording probe for the memory session, throwaway

<img src=".github/assets/header.svg" alt="cc-graph: see what Claude knows" width="100%">
<samp>install · the pane · privacy · roadmap · changelog</samp>
<samp>After a long turn, nobody can say without scrolling back what Claude actually has in context. cc-graph is a Claude Code mod that draws it in a live pane beside the conversation: every file Claude read, searched or changed, how those files import each other, and what compaction took away.</samp>
<a name="install"></a> <img src=".github/assets/h-install.svg" alt="install" width="100%">
/plugin install cc-graph --marketplace kuehn-lars/cc-graph
<samp>Then type /graph. Needs Claude Code v2.1.287 or later, in the terminal.</samp>
<a name="the-pane"></a> <img src=".github/assets/h-the-pane.svg" alt="the pane" width="100%">
<img src=".github/assets/showcase.svg" alt="The cc-graph pane in the terminal, annotated: the context window meter, partly read and compacted files, import edges, folder frames, size bars, the focus, search-only files, an edit and a new file, the now line and the legend" width="100%">
| <samp>control</samp> | <samp>what it does</samp> |
|---|---|
| <kbd>g</kbd> | <samp>graph view</samp> |
| <kbd>l</kbd> | <samp>list view</samp> |
| <kbd>1</kbd> … <kbd>9</kbd> | <samp>pick a row in the list</samp> |
maxNodes = 60 | <samp>most files in the graph, in /config</samp> |
importEdges = on | <samp>show file imports, in /config</samp> |
blindSpots = on | <samp>look for blind spots with git, in /config</samp> |
captureThinking = on | <samp>keep thinking excerpts, in /config</samp> |
<samp>Files a shell command created, deleted or changed show too, named with the command that did it, and so do files Claude read with cat, head or sed -n. Files that import a change but were never opened are flagged as blind spots while the turn is still running.</samp>
<samp>The list also shows Claude's newest thinking: a short excerpt per step, with its turn and the files that step read or changed. Claude Code passes thinking text to mods only when "showThinkingSummaries": true is in your settings (or with --thinking-display summarized). This holds for every 5.5 model: Opus, Sonnet and Haiku. Without it, the footer says thinking is hidden.</samp>
<a name="privacy"></a> <img src=".github/assets/h-privacy.svg" alt="privacy" width="100%">
<samp>cc-graph only watches. Its hooks pass every tool result on untouched and record what happened in session memory.</samp>
captureThinking is on. All of it is gone when the conversation ends or on /clear.</samp><a name="roadmap"></a> <img src=".github/assets/h-roadmap.svg" alt="roadmap" width="100%">
<img src=".github/assets/roadmap.svg" alt="Roadmap: M0 Foundations, v0.1 What Claude knows, v0.2 The graph and v0.3 Blind spots shipped; next v0.4 Why it did that, then v0.5 Desktop graph and pointer, v0.6 Decisions and timeline, v1.0 Hardening and listing" width="100%">
<samp>Features, exit gates and spikes per milestone are in ROADMAP.md.</samp>
<samp>The project is spec-driven: specs/ is the source of truth, and each feature goes from spec to failing tests to code. Instructions for Claude Code working on this repository are in CLAUDE.md.</samp>
claude --plugin-dir . # run with the mod loaded (use a copy of fixtures/sample-app)
npx tsc -p . && claude plugin test && node scripts/check-calls.mjs
node scripts/trace.mjs --check # every approved acceptance criterion has a test
<samp><a href="LICENSE">MIT</a> © 2026 Lars Kühn · built with and for <a href="https://claude.com/claude-code">Claude Code</a></samp>
hooks/register.tsx 23 lines1// Throwaway recording probe for fixtures/sessions/memory.ts (see ../../README.md). Not part of the mod.
2// It logs session.start, session.measure and classic.InstructionsLoaded as the hooks see them (with the next(e) result), and at
3// session.start and at each session.measure whose `changed` holds `context` also the result of $.session.usage({ breakdown: 'summary' }).
4import type { Register } from 'claude-code'
5
6const OUT = '/tmp/cc-graph-memory/log-' + Date.now() + '.json'
7const rows: any[] = []
8const log = async (event: string, $: any, e: any, next: any) => {
9 const row: any = { event, input: e }
10 rows.push(row)
11 const out = await next(e)
12 row.result = out
13 if (event === 'session.start' || e.changed?.includes('context')) row.usage = await $.session.usage({ breakdown: 'summary' })
14 await $.fs.write(OUT, JSON.stringify(rows, null, 1))
15 return out
16}
17
18export const register: Register = on => {
19 on('session.start', ($, e: any, next: any) => log('session.start', $, e, next)).catch(($, e, next) => next(e))
20 on('session.measure', ($, e: any, next: any) => log('session.measure', $, e, next)).catch(($, e, next) => next(e))
21 on('classic.InstructionsLoaded', ($, e: any, next: any) => log('classic.InstructionsLoaded', $, e, next)).catch(($, e, next) => next(e))
22}
23