Skip to content

Field Manual

Session Stores

Session stores hold continuity: prompts, tool records, local state, memory, and resume metadata that can tie a timeline together.

Why it matters

Without session stores, an investigation may see final files but miss the sequence of decisions and tool actions that produced them.

Evidence to look for

  • Session IDs
  • Conversation JSONL or databases
  • Workspace paths
  • Tool-call transcripts
  • Resume markers
  • Local agent memory

Common pitfalls

  • Running tools that rotate or compact sessions
  • Collecting only visible chat export
  • Sharing raw stores that contain secrets

Session store formats by agent

Each agent uses a different storage format and directory structure. Understanding these differences is essential for locating, preserving, and parsing session evidence.

Codex CLI session store

Codex stores sessions as JSONL files organized by date. Each session file contains a session_meta header followed by event_msg records. Codex maintains three session directories: active sessions, archived sessions, and headless sessions.

Artifact Paths

Active sessions

~/.codex/sessions/YYYY/MM/*.jsonl

JSONL files organized by year and month.

Archived sessions

~/.codex/archived_sessions/*.jsonl

Completed sessions moved from active.

Headless sessions

~/.codex/headless/*.jsonl

Non-interactive agent runs.

Codex — JSONL session with session_meta header
JSON
{"type":"session_meta","timestamp":"2026-04-03T06:00:00Z","payload":{"source":"cli","model_provider":"fixture-provider","agent_nickname":"fixture-agent","model":"fixture-model"}}

{"type":"event_msg","timestamp":"2026-04-03T06:00:01Z","payload":{"type":"user_message","message":"Inventory the MCP configuration for this synthetic workspace."}}

{"type":"event_msg","timestamp":"2026-04-03T06:00:02Z","payload":{"type":"tool_call","tool_name":"mcp_inspector","command":"probe mcp servers","arguments":{"server":"filesystem","inventory_method":"tools/list"}}}

Codex sessions always start with a session_meta record. Respects $CODEX_HOME if set.

Claude Code session store

Claude Code stores sessions as JSONL files organized by project. Each project directory contains session files with alternating user and assistant message records.

Artifact Paths

Project sessions

~/.claude/projects/<project-hash>/*.jsonl

One directory per project. Each JSONL file is one session.

Claude — JSONL with user/assistant message records
JSON
{"type":"user","sessionId":"claude-tool-use","timestamp":"2026-04-27T12:10:00Z","message":{"role":"user","content":[{"type":"text","text":"Read the project README and summarize it."}]}}

{"type":"assistant","sessionId":"claude-tool-use","timestamp":"2026-04-27T12:10:01Z","message":{"role":"assistant","model":"claude-fixture-model","content":[{"type":"text","text":"I will read the public README only."},{"type":"tool_use","id":"toolu_fixture_read","name":"Read","input":{"file_path":"README.md"}}]}}

Claude Code sessions use type values of user and assistant at the top level. Tool calls and results are nested inside message.content arrays.

OpenCode session store

Telltale retains only opencode.sqlite. Linux discovery uses $XDG_DATA_HOME/opencode/opencode.db or ~/.local/share/opencode/opencode.db; macOS and Windows use platform data roots. Current stores with session_v2 and session_message are read from those tables only. Legacy message and part tables are read only when v2 tables are absent. Filesystem JSON is legacy: support is no longer maintained.

Artifact Paths

Current (SQLite — v2 session_message)

~/.local/share/opencode/opencode.db

Read when session_v2 and session_message exist. Tool entries are in message data. macOS: ~/Library/Application Support/opencode/opencode.db.

Legacy schema (part and message)

~/.local/share/opencode/opencode.db

Still read only when v2 tables are absent. Not the current format. Do not describe this as a 5,000-row current cursor.

Legacy (per-message JSON)

~/.local/share/opencode/storage/message/<session-id>/*.json

Legacy. Support no longer maintained. Not scanned.

OpenCode SQLite — part table schema and a tool row
SQL
CREATE TABLE part (
  id           TEXT PRIMARY KEY,
  message_id   TEXT NOT NULL,
  session_id   TEXT NOT NULL,
  time_created INTEGER NOT NULL,
  time_updated INTEGER NOT NULL,
  data         TEXT NOT NULL  -- JSON: {"type":"tool","tool":"bash","state":{"status":"completed","input":{"command":"cat .env"},"output":"..."}}
);

Legacy schema example, not the current v2 stream. Read only when session_v2 and session_message are absent.

OpenCode SQLite — message table (legacy compat)
SQL
CREATE TABLE message (
  id         TEXT,
  sessionID  TEXT,
  data       TEXT  -- JSON blob with role, modelID, providerID, agent, time, type, tool_name, arguments, content
);

The retained SQLite source can read message data alongside part rows. This is distinct from the retired filesystem JSON sources.

OpenCode — legacy per-message JSON (older installations)
JSON
[
  {
    "id": "msg-cred-1",
    "sessionID": "opencode-uc002-credential-publish",
    "type": "tool_call",
    "tool_name": "bash",
    "arguments": { "command": "cat ~/.aws/credentials" },
    "modelID": "fixture-model",
    "providerID": "fixture-provider",
    "time": "2026-04-28T10:00:00Z",
    "agent": "build"
  }
]

Historical shape only. Current Telltale has no filesystem JSON acquisition for OpenCode.

Legacy — Roo Code and Kilo Code

Legacy. Support is no longer maintained. These are not Telltale sources. The JSON below is an old synthetic fixture, not a verified current product schema. Preserve the files the installed version actually wrote.

Artifact Paths

Roo Code

~/.config/Code/User/globalStorage/rooveterinaryinc.roo-cline/tasks/<task-id>/ui_messages.json

VS Code extension storage. macOS: ~/Library/Application Support/Code/. Windows: %APPDATA%\Code\.

Kilo Code

~/.config/Code/User/globalStorage/kilocode.kilo-code/tasks/<task-id>/ui_messages.json

Legacy. Support no longer maintained. Not a verified shared schema with Roo Code.

Roo Code — ui_messages.json flat array
JSON
[
  { "type": "user", "content": "Check the repository status." },
  { "type": "tool_call", "name": "repo_status", "input": { "format": "json" } },
  { "type": "tool_result", "tool": "repo_status", "content": "status=ok" }
]

Old synthetic fixture only. Do not treat name and input as the installed Roo or Kilo schema.

Qwen CLI session store

Qwen CLI stores sessions as JSONL files organized by project. Each record carries agent, provider, and model fields at the root level alongside the event data.

Artifact Paths

Project sessions

~/.qwen/projects/**/*.jsonl

JSONL files under project chats directories. Each record carries type, model, timestamp, sessionId, and usageMetadata.

OpenClaw session store

OpenClaw stores sessions as JSONL-like files in an agents directory. The discovery pattern matches any file containing .jsonl in the name, including archived and reset variants.

Artifact Paths

Agent sessions

~/.openclaw/agents/*.jsonl

JSONL files. Also discovers .jsonl.deleted, .jsonl.archived, and .jsonl.reset variants.

GitHub Copilot session store

GitHub Copilot CLI records sessions as plain text process logs in the repository directory. This is the most limited and lossy session store format.

Artifact Paths

Process logs

<repo>/logs/copilot/process-*.log

Plain text log files. Tool calls are embedded as JSON in log lines.

Copilot — process log with embedded function_call
TEXT
2026-04-27T16:16:57.841Z [INFO] Workspace initialized: copilot-uc001-tool-result (checkpoints: 0)
2026-04-27T16:16:57.847Z [INFO] Starting Copilot CLI: 1.0.36
2026-04-27T16:17:17.990Z [INFO] Accumulated output items (1): [{"arguments":"{\"format\":\"json\"}","call_id":"call_fixture_001","id":"c1","name":"repo_status","status":"completed","type":"function_call"}]
2026-04-27T16:17:45.200Z [INFO] Session completed.

Copilot process logs are the most lossy format. User intent, system instructions, and structured content are not preserved. Tool call arguments are stringified JSON.

Preservation priorities

When preserving session stores for investigation, follow these priorities:

  • Copy the raw files first. Do not parse, normalize, or transform before preserving. Use forensic copy tools when possible.
  • Record the source path and collection time. Provenance metadata is essential for defending the evidence chain.
  • Check current registered variants: Codex active, archived, and headless sessions; OpenClaw archived/reset suffixes; OpenCode SQLite only. Historical JSON stores require separate authorized preservation, not an assumption of scanner support.
  • Hash the preserved files. SHA-256 hashes let you verify that preserved copies have not been modified.
  • Do not run the agent or its tools on the preserved copy. Session stores can be modified by agent startup, compaction, or rotation.
  • Roo Code and Kilo Code are legacy. Support is no longer maintained. Preserve their files only as raw evidence, not as a Telltale source.