A CLI tool for parsing, browsing, and analysing the history of LLM coding-agent sessions. Supports two providers out of the box:
| Provider | Storage location |
|---|---|
| Gemini CLI | ~/.gemini/tmp/<project>/chats/*.json |
| OpenCode | ~/.local/share/opencode/opencode.db (SQLite) |
Python 3.10+ (uses the X | Y union-type syntax). No third-party dependencies.
python3 main.py <subcommand> [options]
The subcommands form a natural drill-down:
list-projects # discover all projects and their Project IDs
└─ list-sessions <project-id> # list sessions for one project
└─ show-session <project-id> <session-id> # read a single conversation
└─ stats / search / daily-digest # aggregate or search
The Project ID column from list-projects is the exact token you pass to
every other subcommand. The Session File / Session ID column from
list-sessions is the token you pass to show-session and stats --session.
Every subcommand that targets a specific project or session expects the exact
Project ID string as shown in list-projects.
| Provider | Format | Example |
|---|---|---|
| Gemini | gemini:<dir-name> |
gemini:nostromo |
| OpenCode | opencode:<hex-id> |
opencode:deadbeefcafe0042deadbeefcafe0042deadbeefcafe |
The global OpenCode project (not tied to any directory) appears as
opencode:global.
Discover all projects that have history, sorted by number of sessions (descending).
python3 main.py list-projects [--additional-folders DIR [DIR ...]]
Options
| Option | Description |
|---|---|
--additional-folders DIR … |
Extra directories to scan (2 levels deep) to resolve Gemini hash-named project dirs whose path cannot be found in ~/.gemini/projects.json. Pass your usual workspace roots here. |
Output columns
Name Sessions Project ID Path
------------------------------------------------------------
gemini:nostromo 172 gemini:nostromo /home/ripley/projects/nostromo
opencode:nostromo 18 opencode:deadbeefcafe0042deadbeefcafe0042deadbeefcafe /home/ripley/projects/nostromo
gemini:b4d455c0ffee1337b4d4… 206 gemini:b4d455c0ffee1337b4d455c0ffee1337b4d455c0ffee13 Unknown
| Column | Meaning |
|---|---|
| Name | Human-readable label: <provider>:<folder-name>. Use this for display only. |
| Sessions | Number of unique sessions for this project (deduplicated across any merged storage dirs). |
| Project ID | The opaque identifier to pass to all other subcommands. For Gemini this is gemini:<dir-name>; for OpenCode this is opencode:<hex-id>. |
| Path | Absolute path of the project on disk (Unknown when a hash-named dir cannot be resolved). |
Note on Gemini hash dirs — Gemini CLI stores new sessions under a SHA-256 hash of the project path. Older sessions may live under a human-readable dir name.
list-projectsmerges both into one row and deduplicates session filenames, so the count and all subsequent commands cover the full history. IfPathshowsUnknown, run again with--additional-folders ~/your/workspaceto help resolve the hash.
List all sessions for a project, sorted by start time (newest first).
python3 main.py list-sessions <Project ID>
Example
python3 main.py list-sessions "gemini:nostromo"
python3 main.py list-sessions "opencode:deadbeefcafe0042deadbeefcafe0042deadbeefcafe"
Output columns
Session File Messages Tools Started Last Updated
------------------------------------------------------------------------------------------------------------------------
session-2294-10-26T13-34-c0ffee42.json 24 23 2294-10-26 14:01:03+00:00 2294-10-26 14:48:09+00:00
ses_faceb00c0000c0dec0dec0de0000000000000000 31 47 2294-10-25 08:30:11+00:00 2294-10-25 11:45:22+00:00
| Column | Meaning |
|---|---|
| Session File | For Gemini: the JSON filename (e.g. session-2294-10-26T13-34-c0ffee42.json). For OpenCode: the session UUID (e.g. ses_faceb00c…). This is the value to pass to show-session and stats --session. |
| Messages | Total number of messages in the session (user + assistant turns). |
| Tools | Total number of tool calls made during the session. |
| Started | UTC timestamp of the first message. |
| Last Updated | UTC timestamp of the last message. |
Print the full conversation of a single session to stdout.
python3 main.py show-session <Project ID> <Session File> [--show-tools]
Options
| Option | Description |
|---|---|
--show-tools |
Also print each tool call (name + status) after the assistant turn that triggered it. Only applies to Gemini sessions where tool calls are recorded per-message. |
Output format
Project: gemini:nostromo
Session: session-2294-10-26T13-34-c0ffee42.json
====================================================================================================
[2294-10-26T14:01:03.923Z] USER:
--------------------
<user message text>
[2294-10-26T14:02:15.100Z] GEMINI:
--------------------
<assistant response text>
Tool Calls: ← only with --show-tools, Gemini only
> Tool: read_file (Status: success)
> Tool: run_shell_command (Status: success)
- The role label is
USER,GEMINI(Gemini CLI), orASSISTANT(OpenCode). - For Gemini sessions the timestamp is an ISO-8601 string; for OpenCode it is a Unix millisecond integer rendered as a UTC datetime.
- Gemini
GEMINIturns also printThoughtswhen the model recorded its internal reasoning subjects/descriptions.
Aggregate token usage, tool-call counts, and error counts. Scopes from broad to narrow: all projects → one project → one session.
python3 main.py stats [--project <Project ID>] [--session <Session File>]
Output
Statistics for Project gemini:nostromo
============================================================
Total Sessions: 42
Total Messages: 3100
Total Time Spent: 12 days, 4:30:00
Total Errors: 18
Token Usage:
Input Tokens : 120,000,000
Output Tokens : 3,500,000
Cached Tokens : 95,000,000
Thought Tokens : 800,000
Tool Tokens : 0
Grand Total : 124,300,000
Built-in Tool Usage:
replace : 540
glob : 12
MCP Tool Usage:
run_shell_command : 820
read_file : 610
…
| Section | Meaning |
|---|---|
| Total Time Spent | Sum of (lastUpdated − startTime) per session. |
| Total Errors | Tool calls whose status is not success, plus tool results that set isError or return a non-zero exit_code. |
| Token Usage | Cumulative across all turns: input, output, cache-hit, thought (Gemini extended thinking), tool, and the provider-reported grand total. Only present when the provider records token data (Gemini always does; OpenCode depends on the model). |
| Built-in Tool Usage | Tools whose name contains no underscore (e.g. replace, glob). Sorted by frequency. |
| MCP Tool Usage | Tools whose name contains an underscore (e.g. run_shell_command, read_file). Sorted by frequency. |
The built-in / MCP split is a heuristic: Gemini CLI names built-in tools without underscores and MCP tools with underscores.
Full-text search across all session messages using a Python regex.
python3 main.py search <query> [--project <Project ID>]
<query>is a Python regular expression, matched case-insensitively.- Without
--project, searches across every project (Gemini + OpenCode).
Output
Search results for 'hyperdrive':
================================================================================
[2294-01-11 20:26:39+00:00] gemini:nostromo / session-2294-01-11T20-13-c0ffee42.json (user)
> Can you wire up the hyperdrive controller and make sure the jump sequence ...
----------------------------------------
[2293-12-18 00:55:28+00:00] gemini:nostromo / session-2293-12-18T00-39-cafebabe.json (gemini)
> Here is a minimal hyperdrive bootstrap that satisfies the jump requirements ...
----------------------------------------
Found 37 matches.
Each match line shows:
- UTC timestamp of the message
<provider>:<project-name> / <session-file> (<role>)- The first 100 characters of the message content (newlines collapsed)
The count at the end is the number of messages that matched, not the number of sessions or projects.
Summarise all LLM activity that occurred on a given calendar day.
python3 main.py daily-digest [YYYY-MM-DD]
Defaults to today when the date argument is omitted.
Output sections
DAILY DIGEST - 2294-10-26
================================================================================
First Activity: 09:15:00
Last Activity: 17:42:10
Work Day Span: 8:27:10
Total Sessions: 4
Cumulative Project Time: 9:10:05
Total Errors: 12
Total Tool Calls: 95
Metrics per Project:
Project ID Sessions Tools Duration
--------------------------------------------------------------------------------
opencode:nostromo 2 61 7:30:00
gemini:sulaco 2 34 1:40:05
Daily Tool Usage Breakdown:
opencode:bash : 28
opencode:read : 18
gemini:run_shell_command : 14
…
Total Invoiced Tokens (Cumulative across all turns):
Input Tokens : 500,000
Output Tokens : 20,000
…
PROJECT: gemini:nostromo
----------------------------------------
Topics discussed:
* Please review the navigation subroutines and flag any anomalies...
* Can you add unit tests for the new hyperdrive module...
Full Stream:
USER: <first user message text>
GEMINI: <first assistant response>
…
================================================================================
| Section | Meaning |
|---|---|
| First / Last Activity | Wall-clock time (local, from the machine's perspective of UTC) of the first and last message of the day. |
| Work Day Span | Last − First — the span of the active coding day. |
| Total Sessions | Number of sessions that had at least one message on this date. |
| Cumulative Project Time | Sum of (last-message-time − first-message-time) within each session that was active today. Can exceed Work Day Span when multiple projects ran concurrently. |
| Total Errors | Same counting logic as stats. |
| Total Tool Calls | All tool invocations across all sessions on this date. |
| Metrics per Project | Per-project breakdown sorted by Duration descending. Project IDs are shown as <provider>:<name> for readability. |
| Daily Tool Usage Breakdown | Tool calls prefixed with <provider>: (e.g. opencode:bash, gemini:run_shell_command), sorted by frequency descending. |
| Total Invoiced Tokens | Cumulative token counts for today only (same labels as stats). Only present when token data is available. |
| PROJECT sections | One section per project that was active today. Lists the first line of each user message as "Topics discussed", then prints the full chronological message stream (USER / GEMINI / ASSISTANT roles only; tool output is not reprinted). |
Show per-model token and cost aggregates from the OpenCode database across all time, all projects.
python3 main.py opencode-metrics
Output
OpenCode Token & Cost Metrics
============================================================
Model Input Output Total Cost
---------------------------------------------------------------------------
claude-sonnet-4-5-weyland 1200000 85000 3500000 $1.2500
gemini-2-pro-yutani 950000 42000 2100000 $0.0000
mother-7b-local 80000 5000 85000 $0.0000
---------------------------------------------------------------------------
GRAND TOTAL 5685000 $1.2500
- Total is the value stored by OpenCode (may include cache-read tokens and
therefore exceed
Input + Output). - Cost is populated only when OpenCode records pricing data for the model;
local/self-hosted models typically show
$0.0000.
Easter egg —
mother-7b-localcosts$0.0000because MOTHER runs on Weyland-Yutani's own hardware. Company policy: crew expendable, compute free.
# 1. Discover all projects
python3 main.py list-projects
# 2. Browse sessions for one project (copy Project ID from step 1)
python3 main.py list-sessions "gemini:nostromo"
# 3. Read a specific session (copy Session File from step 2)
python3 main.py show-session "gemini:nostromo" \
"session-2294-10-26T13-34-c0ffee42.json" --show-tools
# 4. Token and tool stats for that project
python3 main.py stats --project "gemini:nostromo"
# 5. Zoom in to a single session
python3 main.py stats \
--project "gemini:nostromo" \
--session "session-2294-10-26T13-34-c0ffee42.json"
# 6. Find all sessions where a topic came up
python3 main.py search "hyperdrive" --project "gemini:nostromo"
# 7. End-of-day review
python3 main.py daily-digest
python3 main.py daily-digest 2294-10-25 # a previous date
# 8. OpenCode cost overview
python3 main.py opencode-metrics
# 9. Resolve an unknown Gemini hash-project
python3 main.py list-projects --additional-folders ~/projects ~/work"Final report of the commercial starship Nostromo. Crew: seven. Cargo: refinery processing 20,000,000 tokens of raw ore. Contact with LLM: achieved. — Ripley"