Skip to content

Index schema

The SQLite index at ~/.claudex/index.db. Schema version: 7.

Not a stable surface

Table and column names may change between releases. Use claudex <cmd> --json for automation. This page is for curiosity and debugging.

meta

Single-row key/value scratchpad.

ColumnTypeNotes
keyTEXT PKe.g. schema_version, last_sync:<provider>.
valueTEXTStringified value.

schema_version drives the forward-only migration ladder; last_sync:<id> and sessions_root:<id> track each provider's incremental sync independently; pricing_revision records the rate-card version this index was last priced at (drives the automatic one-off reprice — see Pricing).

sessions

One row per transcript file, across every provider.

ColumnTypeNotes
idINTEGER PKSurrogate key.
project_nameTEXTDecoded project name, with (worktree) for worktree sessions.
file_pathTEXT UNIQUEAbsolute path to the transcript.
file_sizeINTEGERBytes. Part of the incremental-sync key.
file_mtimeINTEGERUnix seconds. Part of the sync key.
session_idTEXTSession id from the provider.
parent_session_idTEXTSet for Claude subagent transcripts (roll up to parent).
first_timestampINTEGERUnix ms.
last_timestampINTEGERUnix ms.
duration_msINTEGERLast minus first.
message_countINTEGERUser + assistant.
modelTEXTSole model tag, or mixed when a session switched models.
indexed_atINTEGERUnix seconds.
providerTEXTclaude / codex / copilot / copilot-vscode / pi / openclaw.
present_on_diskINTEGER1 if the source file still exists, 0 if retained-after-delete.
archived_atINTEGERUnix seconds when the file was archived/removed (NULL if live).
last_seenINTEGERUnix seconds of the last sync that observed the file.
extrasTEXTProvider-specific metadata as a JSON object (cli_version, git, …).
source_keyTEXTProvider-scoped logical source id; OpenClaw uses this to de-duplicate trajectory-only rows with later transcripts.

Indexes: idx_sessions_project, idx_sessions_timestamp, idx_sessions_parent, idx_sessions_provider, idx_sessions_present, idx_sessions_source.

token_usage

One row per (session, model) pair. A session that switched models has multiple rows.

ColumnNotes
session_idFK → sessions.id (ON DELETE CASCADE).
modelModel tag.
assistant_message_countAssistant messages contributing to the row.
input_tokens, output_tokens, cache_creation_tokens, cache_read_tokensFour counters.
cost_usdPre-computed cost for this row.
cost_sourcecomputed (priced from the tier table) or provider (a provider-reported cost, e.g. Pi/OpenClaw). Repricing only touches computed rows.
inference_geoDistinct reported regions for the row, joined with ASCII Unit Separator (\u001f) in the raw DB value.
speedAverage tokens/sec for the session-model row, if reported.
service_tierDistinct reported service tiers for the row, joined with ASCII Unit Separator (\u001f) in the raw DB value.
iterationsCount of messages contributing to the row.

Index: idx_token_usage_session.

tool_calls

One row per (session, tool_name) pair.

ColumnNotes
session_idFK.
tool_nameTool name as reported (e.g. Edit, Bash, mcp__*__*).
countInvocations.

Index: idx_tool_calls_session.

turn_durations

One row per turn.

ColumnNotes
session_rowidFK.
turn_number1-based.
duration_msWall-clock from user message to assistant reply.
timestampISO-8601 string of the user message.

Index: idx_turn_durations_session.

One row per PR URL detected in the session.

ColumnNotes
session_rowidFK.
pr_numberParsed from URL.
pr_urlFull URL.
pr_repositoryowner/repo.
timestampWhen the URL appeared.

file_modifications

One row per file edit event.

ColumnNotes
session_rowidFK.
file_pathAs recorded.
is_snapshot_update1 for standard Edit/Write; 0 for special cases.

Indexes: idx_file_mods_session, idx_file_mods_path.

thinking_usage

ColumnNotes
session_rowidFK.
thinking_blocksCount of extended-thinking blocks.
thinking_tokensToken count, if available.

stop_reasons

ColumnNotes
session_rowidFK.
stop_reasonend_turn, tool_use, max_tokens, etc.
countNumber of messages with this reason.

attachments

ColumnNotes
session_rowidFK.
filenameAs attached.
mime_typeIf recorded.

permission_changes

ColumnNotes
session_rowidFK.
modePermission mode switched into.
timestampISO-8601.

messages_fts (virtual)

FTS5 virtual table over every user + assistant message.

sql
CREATE VIRTUAL TABLE messages_fts USING fts5(
    session_id   UNINDEXED,
    message_type,
    content,
    timestamp    UNINDEXED,
    tokenize     = 'porter unicode61'
);

Used by search. The porter stemmer means migrat matches migration, migrated, migrates.

Migration strategy

Migrations are forward-only and non-destructive. Bumping SCHEMA_VERSION runs a migration ladder of guarded ALTER TABLE ADD COLUMN steps — it never drops tables, because the index retains sessions that have left disk and those rows can't be rebuilt. Add a column to the CREATE TABLE IF NOT EXISTS block and an additive migration step, then bump the version. The only destructive path is claudex index --force.

Cost values are versioned separately by pricing_revision: when the rate card (ModelPricing::for_model) changes, that constant is bumped and the next open reprices every cost_source = 'computed' row in place — non-destructively, so retained/archived rows are corrected too. See Pricing → Repricing.

Released under the MIT License.