Stores & config
Two fundamentally different store shapes — JSONL files on disk, and SQLite databases — unified behind one session list. Here is every one of them, and what to do when yours lives somewhere else.
crossmem config prints this for your machine, including which candidates actually exist. Start there before believing any table.
What it reads
| Tool | Store | Shape |
|---|---|---|
| Claude Code | ~/.claude/projects/<encoded-workspace>/*.jsonl | JSONL |
| Codex | ~/.codex/sessions/YYYY/MM/DD/*.jsonl | JSONL |
| Codex | ~/.codex/logs_2.sqlite, ~/.codex/history.jsonl | logs, prompt history |
| Copilot in VS Code | <code-user>/workspaceStorage/<id>/chatSessions/*.jsonl | VS Code journal |
| Copilot in VS Code | <code-user>/workspaceStorage/<id>/GitHub.copilot-chat/transcripts/*.jsonl | JSONL |
| Copilot CLI | ~/.copilot/session-store.db | SQLite |
| Devin (CLI + desktop) | ~/.local/share/devin/cli/sessions.db | SQLite |
| OpenCode | <opencode-data>/opencode*.db | SQLite |
Claude encodes the working directory into a project directory name; every VS Code fork records it in workspaceStorage/<id>/workspace.json; the SQLite stores keep it in a column. Either way, a session is matched to a folder by the real cwd it recorded, so a folder whose name contains a dash still resolves correctly.
The Devin desktop app has no separate store. It drives the Devin CLI through an ACP connector, so every session — desktop or terminal-driven — lands in the one sessions.db under the devin provider. A devin-gui provider and an encrypted Cascade store were both removed once this was verified against a real install. ADR 2.
Devin's ~/.local/share/devin/credentials.toml sits right beside the session database and is deliberately never read. Nor is any sibling auth.json, auth.db or credential table.
Per-platform locations
| Placeholder | macOS | Linux | Windows |
|---|---|---|---|
<devin-cli> | ~/.local/share/devin/cli | ~/.local/share/devin/cli | %APPDATA%\devin\cli |
<opencode-data> | ~/.local/share/opencode | ~/.local/share/opencode | %APPDATA%\opencode |
<code-user> | ~/Library/Application Support/Code/User | ~/.config/Code/User | %APPDATA%\Code\User |
Claude Code, Codex and the Copilot CLI use the same ~-relative path on every platform. %LOCALAPPDATA% and $XDG_DATA_HOME are checked too.
Environment variables that win
| Variable | Effect |
|---|---|
$CLAUDE_CONFIG_DIR | relocated Claude config dir — checked before the default |
$CODEX_HOME | relocated Codex home — checked before the default |
$DEVIN_HOME | relocated Devin data dir |
$DEVIN_DB_PATH | points straight at the Devin database file |
$CROSSMEM_CONFIG | use a different crossmem config file |
$CROSSMEM_CURRENT_SESSION | comma-separated session ids to exclude as “live” |
$CROSSMEM_DEBUG / $CROSSMEM_LOG | opt-in local debug logging |
A candidate path whose variable is unset on the current machine simply drops out — which is how a Windows-only location disappears on macOS without a single runtime.GOOS branch. ADR 1.
Pointing it somewhere else
crossmem already knows the standard locations. The config file is for what it cannot know: a portable install, a second drive, a custom data directory.
~/.config/crossmemcli/config.json — or wherever $CROSSMEM_CONFIG says. crossmem config --init writes a starter.
{
"defaults": { "mode": "full", "limit": 5 },
"stores": {
"devin:sqlite-sessions": "D:/agents/devin/cli/sessions.db",
"claude": ["~/work/.claude/projects"]
},
"extraStores": {
"opencode": "~/other/opencode/opencode*.db"
},
"dumpDir": "~/.assets/convdump",
"sync": { "remote": "hetzbox:companydata/convdump" }
} defaultssets what happens with no flag. A command-line flag always wins, so"mode": "full"means you never type--fullagain.storesreplaces a store's built-in locations;extraStoreskeeps them and adds more.- Keys are
provider:kindas printed bycrossmem scan, or a bareproviderfor that provider's primary store — so overridingdevincannot accidentally repointdevin:cli-logsat a database file. - Values are a path or a list of them.
~,%VAR%,$VARand*globs expand, and a path whose variable is unset is skipped — so one config file can be shared across machines. - An unknown key is a load error, surfaced by
crossmem configrather than silently ignored.
“It can't find my sessions”
crossmem scan— is the store discovered at all?crossmem config— which candidate paths were checked, and which exist?- Relocated install? Set the env var above, or add a
storesoverride. - Sessions exist but not for this folder? The match is on the recorded cwd — try
crossmem list --provider <tool> --limit 20with no folder and read theworkspacecolumn. - Still nothing?
CROSSMEM_DEBUG=1 crossmem scanreports the local read and query failures (never transcript contents).
What is never read
*.env, credential files, auth databases, credential tables, andvault/directories.- The same filter runs over
exportand thesyncdump, so a dump pushed to a remote cannot carry a secret value. Cache andnode_modulesdirectories are dropped too. - Nothing is sent anywhere. crossmem has no network path except the
rcloneremote you name yourself insync.