Jotura

Guides / AI agents / 2026-08-30

How to give Claude Code a persistent memory

Claude Code carries some state between sessions, but not a decision record. Here is how to build a Claude Code persistent memory you can read and edit.

The short answer

Claude Code does carry some state between sessions. Your CLAUDE.md files load at the start of every session, the # shortcut appends a line to one without leaving the conversation, and claude --continue or claude --resume reopens a previous transcript. What none of that gives you is an accumulating record of decisions: what you chose, why you chose it, and what would make you reverse it.

So a Claude Code persistent memory is something you build on top of the built-ins. It needs three parts: a place the agent writes decisions down, a habit of reading them back before it proposes anything, and a format you can open and correct yourself. There are four ways to get there, and the first one costs nothing.

Four ways to get memory across sessions

ApproachWhat it costsWhere it wins
CLAUDE.md and the # shortcutNothing, it is already installedStanding instructions that stay small and stable
A decisions file in the repoFour lines of CLAUDE.mdNo tooling, versioned with the code, reviewed in pull requests
A memory server over MCPA server process to run and trustRanked recall the agent retrieves on its own
A notes vault with a command-line toolInstalling a notes appNotes that outlive the repo and follow you across agents

Try the second one first. Create docs/decisions.md, then tell CLAUDE.md to read it before proposing an architecture and to append to it whenever you settle something. This is an architecture decision record, a practice older than coding agents by a decade, and for one repo with one agent it is often enough.

It breaks down in three places. The file grows into a wall of text with no ranking, so the agent reads all of it or skims none of it. It lives inside one repository, so a decision about how you deploy cannot help you in a different codebase. Nothing marks an entry as superseded, so old decisions keep arguing with new ones.

A memory server over the Model Context Protocol, the standard interface that lets an agent call an external tool, fixes the ranking problem. The cost is that your memory now lives in that server’s storage, in whatever shape it chose. Vector embeddings retrieve better over a large corpus, but you cannot read a vector, edit it, or diff it in git. Both trades are argued out in MCP memory servers versus plain markdown files and vector databases versus markdown agent memory.

The fourth approach keeps the ranking and the structure while leaving every entry as a file you can read. That is what the rest of this guide covers. If your actual problem is CLAUDE.md drifting between laptops, that is a different fix, covered in syncing CLAUDE.md between machines.

Where Jotura fits

Jotura is a free local-first markdown notes app for Mac, Windows, Linux, and Android. Adam Richardson built it as a private, fast notes app with encrypted sharing, for his own use. The agent layer came later, on foundations that were already there: plain files, atomic writes, and a Rust core.

It ships a first-party command-line tool called jotura. That tool gives Claude Code a small set of verbs, built around three moves: log a memory, recall memories about a topic, and pull a context pack when a session starts. The notes live in an ordinary folder on your disk, so you can open, correct, and delete them.

The cost is worth stating plainly. Adopting this means adopting a notes app, because the memory commands write .md files into a vault. If you do not want one, the decisions file above gets you most of the benefit for none of the setup.

Three kinds of memory worth keeping

The jotura CLI stores each memory as a note with a kind, so recall can filter and rank sensibly.

KindWhat it holdsExample
decisionA choice made, with the reasoning and the conditions that would reverse it“Use a Postgres-backed job queue for billing”
factDurable context about the project that is not in the code“The staging Worker points at a separate D1 database”
followupSomething owed, which stays open until you resolve it“Benchmark queue throughput before the Q4 launch”

Resist logging the conversation itself. Anything that does not fit one of the three kinds is usually chatter.

The shape of a session

You open Claude Code to add background jobs to a billing service. Before it proposes anything, the agent runs:

jotura context "add background job processing to the billing service"

That prints one pack: your vault conventions, the memories ranked most relevant to that task description, and any follow-ups still open. On a fresh vault it prints almost nothing, and becomes useful after a handful of decisions are logged.

The agent is about to suggest Redis. First it checks whether you already decided this:

jotura memory recall "job queue" --kind decision --limit 5

Recall ranks by relevance, freshness, and importance, and hides superseded notes unless you pass --include-stale. If a prior decision comes back, the agent has to reckon with it rather than quietly contradict it.

Suppose this one is fresh. Once you agree on the approach, the agent writes it down:

jotura memory log --kind decision \
  --title "Postgres-backed job queue for billing" \
  --project "Billing" \
  --importance high \
  --tags "queue,postgres,billing" \
  --body "Chose a Postgres-backed queue over Redis. Billing already runs Postgres with backups, and a second durability story is not worth the operational cost. Revisit if sustained throughput passes 500 jobs per second."

That creates a note at Memory/Decisions/2026-08-30 postgres-backed-job-queue-for-billing.md. Note the last sentence of the body. A decision that records its own expiry condition is worth ten that do not.

The benchmark you promised becomes a follow-up:

jotura memory log --kind followup --title "Benchmark queue throughput before Q4 launch" --project "Billing"

Weeks later, list what is still open and close it:

jotura memory list --kind followup --status open --project "Billing"
jotura memory resolve "Memory/Followups/2026-08-30 benchmark-queue-throughput-before-q4-launch.md"

When a decision is genuinely reversed, do not delete the old one. Link the two, so the history of the reversal survives:

jotura memory supersede "Memory/Decisions/2026-08-30 postgres-backed-job-queue-for-billing.md" \
  --by "Memory/Decisions/2026-11-14 move-billing-queue-to-a-dedicated-broker.md"

Setting it up

One command installs the app, puts the jotura command on your PATH, and detects the agents on your machine. On macOS or Linux:

curl -fsSL jotura.io/install.sh | bash

On Windows:

irm jotura.io/install.ps1 | iex

The installer writes skill files that teach each detected agent the loop above, covering Claude Code, Codex, Gemini CLI, and GitHub Copilot. It verifies a checksum for every download before anything runs. It is plain shell at jotura.io/install.sh and plain PowerShell at jotura.io/install.ps1, so read it in a browser before you pipe it to a shell.

If you already have Jotura, wire up your agents at any time with jotura skill install all. To load the context pack automatically at the start of every Claude Code session, install the hook:

jotura hook install claude

That writes a SessionStart hook into your Claude Code settings. Edit the same file to remove it.

Auditing what the agent wrote

Every memory the agent logged is a file you can open, diff in git, and delete. Nothing is stored in a form you cannot read, and no entry appears unless a command wrote it.

The folder is not everything your agent believes in a session. Its working context also comes from CLAUDE.md, the code it just read, and the conversation you are having. The folder gives you the durable half, in full, and auditing what your AI agent remembers walks through reading it.

Two commands help with hygiene. jotura memory list --stale shows active memories older than 180 days, which is usually where the wrong ones hide. jotura memory list --kind decision prints a project’s whole decision record in one pass.

Why a CLI rather than raw file edits

Claude Code already knows how to work with files, and these notes are files. The CLI exists to add the safety that raw editing lacks.

It supports hash-checked writes: the agent passes --if-hash with the hash it read, and the write fails with exit code 2 if the file changed in between. That is a flag rather than an enforced default, so an agent that omits it writes unconditionally. The bundled skill files instruct agents to pass it on every write.

The rest of the safety is unconditional. Replacements must match a unique string unless you say otherwise, the CLI writes atomically, and body edits never touch a note’s frontmatter. It runs the same Rust core the desktop app uses.

Across machines and across agents

One memory folder serves every agent you run. Codex, Gemini CLI, and Copilot read and write the same notes as Claude Code, so switching tools mid-project does not reset your history. Your agent configuration gets the same treatment. Instructions, skills, and subagent definitions live in an Agents/ folder in the vault, and jotura agents sync applies them to each tool’s expected location.

Working across a desktop and a laptop means keeping the notes in both places. A generic file sync will move them, though tools that copy a folder blindly can leave conflicted copies when two machines edit the same note between passes.

The app and the CLI are free. Jotura Sync is the paid option at 4 pounds a month or 40 pounds a year, with no free trial. It is end-to-end encrypted, and the server never sees your note contents, your filenames, or your keys. Full terms are on the pricing page.

The honest limits

This is a discipline, not magic. If your agent skips the recall step, it will still contradict you. The skill files and the session hook make the loop the default path, but a system built on habit can be broken by habit.

The memory is also only as good as what gets logged. Nothing here reads your conversations or infers what matters. A decision reaches the notes because an agent wrote it there.

Jotura itself is closed source, has no iOS app, and supports no plugins. If reading the source of your memory tooling is a requirement, use the decisions file in your repo instead.

Download Jotura

Free. Plain markdown files, yours forever.