Giving Claude Code Persistent Memory Across Sessions
Anthropic gives you a memory primitive. h5i gives you the layers above it — versioned reasoning, per-commit snapshots, and automatic injection at session start, so the next session always knows what the last one was thinking.
You ship a feature with Claude Code on Friday. Monday morning you start a new session, and Claude has no idea what you were working on. Not because the codebase changed — it didn't — but because everything Claude knew lived inside the prior session's context window, and that window is gone.
The fix everyone reaches for first is a memory file: jot the project state into
~/.claude/memory/<repo>.md and prepend it to every new session. That works
for ten lines of project background. It does not work for "what files did I edit yesterday,
which milestones are done, where am I uncertain, and what was the trade-off I rejected at
14:22 last Thursday." That information is the reasoning, not the project description,
and it has structure. A flat markdown file flattens it.
h5i sits in front of Claude Code's memory primitive and adds three layers — a structured
reasoning workspace, automatic per-commit snapshots, and a SessionStart hook that
injects the right slice of it into every new session. Once it's installed, you stop
re-explaining yourself.
What /clear actually destroys
A Claude Code session has four kinds of state. When the session ends or you run /clear,
they evaporate at different rates:
| State | Lifetime | What survives |
|---|---|---|
| The conversation transcript | The session | JSONL log on disk, mostly unread |
| The active context window | Until /clear | Nothing |
Memory files (~/.claude/memory/) | Across sessions | Whatever you manually wrote |
| Hooks & settings | Permanent | Configuration, not knowledge |
Memory files are the only thing Claude carries forward by default, and they're a free-form text blob. There is no structure for "milestones," no link from a sentence in the file to the commit it describes, no automatic refresh when you commit code, and no way to branch the memory the way you branch code when you explore an alternative.
So engineers do what engineers do: they invent ad hoc structure inside the markdown file —
## Done, ## TODO, ## Decisions — and update it manually. The first
week is fine. By week three the file is stale, contradictory, and nobody trusts it.
The three layers above the memory primitive
h5i treats memory the way Git treats files: as a thing you commit, branch, diff, and push. Concretely, it adds three refs to your repo and three classes of write operation:
- Reasoning workspace —
refs/h5i/context. A versioned DAG of OBSERVE / THINK / ACT entries plus milestones. Branches like git, merges like git. - Memory snapshots —
refs/h5i/memory. Everyh5i commitsnapshots~/.claude/projects/<repo>/memory/and pins it to the git SHA. - Session notes —
refs/h5i/notes. The exploration footprint of each session — files read vs. edited, uncertainty signals, blind edits.
All three are git refs, so they push and pull alongside your code. None of them touch your working tree.
The reasoning workspace
Run this once per project (or per major task):
$ h5i context init --goal "Migrate the auth service from Sessions to JWT" ✔ .h5i-ctx/ workspace initialized branch: main · goal recorded
During work, you (or Claude, via the PostToolUse hook) emit trace entries:
$ h5i context trace --kind OBSERVE \ "session.rs uses tower_sessions; refresh_token belongs in JwtClient" $ h5i context trace --kind THINK \ "Issue refresh tokens server-side; access tokens stay client-side. 15-min TTL." $ h5i context trace --kind ACT \ "Replaced session middleware with JwtMiddleware in src/api/mod.rs"
And after a logical milestone, you commit the workspace:
$ h5i context commit "JWT middleware in place" \ --detail "Sessions middleware removed; tests pass; refresh-token path TODO" ◆ milestone m1 recorded · DAG node 4f7a2bc
The trace and milestones live in refs/h5i/context. Every entry is a DAG node with a parent
pointer, so reasoning has a topology — not just a timeline. When you fork an alternative, you
h5i context branch experiment/refresh-rotation, work the side path, and either merge it
back or abandon it. Either way, the abandoned branch is still there in history; you can always
recover the rejected design.
Memory snapshots, pinned to git commits
Every h5i commit auto-snapshots ~/.claude/projects/<repo>/memory/ alongside
the code commit. The snapshot is keyed by the git SHA, so memory is a first-class versioned
artifact:
$ h5i memory log 9e21b04 2026-05-06 11:45 3 files snapshotted +12 -3 a3f8c12 2026-05-05 14:02 3 files snapshotted +5 -1 7216039 2026-05-04 09:18 2 files snapshotted initial $ h5i memory diff a3f8c12 9e21b04 +++ ~/.claude/projects/my-project/memory/decisions.md + - 2026-05-06: Switched to RS256 keys (HS256 felt fragile for multi-service) - - 2026-05-04: Considering HS256 with shared secret per service
You can h5i memory restore <sha> to recover the memory file as it stood at any past
commit, push it to teammates with h5i push, or simply diff it against last week's
version to see how your understanding has shifted.
The SessionStart hook: zero-friction restoration
The previous two sections are the boring infrastructure. The thing that actually changes day-to-day life is the hook that runs every time you open Claude Code:
// Generated by `h5i hook setup` { "hooks": { "SessionStart": [{ "hooks": [{ "type": "command", "command": "h5i hook session-start" }] }], "Stop": [{ "hooks": [{ "type": "command", "command": "h5i hook stop" }] }], "PostToolUse": [{ "matcher": "Read|Edit|Write|Grep|Bash", "hooks": [{ "type": "command", "command": "h5i hook post-tool-use" }] }] } }
Now every new session begins with a synthetic system message that looks like this:
[h5i] Context workspace active — prior reasoning follows. branch=main goal=Migrate the auth service from Sessions to JWT milestones=2 commits=4 trace_lines=89+12 m0: [x] JWT middleware in place m1: [x] Refresh-token endpoint wired up m2: [ ] Token rotation across deployments [h5i] Last decisions & actions: THINK: RS256 keys; HS256 felt fragile for multi-service ACT: Replaced session middleware with JwtMiddleware in src/api/mod.rs NOTE: TODO: integration test for refresh during deploy [h5i] Use `h5i context show` for full details.
The cost is calibrated by the --depth flag. Default is depth 2 — about 2,000-5,000 tokens, the
timeline view above. Depth 1 is a compact 800-token index for token-conscious workflows;
depth 3 dumps the full OBSERVE/THINK/ACT log. Claude can step up the depth itself when it
needs more, by running h5i context show --depth 3.
Branching reasoning
The most underused feature is h5i context branch. Suppose you're halfway through the JWT
migration and want to explore using biscuit tokens instead. You don't want to lose your
current thread, but you also don't want the side-quest polluting your main reasoning history.
$ h5i context branch experiment/biscuit \ --purpose "evaluate biscuit tokens as JWT alternative" # ... Claude explores; you trace the experiment ... $ h5i context checkout main $ h5i context merge experiment/biscuit ✔ Merged 6 trace entries · 1 milestone (rejected → reason recorded)
The rejected branch stays in history. Six months later, when someone says "why didn't we use biscuit?", you have the whole evaluation, with the prompts, the readings, and the reasons — not "I think we tried that once."
Try it on your next task
The minimum useful workflow is three commands once, then nothing:
$ cargo install --git https://github.com/Koukyosyumei/h5i h5i-core $ cd your-project && h5i init $ h5i hook setup # paste the output into ~/.claude/settings.json
From there, the SessionStart hook does the work. You'll notice it the first time you open a
new Claude Code session a week after a hard problem and Claude already knows where you stopped.
Stop re-explaining your project to Claude
h5i is open source, Apache 2.0, and works alongside any git remote.
Star on GitHub Back to docs