Cherry Studio
- ID:
cherrystudio - Store:
<app data>/CherryStudio/Data/Agents/.claude/<projects>/<workspace>/<session>.jsonl—~/Library/Application Support/CherryStudioon macOS,%APPDATA%\CherryStudioon Windows,$XDG_CONFIG_HOME/CherryStudioelsewhere - Store (before the upgrade that added
Data/Agents):<app data>/CherryStudio/.claude/<projects>/…, read so a store that predates it is not lost - Stores of the other agent runtimes:
<app data>/CherryStudio/Data/Agents/.pi/sessions/<ts>_<id>.jsonl(pi) and<app data>/CherryStudio/Data/Agents/.dsh/sessions/<workspace>/session-<id>/(dsh,DSH_HOMEset toData/Agents/.dsh), read by the stock pi and dsh parsers and filed undercherrystudio(#4342) - Moved data dir: every directory in
app.user_data_pathof~/.cherrystudio/boot-config.json, where the app records a move made in its settings, is read the same way as the default (#4347) - Read override:
DEJA_CHERRYSTUDIO_ROOTSreplaces the root list, the pi and dsh stores included - Format: Claude Code's own transcript JSONL; pi and dsh logs for those runtimes
- Needs: nothing
Cherry Studio runs Claude Code sessions from a desktop app and writes ordinary
Claude Code transcripts under its own app data, so the parsing is Claude's.
Last verified: 2026-10-07
The fixture in this repository sits at fixtures/registry/cherrystudio/projects/… rather than
under a .claude directory: the repository excludes .claude/, so a fixture carrying that
segment is never committed and the tests pass only on the machine that wrote it. The parse does
not depend on the directory shape — the roots come from the environment — and the real layout is
the one above.
Known quirks and drift
- A snapshot per stream chunk. Cherry Studio appends the same API call three
or four times as the response streams: a new uuid each time, the same
requestId and message.id, and the text growing. Read plainly that is one
reply stored three times in prefixes — a recall can then quote half a sentence
and deja show prints the answer twice before finishing it. The reader
collapses a run by requestId (else message.id, else uuid) and keeps the
longest text. Stock Claude Code writes one record per turn, so its reader is
unchanged and a test pins that.
- Sessions are their own harness rather than extra Claude roots: a reader should
see which app the work happened in, and deja sources says cherrystudio.
- Wiring:
deja install cherrystudiowrites
<config>/deja/cherrystudio-mcp.json and says to import it in Settings → MCP
→ Import from JSON. The app keeps its MCP servers in its own SQLite store — a
drizzle schema seeded from a built-in preset list
(src/main/data/services/McpServerService.ts,
src/main/data/db/seeding/seeders/builtinMcpServerSeeder.ts) — so there is no
config file to write, and writing into a running app's database is not an
installer's job. Its import paths are JSON, DXT and MCPB
(src/renderer/pages/settings/McpSettings/McpServersList.tsx); the MCPB
bundle this project already publishes is the other one and needs nothing new.
- The skill channel exists, and it is not one of its own: Cherry Studio
discovers the skill directories of the agent CLIs a machine has —
~/.agents/skills, ~/.claude/skills, ~/.codex/skills and a dozen more,
in src/main/ai/skills/systemSkillSources.ts — and lists what it finds for
the user to enable per agent. deja install cherrystudio writes deja's
shared skill into ~/.agents/skills, which is one of those roots, so the
app lists it; enabling it for the agent is the one click left.
- Auto-recall:
deja install cherrystudio-autowrites Claude Code's hooks
into <userData>/Data/Agents/.claude/settings.json, the CLAUDE_CONFIG_DIR
2.0.14 gives the Claude agents it runs (feature.agents.claude.root; a move
in ~/.cherrystudio/boot-config.json moves it). Run with the app's own SDK,
binary, env and options against a stub, SessionStart, UserPromptSubmit,
PreToolUse and PostToolUse output reached the model (#4802). The sealed
built-in Support agent loads no settings, and an external-CLI provider drops
CLAUDE_CONFIG_DIR and reads only the project's, so neither gets them. Slash
commands have no surface for a third party: they are the app's own.
The import file, checked against the app's own validator
Cherry Studio 2.0.14 installed, and its importer read out of the bundle
(Contents/Resources/app.asar, out/renderer/assets/mcp-uMWTyAhi.js):
const McpConfigSchema = object({ mcpServers: record(string(), McpServerConfigSchema) })
// McpServerConfigSchema = object({ id?, name?, type?, description?, url?, baseUrl?,
// command?, registryUrl?, args?, env?, headers?, … }).strict()
// type ∈ stdio | sse | streamableHttp | inMemory
and the paste handler beside it names each server after its key unless the entry
carries a name. So the file deja writes —
{"mcpServers":{"deja":{"type":"stdio","command":"<abs path>","args":["mcp"]}}}
— validates, and the server arrives called deja.
The schema is .strict(), which is the part worth remembering: one key the app
does not know fails the whole import rather than being dropped. A test pins
deja's key set for that reason (#3674).
What still needs a person: the paste itself, and a Claude account in the app
before it writes any transcript at all.
deja reads this format and 42 others, and turns what it finds into memory your agents can search. See the harness matrix for what is wired where, or install it and search your own history.
Found this useful? Star deja-vu on GitHub.