Skip to content

Feature request: import claude-code for Claude Code session transcripts #1527

Description

@rockad

basic-memory import claude conversations reads the claude.ai account data export (conversations.json). Claude Code — the CLI — writes something different and unrelated: one JSONL transcript per session, at

~/.claude/projects/<cwd-slug>/<session-id>.jsonl

There is no importer for that format, and two things make it worth one:

  1. Claude Code deletes those transcripts. Retention is cleanupPeriodDays in ~/.claude/settings.json, 30 days by default. So the record of how a decision was reached expires on a rolling basis while the decision stays.
  2. The conversations are substantial. One machine here: 131 transcripts, 158 MB. A single session's transcript can reach 15 MB.

Shape of the format

One JSON object per line. type distinguishes the record; across 131 transcripts these appeared:

type what it is
user a turn. message.content is either a string (what the user typed) or a list of tool_result blocks
assistant a turn. message.content is a list of text, thinking and tool_use blocks
system harness notices
attachment injected file/context payloads
ai-title the session's generated title (aiTitle), written repeatedly
continued-in names the session id this one was resumed into (continuedInSessionId)
file-history-snapshot, file-history-delta editor state
queue-operation, cost-state, last-prompt, mode, permission-mode, bridge-session, atis-latch, agent-setting, agent-name housekeeping

Useful fields on the turn records: sessionId, timestamp, cwd, gitBranch, isMeta, isSidechain, parentUuid.

Four things an importer has to get right

These are the traps a naive reader falls into. All four were hit while writing a local converter, and each one is invisible rather than loud.

  1. Conversation text is a small minority of the bytes. tool_use and tool_result blocks dominate. Importing them wholesale imports tool output — which is where credentials surface — and buys little as memory. A messages-only default seems right, with tool content opt-in. On the history above, 158 MB of transcript reduced to 1.2 MB of notes once tool traffic was dropped.

  2. A resumed session replays its parent. The transcript of a resumed session contains the whole earlier conversation under the new session id, so importing every file stores the same conversation once per resume. On one chain here: 15, then 17, then 27 user turns, the last file holding all of them. continued-in gives the forward link, so the tail of a chain is the one to keep.

  3. ai-title is inherited by a resumed session, so it is not a unique title. On one history it collided on 13 notes of 30 — same title, same start time, overlapping content.

  4. Subagent transcripts are separate files named agent-*.jsonl, and subagent turns inside a normal transcript carry isSidechain: true. Here, 91 of 131 files were subagent transcripts — the bulk of the bytes, and not conversation.

There is also a fifth, which is about output rather than input: a whole session can be too large for an MCP client to read back. read_note on a 136,000-character note is refused by the client for exceeding its tool-result token budget, which makes the note unsearchable in practice — search returns a snippet and the note itself cannot be opened. Some form of splitting, or a paged read, matters more for this source than for a chat export. (Measured against one client: returned in full at 45,110 characters, refused at 62,645.)

What already exists

I have a converter along these lines running as a SessionEnd hook in a Basic Memory wrapper project — one note per session into its own project, with the filters above, emitting the same type: conversation frontmatter and ### Human (ts) / ### Assistant (ts) body that ClaudeConversationsImporter produces, so the two streams sit side by side. Happy to contribute it upstream in whatever shape suits the project — as import claude-code, or as a separate importer module.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions