npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@csepulv/session-export

v1.0.0

Published

Export Claude Code conversations from JSONL to readable markdown or plain text.

Readme

session-export

Export Claude Code conversations from JSONL to readable markdown or plain text.

DISCLAIMER / PSA: Shared as-is, I hope it helps. This space is evolving quickly. I am sharing to help others wade through the fog and swamp, as I have been doing. Look around; there are probably better tools than this one. 😉

Why

Claude Code stores each session as a JSONL file under ~/.claude/projects/<encoded-path>/<session-id>.jsonl. Machine-friendly, not reader-friendly — and the turns are interleaved with tool calls, subagent traffic, thinking blocks, and system messages.

I wanted a way to get my conversations out — for archiving, sharing, reviewing agent work, or feeding prior context back into a new session. session-export reads the JSONL and emits markdown (with YAML frontmatter and collapsible tool/thinking blocks) or plain text. It also does bulk export organized by project, and emits aggregate per-session stats as JSON.

Your mileage may vary — I share it in case it helps. There are other tools in this space; look around before settling.

Install

npm install -g @csepulv/session-export

(The CLI binary is still called session-export — only the npm package name is scoped.)

Or from source:

git clone https://github.com/csepulv/save-the-tokens
cd save-the-tokens/tools/session-export
npm install
npm link  # makes `session-export` available globally

Quick Start

# List conversations across all configured sources
session-export list

# Export a conversation to stdout (markdown, default format)
session-export 7dee69bc

# Export to a file, including tool calls
session-export --include-tools --output mysession.md 7dee69bc

# Bulk-export every conversation into per-project folders
session-export all ~/exports/archive/

# Aggregate per-session stats as JSON
session-export stats --after 2026-01-01 --before 2026-04-01 > stats.json

Run session-export --help or session-export <command> --help for full flag details.

Commands

| Command | Purpose | |---|---| | session-export <id> | Export one conversation (default — no subcommand word) | | session-export list (alias ls) | List conversations | | session-export all <output-dir> | Bulk export to per-project folders | | session-export stats | Aggregate per-session stats as JSON |

All four commands accept --source <alias\|path> to restrict to one configured source (or an ad-hoc directory). For list, all, and stats, omitting --source walks all configured sources. For export, --source defaults to default.

Export one conversation

session-export [options] <id>

<id> matches first against the conversation's session ID (partial match, e.g. 7dee69bc7dee69bc-8dca-4383-a7d0-21e8446828c8), then against the conversation's custom title.

Examples:

# To stdout (markdown, default)
session-export 7dee69bc

# Plain text format
session-export --format text 7dee69bc

# Include tool calls (Read, Bash, Grep, etc.)
session-export --include-tools 7dee69bc

# Everything — tools, results, thinking, subagents, system, timestamps
session-export --include-all 7dee69bc

# From an alternate source
session-export --source work 7dee69bc

Writing to a file:

| Usage | Behavior | |---|---| | (no --output) | Write to stdout | | --output mysession.md | Write to mysession.md | | --output ~/exports/ | Write to ~/exports/<auto-slug>.md | | --output | Write to <config.outputDir>/<auto-slug>.md |

Auto-slug uses the conversation's custom title (slugified) or the session ID.

Content flags (all default off):

| Flag | Adds | |---|---| | --include-tools | Assistant tool calls (Read, Bash, Grep, etc.) as collapsible blocks | | --include-system | System messages (turn duration, subtype markers) | | --include-timestamps | Per-message timestamps on role headers | | --include-skill-text | Full skill body text (default: truncated to first 2 lines) | | --include-all | All of the above, plus tool results, thinking blocks, and subagent conversations |

List conversations

session-export list [options]
session-export ls [options]   # alias

Shows ID, date, project, and a preview line for each conversation.

# All sources (default)
session-export list

# One source
session-export list --source work

# Filter by project path substring
session-export list --filter my-app

Bulk export

session-export all <output-dir> [options]

Writes one folder per project, two files per session — <slug>.md (default export) and <slug>.full.md (same session with --include-all). Sessions from different sources with the same project name merge into one folder.

# Every conversation, every source
session-export all ~/exports/archive/

# Restrict to one source
session-export all ~/exports/archive/ --source work

# Filter by project path + date range
session-export all ~/exports/archive/ \
  --filter my-app \
  --after 2026-01-01 --before 2026-04-01

Flags:

| Flag | Purpose | |---|---| | --source <alias\|path> | Restrict to one source (default: walk all) | | --filter <substring> | Filter by project path substring | | --after <date> | Include sessions on or after (inclusive, start of day if date-only) | | --before <date> | Include sessions on or before (inclusive, end of day if date-only) | | --config <path> | Config file path (default: ~/.session-export.yaml) | | --exclude-timestamps | Omit per-message timestamps (default: included) | | --include-skill-text | Keep full skill body text (default: truncated) |

Date format: YYYY-MM-DD or YYYY-MM-DDTHH:MM:SS (local time).

Stats

session-export stats --after <date> --before <date> [options]

Emits a JSON object to stdout with aggregate per-session stats — turn counts (user, assistant, subagent), token totals by model, start and end timestamps, duration. No conversation content.

session-export stats --after 2026-03-01 --before 2026-03-31 > march.json

Exit codes:

  • 0 — at least one session emitted
  • 1 — error (bad args, I/O failure)
  • 2 — no sessions in window (still emits valid JSON with sessions: [])

Config

Optional config file at ~/.session-export.yaml:

# Default output directory for bare --output flag
outputDir: ~/exports

# Named source directories
sources:
  default: ~/.claude          # used when no --source given on the export command
  work: ~/.work-claude        # --source work

Without a config file: the default source is ~/.claude, and bare --output requires an explicit path.

Output formats

Markdown (default)

YAML frontmatter followed by the conversation. Turns separated by horizontal rules with bold role labels. Assistant markdown (headings, code blocks, tables) renders at its original heading levels.

---
session: 7dee69bc-8dca-4383-a7d0-21e8446828c8
title: My Session
project: my-app
cwd: /path/to/my-app
hostname: my-host
git_branch: main
claude_version: 2.1.92
permission_mode: default
started_at: 2026-04-03T10:15:00.000Z
ended_at: 2026-04-03T11:42:00.000Z
duration: 1h 27m
---

# My Session

---

**User**

What does this script do?

---

**Assistant**

It exports Claude Code conversations…

With --include-tools, tool calls appear as collapsible <details> blocks. With --include-all, tool results, thinking blocks, subagent conversations, and system messages all render as collapsible sections.

Plain text

=== USER === / === ASSISTANT === headers with the same YAML frontmatter. Use --format text.

What gets filtered by default

Even without --include-* flags, the export includes only the human/assistant dialogue. Infrastructure noise is filtered:

  • Local command messages (/exit, /color, caveat notices) are excluded
  • Tool calls and results are excluded unless --include-tools / --include-all
  • System messages are excluded unless --include-system / --include-all
  • Subagent conversations are included with --include-all

Troubleshooting

session-export <id> can't find the conversation

The export subcommand searches one source (the one --source resolves to — default by default). If the conversation lives in a different source, pass --source <name> or use list (which walks all sources) to confirm where it is.

list / all / stats show nothing

No configured source has a projects/ subdirectory with matching JSONL files. session-export list walks every source in your config; if you get an empty table, either Claude Code hasn't recorded any sessions there, or your config points at the wrong directory.

Development

npm install
npm test           # vitest
npm run test:watch