Automatic compaction recovery
September 11, 2026 · View on GitHub
With auto-recall installed, hook-precompact reads the current Claude Code or
Codex JSONL transcript before the host compacts it. It extracts the user's
objective, assistant conclusions, recorded verification commands, and what a turn
says is still open or in conflict. An open item is recognised by its shape — the
line opens with the label, in either language ("Gap: …", "Осталось: …", "Still
open: …") — so a sentence that merely contains the word is not mistaken for one.
A turn that only tells the agent to carry on ("continue", "продолжай") is skipped
when looking for the objective, but a turn that carries an instruction is the
objective even when it opens with one of those words. Each item identifies its
source session, harness, role, and recorded timestamp. No checkpoint command or
model call is required.
The next session-start, prompt, or tool hook for that same session and workspace
returns a recovery packet once. Its 4 KiB limit includes the untrusted-history
frame. The packet labels assistant conclusions as reported claims. A recorded
verification command is marked passed or failed from the harness's own exit
status when the transcript carries one, and otherwise from the output recorded
after it, by the same rule deja friction uses to decide whether a line is a
failure; a command whose output was not recorded stays unknown. Repository HEAD,
branch, and working-tree fingerprints are compared at recovery, and the packet
states the verdict — unchanged, or changed with the commit it was captured at —
rather than the fingerprints themselves. Changed, partial, or unavailable
fingerprints require validation instead of presenting old conclusions as
current.
Storage and limits
Packets live in the existing manifest.gob, alongside index metadata. There is
no separate context store, additional MCP tool, or synthetic searchable session.
The index keeps the latest packet for up to 32 session/workspace pairs, with a
24 KiB limit per stored packet. A new capture replaces that session's packet;
the oldest captures are evicted when the session limit is reached. There is no
packet history. Full and incremental index rebuilds preserve retained packets.
Packets are not included in sync exports.
The reader inspects at most 4 MiB of transcript tail plus a 64 KiB header. The extractor selects at most 64 useful records and 32 KiB of text, with at most eight items in each category. Omitted content is identified in the recovery packet. Git output is streamed and its subprocesses share a 750 ms deadline. Untracked-file hashing stops at 4,096 files, 1 MiB per file, or 8 MiB total; incomplete fingerprints remain visibly partial.
Capture uses the existing index lock without waiting behind a rebuild. A busy or unreadable store causes a best-effort miss. A packet captured before the first index build does not mark the search index ready. The hook still requests the usual background index warmup.
Privacy and supported hosts
The source must declare the exact native session ID and workspace supplied by the hook. Unknown formats, missing transcript paths, mismatched identities, and files that change during reading cannot produce a successful capture. Other hosts keep the existing warmup and recall behavior until a supported transcript reader and the required hook payload are available.
Stored text uses the existing redaction pass; DEJA_NO_REDACT=1 retains its
documented opt-out behavior. DEJA_RECALL=off, automatic-recall policy, ignored
directories, excluded projects, and forgotten-session tombstones apply to this
path. deja forget removes matching packets, including a packet whose session
has not yet been indexed, and prevents it from being captured again. As with the
rest of the index, redaction does not remove all sensitive prose and storage is
not encrypted.
Measuring recovery
deja stats reports locally observed raw tool calls between capture and the
first explicit editing tool, excluding the edit itself. It shows the sample
count, median, and 75th percentile, separately from pending and unmeasured
captures. The metric is reconstructed from the existing bounded usage log;
measurement events contain identifiers and counts, not transcript text.
The count comes from native transcript tool invocations, including tools that do not run a deja hook. It does not count normalized message records or hook invocations. A later editing hook can recover the first-edit boundary already recorded in the transcript. Rewritten logs, unreadable evidence, or an interval outside the bounded transcript window remain unmeasured. These observations measure local recovery cost; they do not establish a speedup or compare against a built-in baseline.