Skip to main content

chsum

Work logs and reload-ready context from your Claude Code conversations.

Nothing here is generated by a model. Every line of output is either copied verbatim from a transcript or computed from it, so nothing can be invented. That matters because the output is designed to be pasted back into a future Claude session, where a plausible-but-wrong sentence would become ground truth.

The idea

Your own prompts already are a faithful record of what you were trying to do. Extracted in order they read as the story of the session — most of what a summary would have said, without the risk:

**m1**
> can you open a chrome page to the site, it is running on 3000

**m7**
> sherpa-onnx-tts.worker.js:267 [Sherpa Worker] Initialization failed…

**m137**
> when I speed up the text to speech, it ends up sounding like a chipmunk

**m153**
> The toolbar is no longer working to slow it down or speed it up live

Blockquoting is functional, not cosmetic: a quoted reply containing ## Summary would otherwise forge a section of the digest. Everything else — dates, duration, branch, files, commands — is parsed straight out of the transcript.

Requirements

  • claude-history on your PATH
  • Python 3.10+. No third-party packages, no model, no network.

Install

pipx install chsum            # from a checkout: pipx install .

Or as a Claude Code plugin, which brings the skill with it:

/plugin marketplace add InDate/indate-tools
/plugin install chsum@indate-tools

The plugin carries the skill; the chsum command still comes from pipx.

pipx, not pip install --user: chsum is an application, so it gets its own venv and one symlink on PATH. pipx install --editable . while working on it.

A real command rather than a shell alias, because an alias doesn't exist for scripts, hooks, or agents.

Usage

chsum                                          # every session in this project, one line each
chsum -n 5                                     # just the five most recent
chsum --since 7d                               # only the last week
chsum --all                                    # across every project
chsum last                                     # most recent real session, as context
chsum last -n 2                                # the one before that
chsum find "text to speech playback speed"     # locate a conversation
chsum digest <ch_ref>                          # write a digest file
chsum digest <ch_ref> --stdout                 # print it instead
chsum digest --file path/to/session.jsonl      # address by file
chsum context <ch_ref>                         # reload artifact, for pasting into Claude
chsum context <ch_ref>/<agent-id>              # one subagent's own digest
chsum journal --since 7d                       # work log for this project
chsum journal --since 2w --all                 # across every project
! chsum mark "this is the approach that worked"  # flag the moment as notable
! chsum mark --recent 20                       # list recent messages, with ids
! chsum mark --at 47dca7e9 "where it turned"   # mark an earlier message
chsum find --marks                             # everything you've marked

Bare chsum lists the project's sessions, newest activity first:

Thu 06 Aug 2026                        dur    prompts  files  agents  marks
  ch_c120431a267b202aebf0b38f6c3c1b69  5h38m  78       14     -       ⚑2
    ↳ Plan 3D house model from floor plan photographs

Wed 05 Aug 2026
  ch_da4e99d42e5efab11ebdedc22fb65145  3h03m  30       12     5       -
    ↳ Set up cdp-tools server
  ch_b99f11b7c257dafc8b93f53480ba3804  6s     1        0      -       -
    ↳ (untitled)

Listing is the default because picking is the common case, and "most recent" is often a session you abandoned after one prompt. Dead ends are listed, not hidden — that a session went nowhere is the answer to "where did that work go". The header counts them: no activity is no file, no notable command, no agent, and one prompt.

chsum last is chsum context on the most recent session with activity, ordered by last activity so one you resumed yesterday beats one you started last week. Run from inside Claude Code, the session doing the running is excluded.

Everything scopes to the current project; --all widens. Digests land in ~/.claude/chsum/digests/<uuid>.md (--out to change).

Subagents

A subagent's edits and commands fold into its parent's totals — otherwise a session that delegated everything reads as no activity. Files no parent turn touched are marked (agent). Each agent gets a line in Delegated, and an address:

chsum context ch_da4e99d42e5efab11ebdedc22fb65145/a728cd49179f1a356

Its task, files, commands, and last message. Everything past the one-line summary is fetched on demand, so a heavily-delegated session doesn't produce a digest nobody wants to read.

<parent-ref>/<agent-id> resolves to <uuid>/subagents/agent-<id>.jsonl. chsum's own scheme, not claude-history's — see Notes on correctness.

Marks

chsum mark flags a moment while you're in it, so the digest says which part mattered — extraction can tell you what changed, not which of it was the point.

! chsum mark "the shrinkwrap approach, after two dead ends"

The ! prefix is the mechanism, not decoration. chsum writes nothing: it prints a marker line, and Claude Code's own recording of the ! run puts it in the transcript, at the point in the conversation where you typed it. So there is no second store to keep in sync, nothing injected into a file Claude Code is appending to, and the mark inherits an mN and a durable ma_ anchor for free. Run outside a session it warns instead — there is nothing there to record it.

To mark something further back, list recent messages and name one:

! chsum mark --recent 20
47dca7e9  06:27  you     can we make the digest quote the anchor instead
be74e21f  06:40  claude  That collides  two messages with identical text share one anchor
a27a1c9c  06:41  claude  Edit: chsum.py
0b2f4db2  06:42  claude  Bash: python3 -m pytest -x
! chsum mark --at be74e21f "the anchor collision, explained properly"

Everything that happened, in order: both sides' messages and every tool call, so you can mark the edit or the command rather than the sentence near it. Tool results are left out — a mark resolves to the message containing the action either way.

Ids come from the transcript itself rather than claude-history, which lags a live session by some minutes. --at mN works too, once it has caught up.

Or name the message by something it said:

! chsum mark --match "worth knowing exactly where it dies" "the subagent gap"

Matching folds case, punctuation, and markdown away — currently no finds Currently **no** —, because nobody retypes the asterisks. Marks still quote the original bytes. If more than one message matches, chsum lists the candidates and marks nothing: asking to mark a phrase puts that phrase in your own prompt too, so "newest wins" would keep marking the request instead of its subject. chsum mark's own calls and output are excluded from matching — its tool call is recorded before the command runs, so otherwise every search would find itself.

Marks show up as Notable at the top of the digest, verbatim, with the message they point at; as a count in the listing; inline in journal; and chsum find --marks [query] searches them across sessions.

Marked something you'd rather not keep:

! chsum mark --list
the subagent gap, stated plainly    dde43c3c
   Currently **no**  and worth knowing exactly where it dies.

Testing                             32e8b253
   Left in place  it records the state that prompted the change.

! chsum mark --list --full          # whole reason, whole marked message
! chsum mark --revoke 32e8b253      # takes several ids at once

Each mark shows its reason, its id, and the message it marks. A bare chsum mark points at the message it followed — its own output record says nothing about what you were marking.

A revocation is another line of output, same as a mark — nothing was written, so there is nothing to delete. Both records stay in the transcript; the mark simply stops counting everywhere marks are read.

A subagent can mark too. Its marks land in its own sidecar and fold into the parent, like its edits and commands, tagged agent <id> instead of an mN — sidecars have no ordinals or anchors to cite. Revocations cross that boundary in both directions: the parent can drop a mark its agent made, and vice versa.

Search modes

--hybrid (default) and --semantic are best for conceptual recall but are slow: tens of seconds warm, and several minutes on the very first run while the embedding index builds. Use --lexical (sub-second) for identifiers, filenames, and error strings, or --exact for exact tokens.

What a digest contains

Section Source
Frontmatter — ref, title, project, branch, start, duration, counts computed
Notable — what you flagged with chsum mark, verbatim copied
What I asked for — your prompts, verbatim, in order copied
Files changed / Commands run parsed from tool calls
Delegated — one line per subagent, with its address parsed from sidecars
Where I left off — last prompt and last reply, verbatim copied
found by two separate backward scans, so they may be far apart and are not a Q&A pair
Drill downmN → ma_… anchor map computed

An agent digest has the same shape minus the intent trail — an agent gets one instruction, so Task is a single block — and no anchor map (see below).

Output is budgeted, because it lands in a future context window: quotes clip, lists cap. Every truncation is marked ([+N chars, read the anchor], …and N more) so you always know when you're seeing a fragment.

Notes on correctness

Several things here are non-obvious and were established by measuring, not assuming:

  • Duration excludes idle time. Sessions get resumed hours or days later, so first-record-to-last-record wildly overstates effort — one session in the corpus reads as 92 hours. Gaps over 30 minutes are treated as "walked away".
  • Anchors are content-addressed, so they can collide. Two messages with byte-identical text ([Request interrupted by user], say) share one anchor, and read --anchor then fails with ambiguous-ref. Ambiguous anchors are detected and never published — every anchor a digest prints resolves to exactly one message.
  • Most "user" records aren't from you. They're tool results, interrupts, and harness scaffolding. Those are filtered out; prompts: counts what you typed.
  • outline has two output shapes — segment ranges for long conversations, per-message lines for short ones. Both are handled.
  • Subagent transcripts aren't conversations in their own right and never appear in the listing, matching claude-history's discovery rules.
  • claude-history has no per-agent ref. --subagents inlines agent messages into the parent read untagged, so they can't be sliced apart. Sidecars are parsed directly, which is why agent digests carry no ma_ anchors — those are claude-history's to mint, and a fabricated one is worse than none.
  • An agent's last message isn't necessarily its conclusion, so the section is Last thing it said. An interrupted agent ends mid-thought.
  • Agent counts take the larger of two sourcesAgent/Task calls in the parent, and sidecars on disk. Sidecars go missing; an agent that spawns its own outnumbers the visible calls.
  • Scratch paths (/tmp, scratchpads, plan files) are excluded from "files changed" so the work log shows real project changes.

Adding prose later

There is a deliberately unimplemented Summariser seam at the bottom of chsum.py. A TL;DR is the one thing extraction can't produce; the intended order is Haiku first to set a quality bar and a price, then a local MLX backend measured against it.

The rule for any backend: it gets the already-extracted material, and its output is additive — layered on top of the verbatim record so a wrong sentence can always be checked against the quotes beneath it.

If you do go local, note that the model in mlx-community/DeepSeek-R1-Distill-Qwen-14B-MLX is 139 GB of unquantised weights. The 4-bit build is …-14B-4bit at 8.32 GB. On a 16 GB machine the binding constraint is KV cache, not context length: this architecture costs 192 KB/token at fp16 (96 KB with kv_bits=8), so after 8.32 GB of weights you get roughly 18k–36k tokens of usable input, not the 131k the config advertises.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

chsum-1.0.3.tar.gz (31.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

chsum-1.0.3-py3-none-any.whl (30.1 kB view details)

Uploaded Python 3

File details

Details for the file chsum-1.0.3.tar.gz.

File metadata

  • Download URL: chsum-1.0.3.tar.gz
  • Upload date:
  • Size: 31.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for chsum-1.0.3.tar.gz
Algorithm Hash digest
SHA256 9d165b29303912e2dd56225a717d562d1544311a87b23dabe4279d92ecf8919a
MD5 c739bde512a5808566fb423650d558d7
BLAKE2b-256 3b58b329a16f7696af86213ac3b3e46ecd63134991f7198a409a2190d3d8714f

See more details on using hashes here.

Provenance

The following attestation bundles were made for chsum-1.0.3.tar.gz:

Publisher: publish.yml on InDate/chsum

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file chsum-1.0.3-py3-none-any.whl.

File metadata

  • Download URL: chsum-1.0.3-py3-none-any.whl
  • Upload date:
  • Size: 30.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for chsum-1.0.3-py3-none-any.whl
Algorithm Hash digest
SHA256 fe865046586a7f806717cbcac4ca9f021515478f809ea52f5d22c97486713360
MD5 d82a5b71da87acbc4f1ca4e8045dd29f
BLAKE2b-256 7a822424781cf1934abf31da7b06352c7350d5004f284b257d60b71dd10c38c1

See more details on using hashes here.

Provenance

The following attestation bundles were made for chsum-1.0.3-py3-none-any.whl:

Publisher: publish.yml on InDate/chsum

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

2.1.0

2 files

2.0.0

2 files

1.1.0

2 files

This release

1.0.3 This release

2 files

1.0.2

2 files

1.0.1

2 files

1.0.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page