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

  1. CoralLips commented on Oct 4, 2026

    @CoralLips

    @rockad I’m building GFT Map and studying what people need after preserving their conversations. Your read-back limit example makes the downstream task important.

    What was the last question you tried to answer from an imported session, and did the search snippet plus note give you enough context? What, if anything, did you still have to recover manually? A non-sensitive description is enough; no transcript needed.

  2. rockad commented on Oct 4, 2026

    @rockad
    Author

    Hi @CoralLips 👋

    Here is a practical example from real usage:

    1. The question tried to be answered:
    Looking up past benchmark notes and decision rationale when comparing LLM memory engines (Basic Memory vs. mcp-memory-service vs. Graphiti)—specifically why mcp-memory-service was disqualified (silent edit discards) and why Graphiti was rejected (cost and silent hangs).

    2. Did the search snippet + note give enough context?

    • With unsliced, raw transcripts (>60k chars): The search_notes snippet correctly identified the session and heading, but running read_note failed outright because the note payload exceeded the MCP client's tool-result character budget (refused at ~62k chars).
    • With sliced & filtered notes (tool noise removed, split by turns/### headings): The search_notes snippet pinpointed the exact ### section, and a single read_note call returned 100% of the required decision context comfortably under the client budget limit.

    3. What had to be recovered manually?
    When hitting the payload limit on raw transcripts, we had to drop to terminal tools (rg, cat, or a JSONL parser) directly on disk to read the turns surrounding the search snippet. Session slicing completely eliminated that manual step.

  3. CoralLips commented on Oct 4, 2026

    @CoralLips

    Thanks, @rockad. For this benchmark-decision lookup, slicing and filtering made the existing search + note workflow sufficient and removed the manual terminal step. That is a useful case where the current approach already meets the need. I appreciate the concrete before/after.

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