A release about what deja hands over and whether it can be trusted. The week's
bug hunt landed with it, and the theme that runs through both is the same: a
surface that says something it does not know is worse than one that says
nothing.
Added
- prime-agent sessions are indexed. (#2623)
- goose sessions reach recall whichever way a person got to goose — over ACP
from an editor, from the CLI, from a chat gateway, or from a run that kept no
session. The filter was an allow-list ofsession_type = 'user', so a store
full of ACP sessions had none of them in recall and nothing said why.
(#2874, #2908) --jsonforfix,frictionandhow, in the shapedocs/json-output.md
describes. Each envelope carries the counts a caller cannot recover from the
rows — how many recurring errors there were before--limit, the threshold a
row had to clear, what a rule withheld — so an empty result can be told apart
from a hidden one. (#2895, #2919)deja bench blockscores what the block says rather than what it chose. The
other three benches print the same numbers with the block emptied; this one
goes to zero, and its baseline — the newest turns of the top hit — scores zero
so an arm above it had to find the answer. (#2940)recall_contextsays how many other sessions matched the question, so a
digest chosen from forty no longer reads as the only thing deja held. (#2894)doctornames the sessions stamped ahead of the clock. (#2824)DEJA_EMBED_OFF=1switches off the localhost probe for an embedding endpoint.
Without it a machine running Ollama answered differently from one that was
not, including in deja's own test suite. (#2937)
Changed
- Every answer that carries text out of a transcript says that the text is
untrusted — the MCP tools, the resources, the hooks, and the commandshow
andfixhand an agent. Pinned by a property test per surface rather than
case by case. (#2844, #2847, #2848, #2850, #2852, #2859) - A growing session is read from where the last pass stopped rather than whole,
for goose, qwen, omp, OpenClaw and prime; the grok, hermes and zed stores are
asked only for what changed. One appended turn against a 300-file store went
from 1045 ms to 58 ms. (#2812, #2813, #2818, #2876, #2877, #2902) installreads a config before writing it: it updates the entry that already
runs deja instead of adding a second, keeps the shape and the comments it
found, edits an inline block that opens and closes on one line, asks about
every host a target touches before writing any of them, and refuses a config
it cannot read rather than writing over it. (#2648, #2737, #2739, #2743,
#2747, #2748, #2752, #2753, #2755, #2756, #2758, #2761, #2778, #2780)- A rephrased question reaches its answer through the project's own words, and
ranking pays for coverage only on the words that identify something.
(#2480, #2484)
Fixed
- The block quotes the sentence that concludes rather than the opening of the
message that carries it, and a message kept for its code fence no longer
takes the slot the conclusion needs. Measured against a real store, blocks
carrying what the session settled went from 265 of 456 to 440 of 452 at the
session-start budget. (#2906, #2913, #2922) - A sentence with no stopword in it is no longer read as a listing dump, and a
sentence that opens with a number is no longer read as a numbered one. The
first rule counted path-shaped fields and never read the count; over 277375
prose lines of a real store it dropped 20294 of them, of which 55 were
listings. (#2916, #2918) blameand the search excerpts stopped quotingwc -loutput and runs of
paths as the passage that explains a file. The snippet path had its own
smaller set of filters and no notion of a listing at all. (#2925)frictionsanitises a recorded error line before printing it. An ANSI escape
recoloured the rest of the terminal and U+202E reversed the reading order of
everything after it; every other surface already ran a recorded line through
the same sanitiser. (#2910)- An empty store is described as an empty store.
recall,blame,howand
fixblamed the query instead, and a store emptied byforgetwas reported
as a first run. (#2862, #2863, #2865, #2882) - A remedy that names a scratch file is not mined as one. On a real store 38 of
186 confirmed pairs pointed at a path under a temp directory — a command
nobody can run by the time deja serves it. (#2903) - pi transcripts keep their session header when a parse resumes past it, so an
appended turn lands in the session it continues rather than beside it. (#2901) - A promoted note stays ahead of the transcript it distils, on the error and
relevance tiers, in the per-prompt hook, and when either side arrived by sync.
(#2804, #2821, #2823, #2838) - A recalled session that names what was asked is no longer disowned by the line
above it, and the recall header stopped claiming a query it did not match.
(#2789, #2831, #2834, #2837) howcounts the sessions the policy hid that match the question, not every
withheld session on the machine. (#2765, #2792, #2795)- CI status is not promoted as what a session concluded, a bullet of a document
the agent wrote is not recalled as a decision, and harness envelopes stay out
of the session-start block. (#2736, #2741, #2745, #2774) - The trust policy is read from a home directory or from nowhere, and with no
home directory deja writes nothing where it happens to be run. (#2782, #2788) handoffmarks where the quoted session starts and ends, and sanitises the
digest--exechands to the next agent. (#2867, #2891)- The week's bug hunt, 124 fixes, merged. (#2616, #2733)
Changelog
Features
- feat(bench): score what the block says, not what it chose (#2940)
- feat(cli): --json for fix and friction (#2895)
- feat(cli): --json for how (#2919)
- feat(doctor): name the sessions stamped ahead of the clock (#2824)
- feat(fix): answer a failure with the single sighting, said as one (#2589)
- feat(mcp): recall_context says how many other sessions matched (#2894)
- feat(recall): reach a rephrased question's answer through the project's own words (#2484)
- feat(sources): index prime-agent sessions (#2623)
Fixes
- fix(bench): stop the cross-paired arm asking where the answer lives (#2550)
- fix(blame): name the file this one's history stops at (#2776)
- fix(blame): stop quoting deja's own output as a file's history (#2387)
- fix(cli): the rest of the printed commands quote what they hand over (#2797)
- fix(cli): with no home directory, write nothing where deja happens to run (#2782)
- fix(digest): a code fence must not take the slot from the conclusion (#2913)
- fix(digest): a sentence that starts with a number is not a numbered dump (#2918)
- fix(digest): a sentence with no stopword is not a listing dump (#2916)
- fix(digest): mark an overlong conclusion instead of dropping it (#2922)
- fix(digest): quote the sentence that concludes, not only the opening (#2906)
- fix(doctor): say what the store said when it refused (#2626)
- fix(doctor): say which codex hook events an older install lacks (#2565)
- fix(doctor): say which hook events an older install lacks (#2553)
- fix(embed): let the localhost probe be switched off (#2937)
- fix(friction): sanitise the recorded error line before printing it (#2910)
- fix(goose): keep a session unless goose wrote it for itself (#2908)
- fix(handoff): mark where the quoted session starts and ends (#2891)
- fix(handoff): sanitise the digest --exec hands to the next agent (#2867)
- fix(help): fit the usage page to the terminal reading it (#2771)
- fix(hook): stop one repository's error being told as a fact about the machine (#2580)
- fix(hooks): say when the receiver was lost with an unreadable payload (#2769)
- fix(hooks): the deja-vu hook says when it could not read the payload (#2791)
- fix(hooks): the receipt counts what the statusline counts (#2770)
- fix(how): count the hidden sessions that match the question, not the store (#2792)
- fix(how): count the sessions the policy hid, not their commands (#2765)
- fix(index): record the files a session really worked on (#2706)
- fix(index): stop mining remedies that point at a scratch file (#2903)
- fix(install): a comment in a config is not a refusal (#2739)
- fix(install): ask every Roo host before writing the first one (#2755)
- fix(install): check every config a target touches before writing any (#2748)
- fix(install): opencode reads its config by content, and an inline block is opened (#2778)
- fix(install): refuse a config deja cannot read instead of writing over it (#2753)
- fix(install): say the entry is off whichever way the host spells it (#2758)
- fix(install): settings.json keeps the shape it was found in (#2737)
- fix(install): the JSONC path decides like the parsed one (#2743)
- fix(install): the switch writer edits only what it can read (#2747)
- fix(install): the text writer writes the entry its caller would have written (#2780)
- fix(install): update the entry that already runs deja instead of adding a second (#2648)
- fix(mcp): an emptied store is a removal, not a first run (#2882)
- fix(mcp): blame says why it found nothing on an empty store (#2863)
- fix(mcp): exit when the parent is gone and nobody has spoken for five minutes (#2649)
- fix(mcp): frame the command fix hands an agent (#2847)
- fix(mcp): frame the commands how hands an agent (#2844)
- fix(mcp): how and fix reach the journal, without moving the stats ratios (#2892)
- fix(mcp): how and fix say the store is empty rather than reporting an absence (#2865)
- fix(mcp): journal a remembered note even when the index is busy (#2855)
- fix(mcp): recall_context says what a relevance session is, in a sentence (#2793)
- fix(mcp): say the store is empty instead of blaming the query (#2862)
- fix(mcp): tell an agent the session it was handed was forgotten (#2775)
- fix(mcp): the how tool prints the CLI's answer instead of its own copy (#2767)
- fix(mcp): the line above a relevance answer says what follows it (#2786)
- fix(pi): keep the session header when a parse resumes past it (#2901)
- fix(policy): a trust policy is read from a home directory or from nowhere (#2788)
- fix(recall): ask the store whether a word identifies, not just its shape (#2532)
- fix(recall): stop a subject the store never saw from carrying a match (#2528)
- fix(recall): stop two sessions saying one thing from taking both slots (#2527)
- fix(remember): quote the id in the tombstone hint the way a shell pastes it (#2763)
- fix(search): refuse a bad --re pattern in deja's own voice (#2764)
- fix(search): the snippet path did not know what a listing is (#2925)
- fix(sources): include goose ACP sessions in the type allowlist (#2874)
- fix(sources): read a WAL store that nobody has open (#2702)
- fix(sync): send the export in batches scp can accept (#2629)
- fix(uninstall): take a server's sub-tables with its block (#2717)
- fix: a list marker needs a space after it (#2745)
- fix: anchor the context digest on the query's identifying words (#2729)
- fix: do not recall a bullet of a document as a session's decision (#2741)
- fix: gemini-auto no longer refuses a commented config it has already edited (#2759)
- fix: how counts the withheld sessions the question matched, not the store's (#2795)
- fix: keep harness envelopes out of the session-start block (#2736)
- fix: lift a note over its source when either arrived by sync (#2838)
- fix: markers fire on words, not on any substring (#2779)
- fix: merge deja's own entry on the jsonc path instead of replacing it (#2756)
- fix: no trailing space where deja takes over an inline mcp brace (#2781)
- fix: read past an entry's key at what it runs on the opencode jsonc path (#2761)
- fix: recall_context names the query words the search could not use (#2837)
- fix: say when install left an mcp entry switched off, in either spelling (#2772)
- fix: stop disowning a recalled session that names what was asked (#2831)
- fix: stop promoting CI status as what a session concluded (#2774)
- fix: take out a hook line deja wrote for a subcommand it no longer has (#2749)
- fix: the error and relevance tiers keep a note ahead of its own transcript (#2804)
- fix: the log of a query no longer answers it (#2784)
- fix: the per-prompt hook puts a note ahead of the transcript it distils (#2823)
- fix: the recall header stops claiming the query it did not match (#2789)
- fix: the recall page stops disowning a first session that names what was asked (#2834)
- fix: the salvage scan finds a key where it is a key (#2796)
- fix: the semantic tier serves a promoted note with the source it distils (#2821)
- fix: write into an mcp block that opens and closes on one line (#2752)
Performance
- perf(index): let omp, openclaw and prime append instead of re-reading (#2902)
- perf(rank): pay coverage only on words that identify something (#2480)
- perf: a growing goose session appends, keeping the project its header names (#2877)
- perf: a growing qwen session appends instead of rewriting the index (#2876)
- perf: ask the grok store only for what is new (#2812)
- perf: ask the hermes store only for what is new (#2813)
- perf: ask the zed store only for the threads that changed (#2818)
Documentation
- docs(bench492): what the pass costs, on both corpora (#2690)
- docs(mcp): say why the parent pid is read once (#2711)
- docs(site): bring the version and the benchmark numbers up to 0.19.1 (#2362)
- docs: changelog and site for 0.19.2 (#2944)
Other
- Bring the bug hunt into main (#2733)
- Merge pull request #2798 from vshulcz/merge/hunt-2026-08-30
- Merge pull request #2801 from vshulcz/merge/hunt-tail
- chore(deps): bump actions/checkout from 4.2.2 to 7.0.1 (#2884)
- chore(deps): bump actions/setup-go from 6.5.0 to 7.0.0 (#2887)
- chore(deps): bump anchore/sbom-action/download-syft (#2885)
- chore(deps): bump every codeql-action step to 4.37.9 together (#2928)
- chore: collapse a comment a merge left three times over (#2738)
- chore: drop the grok entry in wholeStoresThisPass, which nothing needed (#2815)
- chore: drop the switch readers the merged writer no longer needs
- chore: pin the manifests to 0.19.1 (#2359)
- merge: take the bug-hunt branch into main
- merge: the last bug-hunt commit, which landed during the integration
- test(bench): ask every question in someone else's project (#2542)
- test(hooks): cover the pre-action hook in the framing property (#2852)
- test(hooks): pin that every injection says the text is untrusted (#2850)
- test(mcp): cover the resources surface in the framing property (#2859)
- test(mcp): pin that every answer carrying transcript text says it is untrusted (#2848)
- the bug hunt's week: 124 fixes, merged (#2616)
Install
curl -fsSL https://raw.githubusercontent.com/vshulcz/deja-vu/main/install.sh | sh
go install github.com/vshulcz/deja-vu/cmd/deja@v0.19.2
brew install deja-vu