ZCode
- ID:
zcode - Store:
~/.zcode/projects/<encoded-cwd>/<session>.jsonl - Store (CLI database):
~/.zcode/cli/db/db.sqlite— OpenCode's schema - Store (legacy snapshots):
~/.zcode/v2/sessions/<workspaceHash>/<taskId>.json - Read overrides:
DEJA_ZCODE_ROOTreplaces the project root;DEJA_ZCODE_DBnames the database;DEJA_ZCODE_LEGACY_ROOTreplaces the snapshot root - Format: flat JSONL — one message per line
- Needs:
sqlite3for the CLI database; the transcripts need nothing
ZCode is Z.ai's desktop agent and writes the same flat transcript Command Code
does, under the same project layout: role, content, timestamp,
sessionId, one message per line. Some lines also carry the API's usage
block, which deja has no use for and ignores.
Last verified: 2026-10-07
Known quirks and drift
- Compaction. There is no compaction hook, and the
transcript_patha
hook gets is a temp file holding the one message of that call
(createClaudeCompatibleHookStdin). The CLI database keeps the session
whole: a compaction adds a user message with `semantics.kind:
"compact_summary" and a compaction` part, and the turns before it stay.
The next UserPromptSubmit or PreToolUse reads the session as it stood
before the newest summary and answers with the packet, once. Checked on a
3.14.4 stand with /compact.
- Rules.
~/.zcode/AGENTS.mdis the user scope of ZCode's instructions,
read ahead of the workspace's (bls/mls in vendor/zcode.cjs); a stub
endpoint saw it under "user default instructions". deja rules sync
writes there.
- The CLI database is OpenCode's schema with Claude Code's tool names.
It goes through OpenCode's schema reader (see below), checked against a
store the ZCode 3.14.4 runtime wrote, whose tool parts needed their own
names read (#4428).
- Skill and command: zcode-app-cli 3.14.4 scans
~/.zcode/skills, then
~/.agents/skills (resolveDefaultSkillRoots), and ~/.zcode/commands,
then ~/.agents/commands, expanding $ARGUMENTS. deja writes the shared
skill and ~/.zcode/commands/deja.md (#4802).
- Wiring:
deja install zcodewrites the server intomcp.serversin
~/.zcode/cli/setting.json — one level deeper than the mcpServers every
other client here uses — and deja install zcode-auto adds the hooks to the
same file, under hooks.events: SessionStart, UserPromptSubmit,
PreToolUse on Bash|Edit|Write (the line deja keeps for a file or
command) and PostToolUse on Bash, which a failed command fires with its
exit code (the earlier fix). The runtime (3.14.4) writes that file on
its first launch and reads it from then on. deja used to write
config.json, which the runtime reads once, as the source of that
first-launch migration, so nothing reached the agent on a machine where
ZCode had run; an uninstall clears deja's entries from both. Before that
first launch, install starts setting.json from config.json the way the
runtime would, since the runtime skips its migration once the file exists,
and deja doctor reads hooks outside hooks.events or with
hooks.enabled off as stale (#4429).
- **Three things decide whether that works, and all three are silent when
wrong.** Config-file hooks do nothing without hooks.enabled: true, and
the runtime's own setting.json starts with it off: install turns it on and
says so, and uninstall puts back what was there, so hooks the reader had
switched off do not stay on (#4431). A
config hook gets no template expansion, so the command carries an absolute
path. And the output schema is strict: one key ZCode does not recognise and
the whole response is discarded — which is why the installed line ends in
--strict, dropping deja's receipt line and keeping the context.
- The shapes were not read from ZCode's own documentation, which does not
describe them. They come from volcengine/OpenViking's memory plugin, whose
examples/agent-hook-plugin/DESIGN.md records the surface it established by
inspecting a live install — seven hook events, the manifest probe order, the
strict schema — and ships an installer against it. The file and the
nesting have moved since; the three rules above held on the 3.14.4 runtime,
where the hooks fired and the digest reached the request (#4429).
deja resumeon a session from the CLI database prints
cd '<dir>' && zcode --resume <sess_id>, the directory from the session
row. The terminal client reopens the session from any directory; the cd
keeps the agent in the project. A JSONL transcript has no such command
(#4430).
The CLI database
It was left unread while nothing said what shape it was in. deja reads it
now, on the shape attested by zcode-stats 0.8.0 — a read-only dashboard over the live database,
whose own description names ~/.zcode/cli/db/db.sqlite and whose queries name
the tables:
SELECT directory, count(*), sum(task_type = 'interactive'),
sum(task_type = 'subagent_child'), sum(task_type = 'fork'),
max(time_updated) FROM session GROUP BY directory
SELECT json_extract(data, '$.role') FROM message GROUP BY role
SELECT json_extract(data, '$.type') FROM part GROUP BY type
session / message(data) / part(data) is OpenCode's schema, which deja
already parses for OpenCode and for Kilo Code's CLI, so this is one more root
rather than a new reader. The tool parts are not opencode's, though: a store the
ZCode 3.14.4 runtime wrote names them as Claude Code does, with its arguments —
Bash {command}, Read {file_path}, `Edit {file_path, old_string,
new_string}, Write {file_path, content}`. deja reads those for ZCode as
commands with their output, files, edit spans and written lines; an Edit
ZCode refused (state.status: "error") is not recorded as a change (#4428).
A Bash part has no metadata.exit; a failed run's output opens with "Exit code
N", as Claude Code's does, and that line goes on the command as → exit N
rather than into the output (#4536).
Said plainly: that is a third party's attestation, not a running ZCode checked
here. task_type also separates subagent_child and fork from interactive,
which is the distinction DEJA_INCLUDE_SUBAGENTS draws elsewhere — left alone
until there is a real store to measure it against, rather than guessed at
(#3675).
Legacy snapshots
Before the current runtime ZCode kept each conversation as one JSON file,
~/.zcode/v2/sessions/<workspaceHash>/<taskId>.json:
{"meta": {"taskId": "…", "acpSessionId": "…", "workspacePath": "/path/to/proj",
"title": "…", "createdAt": 1790000000000, "updatedAt": 1790000060000},
"messages": [{"role": "user", "content": "…", "timestamp": 1790000000000}]}
That is the shape the 3.14.4 runtime's own restore-legacy-sessions skill scans
(scan-legacy-sessions.mjs). The files stay until the user restores them by
hand, so deja reads them: acpSessionId, else taskId, is the id, the one a
restore gives the session, workspacePath names the project, and the user and
assistant text is indexed. Files ending .deleted.json are skipped, as ZCode
skips them, and a snapshot whose id is already in the CLI database is read
from there instead, from the first pass after the restore on (#4448). deja resume on a snapshot names ZCode's
/restore-legacy-sessions command rather than a zcode --resume that would
not find it (#4432).
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.