Shabash
Blog · Claude Code guides

How to export Claude Code chat history (to Markdown, a file, or JSON)

Three ways to export a Claude Code conversation, from the built-in /export command to a script that turns any saved session into Markdown.

By Robin Mehta · September 25, 2026

There are three ways to get a conversation out of Claude Code, depending on whether you want something to read, something to keep, or something a script can use.

1. The built-in way: /export

Inside the session you want:

/export

This opens a menu to copy the conversation to your clipboard or save it as a plain-text file, with messages and tool output rendered so a person can read them. To skip the menu and write straight to a file:

/export auth-refactor-notes.txt

This is the right choice for pasting into a doc, a pull request description, or a ticket.

2. For a script: ask the session directly

To get structured output from a session, including one you're not in, ask it a question in headless mode:

claude -p --resume <session-id> --output-format json "summarize what we changed and why" | jq -r '.result'

You get the answer plus the session ID, usage and cost as JSON. This is the method Anthropic recommends for scripts, because it doesn't depend on the transcript file format.

3. Any session to Markdown

Every session is saved as JSON lines at ~/.claude/projects/<project>/<session-id>.jsonl. This script converts one to Markdown: your prompts and Claude's replies, with tool calls noted in one line each. It skips anything it doesn't recognize, so a format change degrades it instead of breaking it.

#!/usr/bin/env python3
"""Convert a Claude Code session transcript (.jsonl) to Markdown. Usage: to_md.py <session.jsonl> > out.md"""
import json, sys

for line in open(sys.argv[1], errors="ignore"):
    try:
        d = json.loads(line)
    except ValueError:
        continue
    msg = d.get("message") or {}
    role, content = msg.get("role"), msg.get("content")
    if d.get("isSidechain") or role not in ("user", "assistant"):
        continue
    if isinstance(content, str):
        print(f"## {'You' if role == 'user' else 'Claude'}\n\n{content}\n")
        continue
    for block in content or []:
        kind = block.get("type")
        if kind == "text" and block.get("text", "").strip():
            print(f"## {'You' if role == 'user' else 'Claude'}\n\n{block['text']}\n")
        elif kind == "tool_use":
            target = (block.get("input") or {}).get("file_path") or (block.get("input") or {}).get("command", "")
            print(f"> Tool: {block.get('name')} {str(target)[:120]}\n")

Find the file for a session with:

find ~/.claude/projects -name '*.jsonl' -mtime -2

Two cautions:

Which one to use

You wantUse
To paste a conversation somewhere/export
A summary or answer from an old sessionclaude -p --resume <id>
A full, readable archive of many sessionsThe Markdown script, run over ~/.claude/projects

If what you actually want is the record of your work rather than the raw conversation, Shabash keeps every session, groups them into threads per project, and writes up what shipped with links back to the sessions it came from.

Questions

How do I export a Claude Code conversation?

Run /export inside the session. With a filename, like /export notes.txt, it writes the file directly. Without one it opens a menu to copy to the clipboard or save to a file.

Can I export Claude Code chat to Markdown?

/export writes readable plain text. For Markdown with headings per message, convert the session's .jsonl transcript with a short script, like the one in this post.

Can I export a session I'm not in?

Yes. Every session is saved as a .jsonl file under ~/.claude/projects, so you can convert any of them, or ask it a question with claude -p --resume <id>.

Will my export script break?

Possibly. Anthropic documents the transcript format as internal and subject to change between versions, so write scripts that skip lines they don't recognize.