Shared Sessions for Claude Code
Share a Claude Code session with a link. Teammates join from their own Claude Code and work in it together.
Share AI coding sessions across tools by indexing messages into a searchable vector database
AI summary · README
PluginsTypeScript · CSSGitHub @djannotSelf-installOwner unconfirmed
Paste into Claude or ChatGPT for installation instructions suited to your environment.
Have you tried it? One tap is enough. No sign-in needed.
No updates detected yet. GitHub releases will appear here.
Owners of public repositories under a personal GitHub account can sign in to verify ownership and manage the introduction themselves. No administrator approval is needed.
Sign in, generate a verification file, and commit it to this repository’s default branch within 30 minutes. Files on other branches or forks do not count. Then check the file below to manage the project without administrator approval. Keep the file to retain your access.
If needed, you will go to sign-in. After signing in, return here and press your chosen verification button again.
Installable projects can be verified without a deployment domain. Use GitHub sign-in for a personal repository, or the repository verification file above for an organization repository.
Ask about other verification options
Loading the full README. The saved excerpt is shown below.
Automatic vector memory for OpenCode, Claude Code, Cursor, VS Code, Codex, and Gemini CLI sessions — shared across all tools.
Every time the AI agent finishes its turn, code-session-memory automatically indexes the new messages into a vector database. Past sessions become semantically searchable — both by the AI agent (via the MCP server) and by you. Sessions from OpenCode, Claude Code, Cursor, VS Code, Codex, and Gemini CLI are stored in the same database, so memory is shared across tools.Read the full README ↗Automatic vector memory for OpenCode, Claude Code, Cursor, VS Code, Codex, Gemini CLI, and Antigravity sessions — shared across all tools.
Every time the AI agent finishes its turn, code-session-memory automatically indexes the new messages into a vector database. Past sessions become semantically searchable — both by the AI agent (via the MCP server) and by you. Sessions from OpenCode, Claude Code, Cursor, VS Code, Codex, Gemini CLI, and Antigravity are stored in the same database, so memory is shared across tools.
By default, data is stored locally in a sqlite-vec database. Optionally, you can use PostgreSQL + pgvector (e.g. Supabase) as a centralized backend to share memory across multiple machines.
Only new messages are indexed on each turn — previously indexed messages are skipped (tracked via sessions_meta table). This makes each indexing pass fast, even in long sessions.
better-sqlite3 13 ships prebuilt Node-API binaries, so no compiler is needed and new Node majors such as 26 work out of the box)text-embedding-3-large)npx code-session-memory install
The install command sets up everything for all detected tools on your machine:
OpenCode:
~/.config/opencode/plugins/code-session-memory.ts~/.config/opencode/skills/code-session-memory/SKILL.md~/.config/opencode/opencode.jsonClaude Code:
Stop hook to ~/.claude/settings.json (fires after each agent turn)~/.claude/skills/code-session-memory/SKILL.md~/.claude.jsonCursor:
stop hook to ~/.cursor/hooks.json (fires after each agent turn; requires Cursor v2.5+)~/.cursor/mcp.json~/.cursor/skills/code-session-memory/SKILL.mdVS Code:
Stop hook to ~/.vscode/hooks/code-session-memory.json (Copilot hook format)settings.json via chat.hookFilesLocations~/.config/Code/User/mcp.json (Linux) or ~/Library/Application Support/Code/User/mcp.json (macOS)Codex:
~/.codex/config.tomlOPENAI_API_KEY to Codex MCP environment variable passthroughnotify hook in ~/.codex/config.toml (fires after each agent turn)~/.codex/skills/code-session-memory/SKILL.mdGemini CLI:
~/.gemini/settings.json under mcpServers.code-session-memoryAfterAgent hook in ~/.gemini/settings.json (fires after each agent turn)~/.gemini/skills/code-session-memory/SKILL.mdAntigravity 2.x:
~/.gemini/config/mcp_config.json under mcpServers.code-session-memoryStop lifecycle hook into ~/.gemini/config/hooks.json (fires when the execution loop terminates)~/.gemini/config/skills/code-session-memory/SKILL.mdAntigravity shares the ~/.gemini directory with Gemini CLI but reads none of its
files: its global customization root is ~/.gemini/config/. One install covers all
three Antigravity surfaces — the 2.x app, the IDE and the CLI.
All tools share:
~/.local/share/code-session-memory/sessions.dbnode binary that ran the install (hooks never rely on PATH)~/.config/code-session-memory/env.json (mode 0600)~/.config/code-session-memory/logs/hook.logThen restart OpenCode / Claude Code / Cursor / VS Code / Codex / Gemini CLI / Antigravity to activate.
VS Code note: Ensure Chat: Use Hooks is enabled in VS Code settings (it is by default in VS Code 1.109.3+).
Codex note: The install command sets
notify = ["/abs/path/to/node", ".../indexer-cli-codex.js"]and MCP env passthrough["OPENAI_API_KEY"]in~/.codex/config.toml.Gemini CLI note: The install command sets an
AfterAgenthook invokingindexer-cli-gemini.jsin~/.gemini/settings.json.Antigravity note: The install command adds a named
code-session-memoryhook with aStophandler invokingindexer-cli-antigravity.jsin~/.gemini/config/hooks.json. Antigravity hooks block the agent loop, so the handler is given a 120-second timeout (the default is 30).
export OPENAI_API_KEY=sk-...
Add this to your shell profile (.bashrc, .zshrc, etc.) so it's always available,
and run npx code-session-memory install from a shell where it is exported.
Apps started from the GUI — the Dock, the Start menu, a desktop launcher — do not
inherit your shell environment: on macOS launchd gives them
PATH=/usr/bin:/bin:/usr/sbin:/sbin and nothing you exported from .zshrc.
Hooks inherit that same bare environment, and hosts discard hook stderr, so a
hook that cannot find node or OPENAI_API_KEY used to fail invisibly.
Install handles both halves of this, on every platform:
node is recorded as an absolute path in every hook command and MCP
server entry, so PATH never matters.~/.config/code-session-memory/env.json (mode 0600), and every entry point
merges that file into its environment. Variables the host does provide
always win.If the snapshot is missing the API key, a hook asks your login shell for it once (POSIX only, with a short timeout) and saves what it finds. A probe that comes back empty is not retried for six hours, so a misconfigured setup never slows down every turn.
Set or inspect the snapshot at any time:
npx code-session-memory config set-env OPENAI_API_KEY=sk-...
npx code-session-memory config set-env OPENAI_API_KEY # copy from this shell
npx code-session-memory config env
Restart the desktop app fully (quit, not just close the window) after installing.
npx code-session-memory status ends with a Runtime section that reports the
node binary baked into the configs (flagging one that no longer exists, e.g.
after an nvm upgrade), the contents of the env snapshot, and the last hook run
and last hook error. The full history is in
~/.config/code-session-memory/logs/hook.log — that file is the only trace hooks
leave, since hosts discard their stderr.
Once installed, memory indexing is fully automatic. No further action needed — sessions are indexed as you use OpenCode, Claude Code, Cursor, VS Code, Codex, Gemini CLI, or Antigravity.
npx code-session-memory status
Output:
code-session-memory status
Database ~/.local/share/code-session-memory/sessions.db ✓
Indexed chunks: 1842
Sessions tracked: 47
OpenCode
Plugin ~/.config/opencode/plugins/code-session-memory.ts ✓
Skill ~/.config/opencode/skills/code-session-memory/SKILL.md ✓
MCP server /path/to/dist/mcp/index.js ✓
MCP config ~/.config/opencode/opencode.json ✓
Claude Code
Stop hook ~/.claude.json ✓
Skill ~/.claude/skills/code-session-memory/SKILL.md ✓
MCP server /path/to/dist/mcp/index.js ✓
VS Code
MCP config ~/.config/Code/User/mcp.json ✓
Stop hook ~/.vscode/hooks/code-session-memory.json ✓
Hook loc ~/.config/Code/User/settings.json ✓
Codex
MCP config ~/.codex/config.toml ✓
Notify hook ~/.codex/config.toml ✓
Skill ~/.codex/skills/code-session-memory/SKILL.md ✓
Gemini CLI
MCP config ~/.gemini/settings.json ✓
AfterAgent ~/.gemini/settings.json ✓
Skill ~/.gemini/skills/code-session-memory/SKILL.md ✓
Antigravity
MCP config ~/.gemini/config/mcp_config.json ✓
Stop hook ~/.gemini/config/hooks.json ✓
Skill ~/.gemini/config/skills/code-session-memory/SKILL.md ✓
The agent can use two MCP tools (and will automatically via the installed skill):
query_sessionsSemantic search across all indexed sessions.
| Parameter | Type | Required | Description |
|---|---|---|---|
queryText | string | yes | Natural language query |
project | string | no | Filter by project directory path |
source | string | no | Filter by tool: "opencode", "claude-code", "cursor", "vscode", "codex", "gemini-cli", or "antigravity" |
limit | number | no | Max results (default: 5) |
fromDate | string | no | Return chunks indexed on or after this date (ISO 8601, e.g. "2026-02-01") |
toDate | string | no | Return chunks indexed on or before this date (ISO 8601, e.g. "2026-02-20") |
Example result:
Result 1:
Content: [Session: Add dark mode toggle > User]
How can I implement a dark mode toggle using CSS variables?
Distance: 0.1823
URL: session://ses_abc123#msg_def456
Section: User
Chunk: 1 of 1
---
get_session_chunksRetrieve the full ordered content of a specific session message. Use the session://ses_xxx#msg_yyy URL from query_sessions results.
| Parameter | Type | Required | Description |
|---|---|---|---|
sessionUrl | string | yes | URL from query_sessions result |
startIndex | number | no | First chunk index (0-based) |
endIndex | number | no | Last chunk index (0-based, inclusive) |
You can search your indexed sessions directly from the terminal without going through the AI agent:
npx code-session-memory query "authentication middleware"
npx code-session-memory query "auth flow" --source opencode
npx code-session-memory query "session summary" --source codex
npx code-session-memory query "hook payload format" --source gemini-cli
npx code-session-memory query "customization root" --source antigravity
npx code-session-memory query "migration" --limit 10
npx code-session-memory query "error handling" --from 2026-02-01 --to 2026-02-20
| Flag | Default | Description |
|---|---|---|
--source <s> | none | Filter by tool: opencode, claude-code, cursor, vscode, codex, gemini-cli, or antigravity |
--limit <n> | 5 | Max number of results |
--from <date> | none | Only include sessions from this date (ISO 8601, e.g. 2026-02-01) |
--to <date> | none | Only include sessions up to this date (inclusive) |
Requires OPENAI_API_KEY to be set (used to embed the query text).
Example output:
Found 2 result(s) for "authentication middleware" (limit=5)
1. [1.1665] "Implement auth flow" (opencode)
Section: Assistant
Chunk 1/3 — session://ses_abc123#msg_def456
────────────────────────────────────────────────────────────
[Session: Implement auth flow > Assistant]
We implemented JWT authentication middleware using Express.js...
────────────────────────────────────────────────────────────
You can browse, inspect, and delete indexed sessions directly from the CLI:
npx code-session-memory sessions # interactive browser (source → date → session)
The interactive browser lists all sessions with their title, date, source tool, and chunk count. Select a session to:
The "Compact for restart" action generates a structured restart document containing:
For long sessions the compactor uses a map-reduce strategy: it splits the transcript into windows, summarizes each independently, then merges the partial summaries into a final digest.
Requires OPENAI_API_KEY. Uses gpt-5-nano by default (override with OPENAI_SUMMARY_MODEL).
After compaction, the CLI prints total token usage (input, output, total).
You can also print or delete directly. Without an ID, an interactive picker opens:
npx code-session-memory sessions print # pick interactively, then print
npx code-session-memory sessions print <id> # print directly by session ID
npx code-session-memory sessions delete # pick interactively, then delete
npx code-session-memory sessions delete <id> # delete directly by session ID
Print output example:
────────────────────────────────────────────────────────────────────────
Session: Add authentication middleware
Source: opencode 2026-02-18
Project: /Users/you/myproject
ID: ses_abc123
Chunks: 12
────────────────────────────────────────────────────────────────────────
## Chunk 1/12 — Section: User
How can I add JWT authentication to the Express middleware?
## Chunk 2/12 — Section: Assistant
...
Note: Deleting a session only removes it from the database. If the original session files still exist on disk, the session will be re-indexed automatically on the next agent turn.
A full-featured web interface provides the same capabilities as the CLI in a modern browser-based dashboard:
npx code-session-memory web
Open http://localhost:3333 in your browser. The web UI includes:
Options:
| Flag | Default | Description |
|---|---|---|
--port <n> | 3333 | Port to listen on |
--host <h> | localhost | Host to bind to (use 0.0.0.0 for network access) |
For development with hot reload:
npx code-session-memory web # API server on :3333
npm run dev:web # Vite dev server on :5173 (proxies /api to :3333)
The installed skill teaches the agent when and how to use these tools. Example prompts:
How did we implement the authentication middleware last week?
Have we discussed this error before?
What was our decision about the database schema?
Show me how we solved the TypeScript config issue.
| Variable | Default | Description |
|---|---|---|
OPENAI_API_KEY | — | Required. Used for embedding generation and session compaction. Recorded in the env snapshot at install time for GUI-launched apps. |
OPENCODE_MEMORY_DB_PATH | ~/.local/share/code-session-memory/sessions.db | Override the database path. |
OPENCODE_CONFIG_DIR | ~/.config/opencode | Override the OpenCode config directory. |
CLAUDE_CONFIG_DIR | ~/.claude | Override the Claude Code config directory. |
CURSOR_CONFIG_DIR | ~/.cursor | Override the Cursor config directory. |
VSCODE_CONFIG_DIR | ~/.config/Code/User (Linux) / ~/Library/Application Support/Code/User (macOS) | Override the VS Code config directory. |
CODEX_HOME | ~/.codex | Override the Codex home directory. |
GEMINI_CONFIG_DIR | ~/.gemini | Override the Gemini CLI config directory (Antigravity's surfaces live under it too). |
ANTIGRAVITY_CONFIG_DIR | ~/.gemini/config | Override Antigravity's global customization root. |
OPENAI_MODEL | text-embedding-3-large | Override the embedding model. |
OPENAI_SUMMARY_MODEL | gpt-5-nano | Override the model used for session compaction (Compact for restart). |
CSM_SUMMARY_MAX_OUTPUT_TOKENS | 5000 | Override the max output token budget for session compaction. |
CSM_BACKEND | sqlite | Database backend: sqlite (default) or postgres. |
CSM_POSTGRES_URL | — | PostgreSQL connection string (when CSM_BACKEND=postgres). |
The default database path works on both macOS and Linux. On macOS, ~/.local/share is used for cross-platform consistency (rather than ~/Library/Application Support).
To change it:
export OPENCODE_MEMORY_DB_PATH=/custom/path/sessions.db
npx code-session-memory install
Instead of the default local SQLite database, you can use PostgreSQL with pgvector as a centralized backend. This is useful when you want to:
npx code-session-memory config set-backend postgres --url "postgresql://user:[email protected]:5432/postgres" --ssl
This tests the connection, creates the schema (tables + HNSW vector index + GIN full-text index), and saves the config to ~/.config/code-session-memory/config.json.
npx code-session-memory migrate
This auto-discovers your local SQLite database and migrates all data (sessions, chunks with embeddings, messages, tool calls) to PostgreSQL. Embeddings are transferred directly — no re-embedding needed.
To share memory across multiple machines, run the setup on each:
# On machine A:
npx code-session-memory config set-backend postgres --url "postgresql://..." --ssl
npx code-session-memory migrate
# On machine B:
npx code-session-memory config set-backend postgres --url "postgresql://..." --ssl
npx code-session-memory migrate
Sessions from both machines are merged into the same database. Duplicate chunks are automatically deduplicated (deterministic chunk IDs). Each machine is tagged with its hostname via origin_host in sessions_meta.
npx code-session-memory config set-backend sqlite
npx code-session-memory config show
npx code-session-memory migrate --help
| Flag | Description |
|---|---|
--sqlite <path> | Explicit SQLite DB path (repeatable). Default: auto-discover. |
--pg-url <url> | Override Postgres URL (if not yet configured). |
--origin <name> | Label for this machine (default: hostname). |
--dry-run | Preview counts without writing. |
--batch-size <n> | Rows per INSERT batch (default: 100). |
The backend configuration is stored at ~/.config/code-session-memory/config.json:
{
"backend": "postgres",
"postgres": {
"url": "postgresql://user:pass@host:5432/dbname",
"ssl": true
}
}
Configuration priority: environment variables (CSM_BACKEND + CSM_POSTGRES_URL) > config file > default SQLite.
code-session-memory/
├── src/
│ ├── types.ts # Shared TypeScript types
│ ├── config.ts # Backend config resolution (SQLite / Postgres)
│ ├── database.ts # SQLite-vec: init, insert, query
│ ├── providers/
│ │ ├── types.ts # DatabaseProvider async interface
│ │ ├── index.ts # createProvider() factory
│ │ ├── sqlite-provider.ts # SQLite implementation (wraps database.ts)
│ │ ├── pg-provider.ts # PostgreSQL + pgvector implementation
│ │ └── pg-schema.ts # PostgreSQL DDL (tables, indexes)
│ ├── migrate/
│ │ └── sqlite-to-pg.ts # Migration tool (SQLite → PostgreSQL)
│ ├── chunker.ts # Heading-aware markdown chunker
│ ├── embedder.ts # OpenAI embeddings (parallel batched)
│ ├── session-to-md.ts # OpenCode SDK messages → markdown
│ ├── transcript-to-messages.ts # Claude Code JSONL transcript parser
│ ├── cursor-to-messages.ts # Cursor state.vscdb reader (metadata + title)
│ ├── cursor-transcript-to-messages.ts # Cursor JSONL transcript parser → FullMessage[]
│ ├── vscode-transcript-to-messages.ts # VS Code JSONL transcript parser → FullMessage[]
│ ├── codex-session-to-messages.ts # Codex JSONL session parser → FullMessage[]
│ ├── gemini-session-to-messages.ts # Gemini CLI JSON session parser → FullMessage[]
│ ├── antigravity-transcript-to-messages.ts # Antigravity JSONL transcript parser → FullMessage[]
│ ├── opencode-db-to-messages.ts # OpenCode internal DB reader (fallback for -s mode)
│ ├── indexer.ts # Orchestrator: incremental indexing
│ ├── indexer-cli.ts # Node.js subprocess (called by OpenCode plugin)
│ ├── indexer-cli-claude.ts # Node.js subprocess (called by Claude Code hook)
│ ├── indexer-cli-cursor.ts # Node.js subprocess (called by Cursor stop hook)
│ ├── indexer-cli-vscode.ts # Node.js subprocess (called by VS Code Stop hook)
│ ├── indexer-cli-codex.ts # Node.js subprocess (called by Codex notify hook)
│ ├── indexer-cli-gemini.ts # Node.js subprocess (called by Gemini CLI AfterAgent hook)
│ ├── indexer-cli-antigravity.ts # Node.js subprocess (called by the Antigravity Stop hook)
│ ├── cli.ts # install / status / uninstall / reset-db / query / web commands
│ ├── cli-query.ts # query command: semantic search from the terminal
│ ├── cli-sessions.ts # sessions list / print / delete / purge (TUI)
│ ├── status.ts # Shared status helpers (tool detection, DB stats)
│ └── web/
│ ├── server.ts # Express server (API + static files + SPA fallback)
│ └── api-routes.ts # REST API route handlers
├── mcp/
│ ├── server.ts # MCP query handlers (testable, injected deps)
│ └── index.ts # MCP stdio server entry point
├── plugin/
│ └── memory.ts # OpenCode plugin (session.idle hook)
├── skill/
│ └── memory.md # Skill instructions (injected into all tools)
├── web/ # React + Vite + Tailwind SPA (web UI)
│ ├── src/
│ │ ├── api/client.ts # Fetch wrapper for REST API
│ │ ├── components/ # Reusable UI components
│ │ ├── pages/ # Route pages (Search, Sessions, Status)
│ │ └── hooks/ # React hooks for data fetching
│ ├── vite.config.ts
│ └── package.json
├── scripts/
│ └── generate-fixtures.ts # Generates committed e2e test fixtures (run manually)
└── tests/
├── chunker.test.ts
├── database.test.ts
├── embedder.test.ts
├── indexer.test.ts
├── mcp-server.test.ts
├── session-to-md.test.ts
├── cursor-to-messages.test.ts # Unit tests: Cursor SQLite reader
├── cursor-transcript-to-messages.test.ts # Unit tests: Cursor JSONL parser
├── vscode-transcript-to-messages.test.ts # Unit tests: VS Code JSONL parser
├── codex-session-to-messages.test.ts # Unit tests: Codex JSONL parser
├── gemini-session-to-messages.test.ts # Unit tests + e2e indexing: Gemini CLI parser
├── antigravity-transcript-to-messages.test.ts # Unit tests + e2e indexing: Antigravity parser
├── opencode-db-to-messages.test.ts # Unit tests: OpenCode internal DB reader
├── cli-query.test.ts # Unit tests: query CLI command
├── e2e-claude.test.ts # End-to-end: Claude Code pipeline
├── e2e-cursor.test.ts # End-to-end: Cursor pipeline
├── e2e-opencode.test.ts # End-to-end: OpenCode pipeline
└── fixtures/ # Committed session files (generated by generate-fixtures)
# Install dependencies
npm install
# Build (backend + web UI)
npm run build
# Build web UI only
npm run build:web
# Run web UI dev server (hot reload, proxies API to :3333)
npm run dev:web
# Run tests
npm test
# Watch mode
npm run test:watch
# Coverage report
npm run test:coverage
# Regenerate e2e fixtures (requires claude and opencode CLIs)
npm run generate-fixtures
Tests use Vitest and run without any external dependencies:
:memory:) for unit tests, temp files for indexer/e2e teststests/fixtures/ (real transcripts, no CLI calls during npm test) ✓ tests/chunker.test.ts (15 tests)
✓ tests/mcp-server.test.ts (14 tests)
✓ tests/session-to-md.test.ts (21 tests)
✓ tests/embedder.test.ts (9 tests)
✓ tests/database.test.ts (27 tests)
✓ tests/indexer.test.ts (9 tests)
✓ tests/cursor-to-messages.test.ts (15 tests)
✓ tests/cursor-transcript-to-messages.test.ts (7 tests)
✓ tests/vscode-transcript-to-messages.test.ts (7 tests)
✓ tests/codex-session-to-messages.test.ts (14 tests)
✓ tests/gemini-session-to-messages.test.ts (5 tests)
✓ tests/antigravity-transcript-to-messages.test.ts (13 tests)
✓ tests/opencode-db-to-messages.test.ts (8 tests)
✓ tests/cli-query.test.ts (23 tests)
✓ tests/e2e-claude.test.ts (18 tests)
✓ tests/e2e-cursor.test.ts (8 tests)
✓ tests/e2e-opencode.test.ts (14 tests)
Tests 336 passed
To refresh the e2e fixtures (e.g. after changing the indexer or parsers), run:
npm run generate-fixtures
This invokes the real claude and opencode CLIs to generate two-turn sessions with tool use, reads the most recent Cursor session from the live state.vscdb, then commits all results to tests/fixtures/.
npx code-session-memory uninstall
This removes the plugin, hooks, skill files, and MCP config entries for all tools (OpenCode, Claude Code, Cursor, VS Code, Codex, Gemini CLI, and Antigravity). The database is not removed automatically.
To delete individual sessions instead of wiping everything, use the session browser:
npx code-session-memory sessions
npx code-session-memory sessions delete <id>
To wipe the entire database:
rm ~/.local/share/code-session-memory/sessions.db
Or use the built-in command, which prompts for confirmation before deleting:
npx code-session-memory reset-db
code-session-memory reset-db
Database: ~/.local/share/code-session-memory/sessions.db
Indexed chunks: 1842
Sessions tracked: 47
This will permanently delete all indexed data. Confirm? [y/N] y
Done. Database reset — all indexed data removed.
The plugin/hook fires on every agent turn. To avoid re-processing the entire session history each time, the indexer:
last_indexed_message_id from the sessions_meta tablelast_indexed_message_id after successThis makes each indexing pass O(new messages) rather than O(all messages). Embedding sub-batches (64 texts each) are sent to the OpenAI API in parallel (up to 4 concurrent requests), keeping network latency low even for large sessions.
OpenCode plugins run inside Bun, but better-sqlite3 and sqlite-vec are native Node.js addons that don't load under Bun. The plugin therefore spawns a Node.js subprocess (indexer-cli.js) to handle all database operations. The Claude Code hook calls a similar subprocess (indexer-cli-claude.js) which reads the transcript JSONL from disk.
Claude Code writes a JSONL transcript after each session turn. The parser (transcript-to-messages.ts) handles:
assistant chunks (keeps the last entry per message.id)thinking blocks, metadata entries, and error messagestool_result user messages back into their corresponding tool_use assistant blocks, so each tool call is a single message with both Input and Output (matching the behavior of Cursor, Codex, and Gemini CLI parsers)Cursor provides a transcript_path field in the stop hook payload — a JSONL file written synchronously before the hook fires, so it is always complete and race-condition-free. Each line is { "role": "user"|"assistant", "message": { "content": [{ "type": "text", "text": "..." }] } }. The reader (cursor-transcript-to-messages.ts) parses this file directly, strips Cursor's <user_query> wrapper tags, and assigns stable composerId-lineIndex IDs for incremental indexing.
Session metadata (title only) is read best-effort from the SQLite state.vscdb. The Cursor stop hook fires after each agent turn and requires Cursor v2.5+.
VS Code (with GitHub Copilot agent mode) supports the same hook lifecycle events as Claude Code and provides a transcript_path in its Stop hook payload. The parser (vscode-transcript-to-messages.ts) handles the JSONL transcript similarly to Claude Code's parser, with retry logic for potential race conditions between hook firing and transcript flush. The Stop hook requires VS Code 1.109.3+ with Chat: Use Hooks enabled.
Codex stores session transcripts as JSONL under ~/.codex/sessions/YYYY/MM/DD/rollout-<timestamp>-<thread-id>.jsonl. Its notify hook passes payload as a JSON string in process.argv[2] (not stdin). The parser (codex-session-to-messages.ts) indexes only clean event_msg.user_message user inputs and assistant final_answer messages, skipping system/developer injections and commentary messages.
Gemini CLI provides transcript_path and session_id in the AfterAgent hook payload. The parser (gemini-session-to-messages.ts) reads the JSON session file, keeps user and gemini messages, maps toolCalls[] to tool-invocation parts, and derives a title from the first user prompt.
Antigravity encodes hook payloads with protojson, so every key is camelCase: conversationId, workspacePaths[], transcriptPath, modelName, terminationReason. The transcript is JSONL, one object per trajectory step, and lives at ~/.gemini/<surface>/brain/<conversationId>/.system_generated/logs/transcript.jsonl — the parser falls back to that path when the payload omits transcriptPath.
The parser (antigravity-transcript-to-messages.ts):
USER_INPUT steps, unwrapping the <USER_REQUEST> tag so the appended <ADDITIONAL_METADATA> and <USER_SETTINGS_CHANGE> blocks the user never typed are not indexed.PLANNER_RESPONSE steps as assistant messages, skipping the thinking field (internal reasoning, same as the Claude Code parser).GENERIC steps that follow a PLANNER_RESPONSE back into its tool-invocation parts — a step emitting N tool calls is followed by N result steps, in order — so each tool call is one message with both Input and Output.error as an error state, so failed tool calls are counted in analytics. Antigravity is the only source that reports this explicitly.input_tokens / cache_read_tokens / output_tokens per step. The two input figures are disjoint in Antigravity, so they map onto MessageTokens without subtraction. The model comes from the payload's modelName, not the transcript, so a re-index from the web UI cannot recover it.SYSTEM_MESSAGE steps (platform noise).Unlike the other hosts, Antigravity reads the hook's stdout: a decision of "continue" would push the agent back into its loop, so the indexer always emits a non-continue decision.
### Tool: name headings, always split into separate chunks (never merged with adjacent sections)[Session: Title > Section] breadcrumb prefix injected before embedding, improving retrieval precisionAlongside vector chunks, the indexer populates two relational tables for structured analytics:
messages table — one row per message:
| Column | Description |
|---|---|
role | user, assistant, or tool |
created_at | Timestamp (ms since epoch) |
text_length | Character count of text parts |
tool_call_count | Number of tool invocations in this message |
message_order | Position within the session |
turn_index | Turn number: incremented at every user message, shared by the assistant messages that follow |
model, provider | Model that produced an assistant message (e.g. claude-opus-5) and, for OpenCode, the provider |
input_tokens, output_tokens, cache_read_tokens, cache_write_tokens, reasoning_tokens | Token usage reported by the source (NULL when not reported) |
cost | Cost in USD when the source reports it (OpenCode) |
Model and token usage are captured for Claude Code (from message.usage in the JSONL transcript), OpenCode (from the message tokens/cost fields) and Codex (model from the per-turn turn_context, usage summed over the turn's token_count events and attached to the turn's assistant message). A single turn can involve several models (e.g. a fallback model), so the model is stored per message; per-turn statistics count such a turn once for each model.
tool_calls table — one row per tool invocation:
| Column | Description |
|---|---|
tool_name | e.g. Read, Bash, Edit, Agent |
status | call, result, or error |
has_error | 1 if the tool errored |
args_length | Size of the serialized input |
result_length | Size of the serialized output |
These tables are populated idempotently during Phase 0 of indexing (before chunk/embedding work): every message of the session is re-extracted and upserted on each run, so a session that is continued after an upgrade gets its new columns (model, tokens) filled in for all of its messages. Sessions that are never continued can be filled in without re-embedding:
npx code-session-memory backfill-analytics # all Claude Code + OpenCode + Codex sessions
npx code-session-memory backfill-analytics --source claude-code # one source only
npx code-session-memory backfill-analytics --dry-run # report without writing
The schema upgrade itself is automatic on both backends: the new columns are added the first time the new version opens the database (SQLite ALTER TABLE, Postgres idempotent migration).
Per-session analytics (shown in the web UI session detail):
Read 45, Bash 23, Edit 12)LEAD() window function over message timestamps, capping each inter-message gap at 30 minutes to exclude idle periodsREST API endpoints:
| Endpoint | Description |
|---|---|
GET /api/analytics/overview | Aggregate totals across all sessions |
GET /api/analytics/tools | Tool usage stats (filterable by source, date range) |
GET /api/analytics/messages | Message counts by role |
GET /api/analytics/models | Per-model stats: messages, turns, sessions, tool calls, token usage, cost (filterable by source, date range) |
GET /api/analytics/session/:id | Per-session analytics detail |
The MCP server uses stdio transport — the simplest and most reliable transport for local use. It opens and closes the SQLite connection on each query (no persistent connection), making it safe to run alongside the indexer. The query_sessions tool supports filtering by source (opencode, claude-code, cursor, vscode, codex, gemini-cli, antigravity), project, and date range (fromDate/toDate).
MIT
CSM_POSTGRES_SSLfalse |
Set to true for SSL connections (required for Supabase). |