CodeWhale
- ID:
codewhale - Store:
${CODEWHALE_HOME:-~/.codewhale}/sessions/<id>.json— one file per session - Store (pre-rebrand):
~/.deepseek/sessions/<id>.json, which CodeWhale migrates into the current root on first access - Read overrides:
DEJA_CODEWHALE_ROOTreplaces the current session directory (the legacy one is still read while it exists);CODEWHALE_HOMEmoves the whole store and turns the legacy root off - Format: JSON —
{schema_version, metadata, messages}, pretty-printed - Needs: nothing
- Resume:
cd <metadata.workspace> && codewhale --resume <id>, the absolute workspace from the session file, with nocdand a note when it is gone (#4362, #4460) —--session-idis its alias andcodewhale exectakes both (checked against 0.9.13)
CodeWhale is a terminal agent written in Rust. It shipped as deepseek-tui
until v0.8.41 and under its own name since; the provider integration did not
change with the name. It is not the DeepSeek Harness deja reads as deepseek —
a different program with a different store, which is why both entries exist.
metadata carries the id, the title CodeWhale derived itself, created_at,
updated_at, the workspace the session was worked in, and
parent_session_id when the session came from a fork. A message is
{role, content}, where content is the block list Anthropic's API uses —
text, thinking, tool_use, tool_result — so the decoding the Cline and
Claude readers already do applies here: a call becomes a command or a file
record, a tool_result becomes tool output, error runs included. Since 0.9.6
new turns use read, write, edit and bash, where edit takes
edits[{oldText,newText}] (also sent as a JSON string, or as one top-level
oldText/newText pair, both read the same way); the older read_file, write_file and edit_file
names are still read for sessions saved before. fim_edit names only two
anchors and gets back the text it generated, generated_text in the JSON its
result holds; that is read as the written side (#595). Commands also run through
terminal/run (a PTY session) and task_shell_start (a background task), both
under command, and are read as commands (#4538). apply_patch takes a
unified diff (--- a/x / +++ b/x, not codex's *** Begin Patch) under
patch, retargeted to path when that is set, or whole files under replace
(deprecated alias changes) as {path, content}; the files, each hunk's
removed lines and the added lines or contents are read, paths under the
workspace. A call whose tool_result has is_error is not recorded (#4538). A failed bash result has
is_error and ends "Command exited with code N"; the command it answers, by
tool_use_id, carries that as → exit N (#4537).
thinking blocks are dropped. So are the system and developer roles:
CodeWhale's own documentation names them as where it puts compaction summaries,
branch summaries and sub-agent framing, which is the harness talking to itself
rather than anything either side said.
$CODEWHALE_HOME is an isolation boundary in CodeWhale's own resolver — with it
set, the legacy root is not consulted — and deja does not reach outside it
either.
Last verified: 2026-10-08
Known quirks and drift
- No per-message timestamps. The file stores
created_atandupdated_at
for the session and nothing per message. The session's own start is the clock,
one millisecond per record, so two identical turns stay two records rather
than collapsing into one the way they did for Zed (#3333).
- Bookkeeping sits beside the transcripts.
offline_queue.json,
session_boot_owners.json and the checkpoints/ slot share the sessions
directory, and 0.10.0 adds a directory per session (approval receipts,
runtime state), .late-usage/ and .work-graph-import-archive/, which keeps
copies of migrated sessions. A transcript sits directly in the root, so
everything in a subdirectory is bookkeeping; the files beside the
transcripts are named rather than counted, so drift there still shows up as
an unread file.
- Checked against a running install. On a 0.10.0 TUI against a stub
endpoint (#4802), the session files had the shape above. Every user message
also carries a <turn_meta> text block — the date, the workspace, the
permission posture — which is the harness talking and is dropped.
- Wiring.
deja install codewhalewrites the server into
$CODEWHALE_HOME/mcp.json under servers (not mcpServers), and adds
mcp_deja_deja to [tools] always_load in config.toml. CodeWhale boots
servers lazily; without that entry the tool was missing from the request.
The skill goes in ~/.agents/skills, which CodeWhale lists beside its own
skills/ and ~/.claude/skills and shows each copy it finds.
- Command.
~/.codewhale/commands/deja.mdis/dejain the slash menu
(0.10.1). The directory is under $HOME even with CODEWHALE_HOME set. The
file has no description: CodeWhale makes it the session's goal and keeps
the turn going until the model closes it.
- Auto-recall.
deja install codewhale-autoadds four[[hooks.hooks]]
entries. Hooks fire only in the TUI; codewhale exec, the ACP and app
servers fire none. Of the events, only two put text in front of the model:
message_submitmay replace the message with{"text": …}. deja keeps
the person's text first and appends the session digest (first message of
a session only) and the prompt's recall, framed in <deja-recall>.
session_start's stdout is discarded, which is why the digest rides here.
CodeWhale saves the replaced message and shows it in the transcript; the
framed part is not indexed.
tool_call_beforemay addadditionalContext, appended to the tool's
result as [hook context] … and capped at 2,000 characters. deja sends no
decision, which CodeWhale reads as allow. The line arrives only on a
tool that ran: a call that fails to run (a ToolError, "Failed to …")
goes back as Error: … without it (turn_loop.rs, 0.10.1).
session_end(on/quit, not on a kill) ends the live stamp.
tool_call_after, turn_end and session_start output never reaches the
model. So tool_call_after only parks text for the next tool_call_before
or message_submit: the fix pair for a failed shell command, read from the
execution receipt on its stdin, and the tool_call_before line of a call
that failed to run. The hooks'
sess_… ids are made fresh for each hook executor and are not the store's
file ids, so a session's live stamp does not keep MCP recall off its own
transcript.
- Compaction. There is no compaction event. Before compacting, CodeWhale
saves the whole history as
sessions/<id>/artifacts/context-transfer-<checkpoint>.json, and once the
summary is written, the summary beside it in .md
(compact_messages_safe). The next message_submit or tool_call_before
takes the newest pair written since that hook session was first seen, for a
saved session in the same workspace, and the packet rides it. A .json
without its .md is a failed attempt or a prune and is skipped. Checked on
a 0.10.0 stand.
- Status line. None to write to: the footer takes only built-in items
(StatusItem in crates/tui/src/config.rs), and observer hooks' stdout is
discarded.
- Resume.
codewhale --helpon 0.9.13 lists--resume,--session-id
and --continue, and --continue refuses in a directory with no saved
session, which is how the per-workspace scoping shows. codewhale exec
does not persist a session; the TUI writes them.
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.