Skip to content

Repository files navigation

Session Bandit

Search, browse, and extract information from the local session transcripts written by your coding agents — Claude Code, Codex, and BotBandit.

Every major coding agent writes its full session history to disk as JSONL. Session Bandit indexes those files locally — no API calls, no auth, no network. Just point it at your session directories and search across everything you've ever done with every agent.

Features

  • Unified listing across Claude Code, Codex, and BotBandit sessions, sorted by most recent first, with filters by agent, project, and time period.
  • Full transcripts — read any session's normalized transcript with tool calls, inputs, outputs, and status indicators.
  • Full-text search across all session messages and tool calls (inputs and outputs), with agent, project, and time-period filters. Uses ripgrep as a fast pre-filter when available, and skips condensed BotBandit wrappers whose full Codex original is in the index.
  • Agent recaps, compactions, and memories captured — Claude's while-you-were-away recaps, Codex's context-window compactions, and BotBandit's memory/compaction events are carried as summary messages and fed to the digest so the synthesizing LLM can use them.
  • Parsing health checkdoctor command validates that Session Bandit's parsing assumptions match your real session files (format drift, injection markers, unrecognized types, silent skips).
  • Token usage & context-window statsstats surfaces per-session and aggregate token usage (input/output/cache/reasoning), the model's context-window limit, and peak/final context size. Codex token_count events, Claude message.usage, and BotBandit turn_end/loop_end usage are all captured. stats --global aggregates every agent from your transcripts, broken down per agent; adding --agent claude layers in Claude's own ~/.claude/stats-cache.json lifetime totals.
  • Redaction preview for publishingredact-check reports what would be redacted from a session before a Markdown export writes public artifacts.
  • Markdown publishing artifactexport-md writes a redacted, reviewable Markdown file with provenance, digest, summaries, transcript, and collapsible tool calls.
  • Gorgeous GitHub Pages template — the bundled skill template renders those Markdown artifacts as a polished static archive without changing the deterministic export path.
  • Works as a library too@session-bandit/core exposes a programmatic API for indexing and querying sessions from your own code.

Install

As a global CLI (npm)

npm install -g session-bandit

Requires Node.js 22+.

From source (for development or pre-npm)

git clone https://github.com/janole/session-bandit.git
cd session-bandit
pnpm install
pnpm -r build
npm install -g packages/cli

Requires Node.js 22+ and pnpm 10+. The npm install -g packages/cli step installs the CLI globally from the built output (core is bundled into the CLI, so no separate install needed).

Agent skill

Session Bandit ships an agent skill in the skills/session-bandit/ directory. The skill teaches Claude Code, Codex, and other npx skills-compatible agents how to use Session Bandit to write handoff notes and memory notes from past sessions.

Install it globally for Claude Code:

npx skills add janole/session-bandit --skill session-bandit -g -a claude-code -y

Install it globally for Codex:

npx skills add janole/session-bandit --skill session-bandit -g -a codex -y

You can also install directly from the skill path:

npx skills add https://github.com/janole/session-bandit/tree/main/skills/session-bandit -g -a claude-code -y

Or manually copy the skills/session-bandit/ directory to the relevant agent skill directory, for example ~/.claude/skills/session-bandit/ for Claude Code or ~/.codex/skills/session-bandit/ for Codex.

The skill's SKILL.md includes instructions for the agent to install the CLI via npm install -g session-bandit if it's not already available.

CLI usage

# List all sessions (JSON lines, most recent first)
session-bandit list

# List with a human-readable table
session-bandit list --pretty

# Filter by agent
session-bandit list --agent claude
session-bandit list --agent codex
session-bandit list --agent botbandit

# Filter by project (substring match on project path / cwd)
session-bandit list --project botbandit

# Show the full transcript of a session (accepts ID prefix)
session-bandit show 342647fa-5bf

# Full-text search across session messages and tool-call input/output
session-bandit search "tool approval" --pretty

# Search within a specific agent
session-bandit search "adapter" --agent claude --pretty

# Emit a structured digest of a session (substance, files, key turns,
# recaps/compactions) for LLM ingestion — the payoff feature for
# handoffs / memories
session-bandit extract 342647fa-5bf --pretty

# Wrap the digest in a ready-to-send synthesis prompt
session-bandit extract 342647fa-5bf --prompt handoff
session-bandit extract 342647fa-5bf --prompt memory

# Preview redaction findings before publishing/exporting
session-bandit redact-check 342647fa-5bf --pretty
session-bandit redact-check 342647fa-5bf --redact strict

# Export a redacted Markdown session artifact
session-bandit export-md 342647fa-5bf --out ./session.md
session-bandit export-md 342647fa-5bf --out ./session.md --report-out ./redaction-report.json

# Token usage and context-window stats for a session
session-bandit stats 342647fa-5bf --pretty

# Aggregate usage across all sessions (Claude stats cache + summed per-session stats)
session-bandit stats --global --pretty

# Find the sessions where something actually happened (by substance score)
session-bandit list --sort importance --pretty

# Drop the trivial / hello-only sessions
session-bandit list --min-importance moderate --pretty

# Limit to the last week (relative: 7d, 24h, 2w, 3m)
session-bandit list --since 7d --pretty

# Limit to a date window
session-bandit list --since 2026-06-01 --until 2026-06-15 --pretty

# Search within a time period
session-bandit search "adapter" --since 3d --pretty

Commands

session-bandit list [--agent <name>] [--project <path>] [--sort recent|importance] [--min-importance <tier>] [--since <date>] [--until <date>] [--pretty]
session-bandit show <sessionId> [--agent <name>]
session-bandit search <query> [--agent <name>] [--project <path>] [--since <date>] [--until <date>] [--pretty]
session-bandit extract <sessionId> [--agent <name>] [--prompt handoff|memory] [--full] [--pretty]
session-bandit redact-check <sessionId> [--agent <name>] [--redact strict|cautious|minimal|none] [--pretty]
session-bandit export-md <sessionId> --out <path> [--agent <name>] [--title <title>] [--redact strict|cautious|minimal|none] [--report-out <path>] [--yes]
session-bandit stats [sessionId] [--agent <name>] [--global] [--pretty]
Flag Description
-a, --agent <name> Filter by agent: claude, codex, or botbandit
-p, --project <path> Filter by project (substring match on project/cwd)
--sort <field> list: sort by recent (default) or importance (substance score)
--min-importance <tier> list: drop sessions below tier (trivial|light|moderate|substantive|heavy)
--since <date> list/search: only entries at/after this time — absolute date (2026-06-01) or relative (7d, 24h, 2w, 3m)
--until <date> list/search: only entries at/before this time — absolute date or relative (7d, 24h, 2w, 3m)
--prompt <kind> extract: wrap the digest in a synthesis prompt (handoff|memory)
--full extract: include the complete de-noised transcript
--redact <mode> redact-check: choose strict, cautious (default), minimal, or none
--out <path> export-md: Markdown output path
--report-out <path> export-md: optional redaction report JSON output path
--yes export-md: required with --redact none
--pretty Print human-readable output instead of JSON lines
--global stats: aggregate usage across all sessions, broken down per agent (add --agent claude for Claude's lifetime cache)

Output defaults to JSON lines (one object per line) for machine consumption and piping. Use --pretty for terminal browsing.

Markdown publishing workflow

Session Bandit deliberately stops at a redacted Markdown artifact and redaction report. It does not call an LLM, push to a remote, or generate a generic HTML site. That keeps the core path offline and reviewable while still making the artifact easy to publish in a GitHub Pages-style repository.

For new publishing repos, use the default template in skills/session-bandit/templates/github-pages-default/. It is a self-contained Jekyll/GitHub Pages site with custom layouts and CSS for generated session Markdown. The agent skill can copy this template into an empty repo, then export sessions into sessions/<slug>/index.md with a sibling redaction-report.json.

Recommended flow:

# 1. Pick a session by ID, search, or importance-ranked list
session-bandit list --sort importance --pretty
session-bandit search "apple watch interface" --pretty

# 2. Preview redaction risk
session-bandit redact-check 342647fa-5bf --pretty

# 3. Export Markdown plus the machine-readable report
mkdir -p sessions/apple-watch-interface
session-bandit export-md 342647fa-5bf \
  --out sessions/apple-watch-interface/index.md \
  --report-out sessions/apple-watch-interface/redaction-report.json \
  --title "Apple Watch interface"

# 4. Review, then commit/push with your normal git workflow
git diff -- sessions/apple-watch-interface

For public artifacts, keep the default --redact cautious or use --redact strict. --redact none is intended for local debugging and requires --yes.

If you want a polished page, treat the Markdown as the canonical source and let an agent or site generator render it after review. A future HTML renderer should consume the same redacted bundle or Markdown rather than re-reading private session files.

Example output

list --pretty:

agent   sessionId     startedAt            msgs  model              project
--------------------------------------------------------------------------------
codex   019ee0ad-2eb  2026-06-19T16:18:26  64    gpt-5.5            /Users/ole/projects/chat-bandit
claude  342647fa-5bf  2026-06-19T10:38:38  153   claude-opus-4-8    /Users/ole/projects/chat-bandit
codex   019eda02-434  2026-06-18T09:14:02  65    gpt-5.5            /Users/ole/projects/chat-bandit
...

list (JSON lines):

{"agent":"claude","sessionId":"342647fa-5bf0-41b4-b21d-1e7d0d78b371","project":"/Users/ole/projects/chat-bandit","cwd":"/Users/ole/projects/chat-bandit","startedAt":"2026-06-19T10:38:38.122Z","endedAt":"2026-06-19T14:41:00.972Z","model":"claude-opus-4-8","messageCount":153}

show <sessionId>:

Session: 342647fa-5bf0-41b4-b21d-1e7d0d78b371
Agent:   claude
Project: /Users/ole/projects/chat-bandit
Model:   claude-opus-4-8
Started: 2026-06-19T10:38:38.122Z
Messages: 153

--- #1 USER  [2026-06-19T10:38:38.122Z] ---
  Do you remember us working on the tool approval yesterday?
--- #2 ASSISTANT  [2026-06-19T10:38:44.405Z] ---
  I don't have a running memory of our actual conversation yesterday, but I do have a saved note that matches what you're describing.
--- #4 ASSISTANT  [2026-06-19T10:38:45.880Z] ---
  ✓ Read
    input: {"file_path":"/Users/ole/.claude/projects/.../memory/plan085.md"}
    output: <system-reminder>This memory is 7 days old...</system-reminder>

search <query> --pretty:

[claude] 005f7977-937  #440  user
  So what about going for simple saving of tool approvals / denials with regexes...
[claude] 005f7977-937  #535  assistant
  Written to `docs/architecture.md` — the repo's canonical systems doc...

2 matches

stats <sessionId> --pretty:

Session:  019f834e-5e48-7d31-91f4-21158d035248
Agent:    codex
Project:  /Users/ole/projekte/codex-workspaces/janole/botbandit-ng
Model:    gpt-5.6-sol
Messages: 71

Tokens
  input          261,974    (cached: 3,601,408)
  output         10,264    (reasoning: 8,413)
  total          3,873,646

Context window
  limit      258,400
  peak       90,134   (35%)
  final      90,134   (35%)

Per turn
  # 1   in 32,722  out 166   ctx 32,722   (13%)
  # 2   in 439  out 134   ctx 32,951   (13%)
  # 3   in 4,045  out 107   ctx 36,557   (14%)
  ...

stats --global --pretty — every agent, summed from the transcripts on disk:

Per-session totals (from transcripts on disk)
  claude           100 sess   in   2,457,734   out 28,904,729
  codex            748 sess   in  93,171,236   out  2,846,545
  botbandit        667 sess   in 656,565,837   out  6,899,516
    └ via codex    243 sess   in 119,854,320   out  4,282,405
  total          1,515 sess   in 752,194,807   out 38,650,790
  cached 4,909,014,405   reasoning 2,544,235
  (└ = codex transcripts running under botbandit sessions — same work, not added to the total)

BotBandit can drive codex as its provider, so those conversations exist twice on disk — once as the BotBandit session you ran, once as the codex transcript beneath it. The row shows the latter without adding it to the total.

stats --global --pretty --agent claude additionally layers in Claude's own lifetime cache, which is Claude-only and counts sessions whose transcripts have since been rotated away — so its totals legitimately exceed the on-disk ones:

All-time (Claude Code cache, since 2026-01-22T10:42:06.325Z)
  sessions      434   (128 transcripts still on disk)
  messages      136,552
  longest       5,378 msgs (8d 11h)  4e4f7ab3

Tokens by model (Claude aggregate)
  claude-opus-4-8
    in 4,616,653   out 45,713,062   cache-read 5,329,110,624   cache-create 170,472,123
  ...

Per-session totals (from transcripts on disk)
  claude       100 sess   in 2,457,603   out 28,841,365
  cached 2,041,544   reasoning 0

Busiest hours (Claude only, messages)
  22:00  36
  23:00  33
  ...

Library usage

The @session-bandit/core package exposes the indexing engine and adapters for programmatic use — no CLI required.

import {
  indexSessions,
  claudeAdapter,
  codexAdapter,
  botbanditAdapter,
} from "@session-bandit/core";

// Index all sessions from all adapters
const sessions = indexSessions([
  { adapter: claudeAdapter },
  { adapter: codexAdapter },
  { adapter: botbanditAdapter },
]);

// Or just one agent
const claudeSessions = indexSessions([{ adapter: claudeAdapter }]);

// Each session is normalized to a common shape:
// {
//   agent, sessionId, filePath, project, cwd,
//   startedAt, endedAt, model, messageCount, messages[], stats?
// }
//
// Messages use a `role` of user | assistant | system | tool | summary.
// `summary` messages carry runtime-generated summaries (Claude recaps,
// Codex/BotBandit compactions, and BotBandit memories) with a `subtype`
// such as "recap", "compaction", or "memory".

Adapter interface

interface Adapter {
  readonly agent: AgentName;       // "claude" | "codex" | "gemini" | "botbandit"
  defaultRoot(): string;           // e.g. "~/.claude/projects"
  discover(root: string): string[];// find session files under root
  parse(filePath: string): Session;// parse one file → normalized Session
}

A new agent is a new adapter file — nothing else changes. See packages/core/src/adapters/ for reference implementations.

Where sessions live

Session Bandit scans these directories by default:

Agent Default location
Claude Code ~/.claude/projects/<encoded-cwd>/*.jsonl
Codex ~/.codex/sessions/YYYY/MM/DD/rollout-*.jsonl (+ legacy flat files)
BotBandit ~/.botbandit/sessions/*.jsonl

Codex has used three file formats over time — legacy .json (single object), flat .jsonl (no envelope), and modern envelope .jsonl. The Codex adapter handles all three transparently.

Development

pnpm install          # install deps
pnpm -r build         # build both packages
pnpm -r typecheck     # type-check (strict mode)
pnpm -r test          # run all tests

# Run the CLI from source (no build needed, uses tsx):
pnpm dev list --pretty
pnpm dev show <sessionId>
pnpm dev search "query" --pretty
pnpm dev doctor --pretty

Publishing the CLI

session-bandit is a self-contained npm package: tsup bundles the whole @session-bandit/core engine into the CLI dist/, so the published package has exactly one runtime dependency (commander) and no workspace:* references. End users need only Node.js 22+ — no pnpm, no monorepo checkout.

The publishable package is packages/cli (the repo root and core package are not published). The prepublishOnly / prepack lifecycle hooks rebuild dist/ (core first, then CLI) before any npm publish or npm pack, so the bundle is never stale.

pnpm run ok                  # quality gate (build + typecheck + lint:fix + test)
cd packages/cli
npm pack --dry-run           # rebuild dist/ + inspect tarball contents
npm publish                  # live (requires npm login)

The version is sourced from packages/cli/package.json. Tag the release (git tag v<version>) after publishing.

Project structure

packages/
  core/                          @session-bandit/core — indexing engine
    src/
      types.ts                   normalized Session/Message/ToolCall model
      adapter.ts                 Adapter interface
      index.ts                   indexSessions() + exports
      jsonl.ts                   JSONL reader
      diagnose.ts                doctor diagnostics (format drift, injection markers)
      stats-cache.ts             Claude aggregate stats-cache reader (stats --global)
      adapters/
        claude.ts                Claude Code adapter
        codex.ts                 Codex adapter (3 formats)
        botbandit.ts             BotBandit event-log adapter
    test/                        fixtures + tests
  cli/                           session-bandit — CLI
    src/
      bin.ts                     entry point
      index.ts                   Commander program + cli()
      scan.ts                    scanAll() + filters + sorting
      format.ts                  output formatters (JSON, table, transcript)
      commands/
        list.ts                  list command
        show.ts                  show command
        search.ts                search command
        extract.ts               extract command
        doctor.ts                doctor command (parsing health)
        stats.ts                  stats command (token usage + context window)
    test/                        tests
docs/
  prd.md                         product requirements document
  extract.md                     session extracts & digest design (primary v2 feature)
  decisions.md                   decision log (the "why" behind the structure)
  adapters.md                    how to add an agent / adapt to format drift
  format-claude.md               Claude Code on-disk format reference
  format-codex.md                Codex on-disk format reference (3 historical formats)
  format-botbandit.md            BotBandit event-log format reference
skills/session-bandit/
  SKILL.md                       Agent skill (handoff + memory note generation)

Extending

See docs/adapters.md for how to add a new agent adapter or adapt an existing one when a provider changes its on-disk format. Per-agent format details live in docs/format-claude.md, docs/format-codex.md, and docs/format-botbandit.md. The rationale behind the structural choices is in docs/decisions.md.

Roadmap

Done:

  • Session extracts — the primary v2 feature. extract computes a structured digest (substance score, files touched, commands, errors, key turns) and can emit a ready-to-send synthesis prompt. See docs/extract.md.

  • doctor command — parsing health check that validates adapter assumptions against real files (format drift, injection markers, unrecognized types).

  • BotBandit adapter — parses ~/.botbandit/sessions/*.jsonl event logs, including memory and compaction events as summary messages.

  • Token usage & context-window statsstats captures per-session and aggregate token usage, the context-window limit, and peak/final context size across Claude, Codex, and BotBandit; stats --global aggregates every agent from your transcripts, broken down per agent; adding --agent claude layers in Claude's own ~/.claude/stats-cache.json lifetime totals.

Next:

  • Gemini adapter — the adapter guide uses Gemini as its worked example; implementing it would dogfood the guide and round out the big three agents.

Origin

v0.1.0 — the full search, browse, extract, and doctor feature set, plus the agent skill and npm packaging — was built by GLM-5.2 in a single session.

License

MIT

About

Offline CLI and agent skill to search, browse, and summarize local Claude Code and Codex session transcripts.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages