Big stores build and search for less. A cold build peaks at half the memory
it did (4.7 GB instead of 9.4 GB on 40,000 sessions, 2.4 GB instead of 4.0 GB
on a 12,000-session Codex store), redacts with 17x less CPU, reads each
transcript line once and writes a quarter of the scratch data. The slowest
searches answer in under 200 ms in process instead of up to 800, and a search
over many copies or look-alike sessions is no longer quadratic, a slowdown
0.23.0 made worse. MiniMax Code is the forty-third harness, a directory tree
can be named as one project in ~/.config/deja/projects, and
deja search --sort date lists the newest match first. A friction wall that
was fixed leaves the session-start block. deja secrets --scrub
no longer breaks the transcripts it rewrites. The index is rebuilt once on
upgrade.
Added
- MiniMax Code: sessions under
~/.minimax/v2/sessionsare indexed with the
person's own words rather than the runtime's reminders,deja resumeprints
mcode --session <id>, anddeja install mcode/mcode-autowrite the MCP
entry and a hook plugin. From @yangala (#5415, #5593). ~/.config/deja/projectsnames a directory tree as one project, one
<path> = <name>per line. Every checkout and worktree under a listed path
is indexed under that name, and the hooks and recall standing anywhere in it
scope to all of them. Editing the file renames nothing already indexed:
deja indexanddeja doctorsay a rebuild is due,deja index --rebuild
renames the sessions whose transcripts are still on disk, and sessions
indexed before the file existed still match from their own checkout until
then. The exclude file wins over an alias, so a repository excluded by its
own name stays out. From @Maweill (#5097, #5373).deja search --sort datelists the newest match first, in the text and in
--json, and^sin the search screen turns the list newest first under
day headings and back. On a common word the page is the newest of the whole
match, not the newest of the best-ranked thousand (#5577, #5587).- Guides for deleting Antigravity and Junie history. From @notsubash (#5604)
and @Kasa-Harendra (#5624). - A friction wall whose cause was fixed no longer stays in the session-start
block for good. It drops out after 30 days without a hit while its projects
keep getting new sessions, anddeja friction --settle <id>takes it out at
once, using the id each row ofdeja frictionnow prints. A session started
after the settle that hits it again brings it back;--unsettleundoes it.
Reported by @SmoothSailingMusic (#5628, #5631).
Changed
- A cold build reads each transcript line once instead of handing it to six
readers that each decoded it again, and checks tool output for known errors
in one pass per line: 60 s instead of 87 s and 353 CPU-seconds instead of
551 on 40,000 sessions (#5586). It also keys messages without allocating a
string per word, which halves the indexing phase: 9.3 s to 4.2 s on a
12,000-session Codex store, and the whole build from 273 to 215
CPU-seconds (#5567). - A cold build peaks at half the memory: 4.7 GB instead of 9.4 GB on a
40,000-session store. The message count and the rebuild's dedupe set key on
a hash instead of the text, and a full build runs the collector at GOGC=25
unless GOGC or GOMEMLIMIT is set (#5498). A store under 20,000 sessions no
longer holds every session's words at once to count which words go
together: a 12,000-session Codex store peaks at 2.4 GB instead of 4.0 GB
(#5533). - Redacting secrets during a build takes 17x less CPU with the same output: on
a 12,000-session Codex store the cold build went from 109 s to 45 s wall and
904 s to 285 s of CPU (#5512). - A cold build derives each session's row on every core instead of in the
write loop: 189-202 s to 157-169 s on a 40,000-session store (#5524). - A cold build writes a quarter of the scratch data it did, so a busy disk
no longer stalls it: 2.47 GB to 0.59 GB on a 12,000-session Codex store, and
indexing messages took 15-20 s instead of 32-35 s with the disk under other
load (#5526). deja indexdecodes the manifest and walks the stores once: renaming 20
transcripts on a 40,000-session store takes 0.97 s instead of 1.5 s (#5471).
A pass that also sees a database store change (opencode, grok and the like)
reads only the sessions that store changed: one new opencode message goes
from 2.4 s to 1.4 s (#5476).- A question with a word the store never saw reads each word's postings once
when it tries the word's neighbours, instead of once per neighbour: on
19,195 sessions search p95 went from 420 to 170 ms and the slowest question
from 740 to 200 ms, with the same answers (#5540). - The search screen reads a page at a time. A word most of a 40,000-session
store holds lists its first 80 cards in about 1 s instead of 16, the list is
headed with every match, and the next page loads as the selection nears the
end (#5487). - MCP
recallruns one index search where it ran two: 2.4 s to 1.3 s outside
any known project, 2.2 s to 1.4 s inside one, same page (#5486). A session
the trust policy withholds no longer takes a slot in a large search's pool
or counts toward its total (#5488). - The Grok, Command Code, Kimi and Kiro line readers and tail checks stream
long JSONL lines rather than holding them whole: a 16 MB line is read in
memory bounded by the message cap instead of the line. From @littfed
(#5424, #5475). - The skill names goose
delegateruns, prime-agentrlm.spawnchildren and
Copilot CLItaskruns among the sub-agents indexed as a child session of
their own. From @zening-cmd (#5610).
Fixed
deja secrets --scrubredacts inside each decoded JSON string, and one line
at a time in a file that is not JSON, instead of over the raw file. On the
raw bytes an escaped quote lost its backslash and the private-key rule ran
from one record to another: on one machine 47 of 249 rewritten files came
back with 182 lines that no longer parsed, and two transcripts went from
1040 to 572 lines and from 1033 to 846. A rewrite that would drop a line or
break one that parsed is now refused,--dry-runincluded, and compressed
or binary stores are left alone. Reported by @AlexanderAbramovPav (#5622,
#5627).- A search over many sessions holding the same turns no longer goes
quadratic: 2,400 identical sessions answer in 0.9 s where 0.23.0 ran past
15 s. From @Terminator637 (#5499, #5502). Sessions that share turns but
each go on past them answer in 0.43 s instead of 5.1 s for 6,000 (#5523),
and 6,000 unrelated sessions that open on the same turn in 0.33 s instead
of 9.7 s (#5549). deja install codexno longer writestype = "stdio"into
[mcp_servers.deja]. Codex 0.163 warned the key is not a setting it knows,
and picks stdio fromcommandanyway. A reinstall drops the line from an
older block. Reported by @j2h4u (#5590).deja fix,deja frictionand the hook at a failed command now know the
errors a package install hits behind a mirror or a proxy: pip's "No matching
distribution found", an HTTP 403 or 401 from an index, an unresolvable host,
an untrusted certificate, a failed docker build step and npm's error codes.
pip3,pip config, conda and apt installs are kept as remedies, so the
install that worked against the mirror is whatdeja fixnames (#5599).- The
deja_recalltool in the dsh, opencode, OpenClaw and Hermes plugins
answers with the MCP recall page, about 4 KB, and takes anoffsetfor the
next one. dsh and opencode handed the modelsearch --json: 222,536
characters for five hits on a test store.deja recalltakes--offset
(#5568). The skills' shell fallback isdeja recalltoo, 4,097 bytes for a
query that ran to 222,546 throughsearch --json, and the Devin plugin's
copy of the skill is current again (#5578). A recall page that names a
session matched more often than it can quote says to call recall with that
id, not recall_context, which the OpenClaw and Hermes plugins do not have
(#5579). MCPrecall'slimitsays it is per ~4 KB page, and a page that
ran out of room says(page full)on its paging line (#5511). - OpenClaw's
deja_recall,deja_fixanddeja_blamerun in the session's
workspace instead of the gateway's launch directory, so a gateway serving
several workspaces puts each one's own project first. From @dchaudhari7177
(#5580, #5619). deja blameanddeja restorefind more of what an agent wrote: an
apply_patchthat renames a file records its hunks under the new name
(Codex, opencode, Copilot CLI, OpenClaw, pi, Cline, Roo and Amp filed them
under the old path), lines from CodeWhale'swrite_fileandfim_edit, the
symbol a Crushlsp_replace_symbolreplaced, the lines a Reasonix
delete_symbolcut, and a Copilot agent'sinsert_edit_into_file(#595). A
Codex shellapply_patchaftercd <dir> &&is filed under the directory
the cd left it in. From @dchaudhari7177 (#5306, #5613).- Several install and uninstall edges, each of which wrote half a target or
took a reader's file with it:- A target whose config directory cannot be created is refused before
anything is written:cursor-autounder a read-only~/.configwired
mcp.jsonandhooks.jsonand then failed. From @dchaudhari7177 (#5291,
#5611). Thekimi-autopre-flight checks the path the writer will use, so
a read-onlytui.tomlis refused beforeconfig.tomlmoves. From
@liziye627-design (#5309, #5615). - A
config.tomlthat spells deja's entry[[mcp_servers.deja]]is refused
untouched instead of getting a second table no TOML parser reads, the
note for an adopted Codex entry names its key once and only on the run
that changed it, Hermes keeps the last of two identical deja entries
instead of refusing, and a refused goose/dejacommand leaves no recipe
behind. From @shrinivas-sn (#5581, #5582, #5583, #5605).
goose-auto --no-guidanceno longer reports a recipe it did not write.
From @have-you-tried-restarting (#5589, #5596). - Uninstall removes only what deja wrote: Cline's three plugin files instead
of the whole directory with the reader's notes and skills, from @6xiaoyan
(#5300, #5556), and the reader's ownSKILL.mdthat install had replaced
is put back, from @Oscar-Williams (#5588, #5629); an empty~/.kiro/settingsdeja created, from
@Kasa-Harendra (#5594, #5597); the snapshot of deja's own text file (Kiro's
steering and agent files, the Copilot Chat prompt) while a reader's is put
back, the reader's OpenClaw snapshot whenplugins.slots.memorynames
deja, and the comments in a commented Copilotsettings.jsonhook list,
from @shrinivas-sn (#5584, #5591, #5607). - Comments survive a round trip: uninstall takes deja's entry out of a
tui.jsonthat has comments, from @liziye627-design (#5313, #5554), keeps
a comment the reader wrote on the list entry before deja's intui.json
and OpenClaw's load paths (#5557), and a JSONC status line leaves the
reader's comment on its own line, from @dchaudhari7177 (#5310, #5601).
- A target whose config directory cannot be created is refused before
- With embeddings on, a session that has no vectors yet (indexed since the
lastdeja embed, or synced from another machine) takes the mean similarity
of the hits that have them instead of zero, so it no longer sinks below
older sessions it outranks on keywords. From @zohartito (#5609). - With
DEJA_HERMES_PG_DSNset, a Hermes/branchcopy is filed as a fork
and adelegate_taskchild as a sub-agent, as from the SQLite store; on
Postgres both stood alone in project "hermes". From @dchaudhari7177 (#5294,
#5616). - A pi resume after a compaction that dropped the start digest but
kept a prompt's recall gets its digest again. From @dchaudhari7177 (#5314,
#5614). deja files,deja howand the MCP orient answer name a hyphenated project
the way the rows do: in~/proj/my-appthe scope line saidmy/app, a
name--projectfinds nothing under. From @dchaudhari7177 (#5321, #5602).- When two aiders start together and neither session can be told apart,
each later message no longer walks the whole chat history again while aider
waits on the context pipe. From @biggdawg320 (#5606). - With
DEJA_EXCLUDE_HARNESSESset,deja stats,deja sources, the empty
search and the first screen count project patterns and name the setting that
excluded each store, instead of blaming the exclude file. From @madhusai3113
(#5401, #5506). - A SQLite store read is given up only when it stops moving, not at ten
minutes on the clock: a Hermes store of 1,683 sessions still reading on a
slow disk was cut and left out of a first build. A store given up, or whose
read fails, is named (hermes: skipped — no progress for 10m0s; DEJA_STORE_TIMEOUT=0 waits),deja indexexits 3 anddeja doctorlists
it, and a rebuild keeps what the last index held from it (#5517). - A first build large enough to answer early no longer forgets the malformed
lines, unreadable files and rollouts waiting for zstd it found, so doctor
still reports them. From @beiryu (#5110, #5381). - A paged
deja search, MCPrecallandrecall_contextcheck a quoted
phrase's unread matches against the text instead of counting the words'
postings: on a 40k-session store"jolquihol huxdex"said 9 of 4,109 and
now lists 15 of 28. Past 20,000 postings the count is an estimate and says
about(total_estimatedin--json) (#5495). - A pass and a rebuild now leave the same index:
- Copies of one session id in several project directories give the same
command tables, facts, fixes andfrictext.bin, read from the copy the
row names, including a copy that takes the row from another project and a
deleted copy that kept turns it shared; a migrated goose session counts
each run once (#5490, #5491, #5492, #5504, #5508, #5509, #5510). - A transcript rewritten and moved to another project before the next pass
keeps its friction line and session facts (#5519). A session whose deleted
transcript owns its row keeps the conclusion, friction lines and questions
the pass read off that file, and a line a live transcript repeats from a
deleted copy is counted once (#5535, #5544). - A Claude, goose, kiro-cli or pi-family command whose result lands one pass
after its call carries theexit 0its result reports (#5527, #5529). - A word taken out of every transcript leaves
cooccur.gobon the pass that
replaced it, and a command removed from transcripts sharing an id leaves
commands.gobon the next pass (#5477, #5489). - A transcript with nothing to index, such as one tool result that was only
a<deja-recall>block, gets no empty session indeja last, and a
transcript read again drops such a tool-output record (#5555, #5563). deja forgeton a session whose transcript was already deleted no longer
leaves that file counted as kept until a second rebuild (#5521).- A transcript that lands between
deja index's freshness check and its
pass is no longer lost or doubled, and a file rewritten after its stat is
read again (#5503).
- Copies of one session id in several project directories give the same
deja index --quietno longer prints the shared-id line, which now counts
sessions rather than transcripts. Command "last run" dates read the same
after a pass and a rebuild, and a plain word some sessions hold only in a
command checks just those sessions instead of every unread match (#5504).
Changelog
Features
- feat(search): --sort date and ^s in the search screen list the newest match first (#5587)
- feat: add the MiniMax Code harness (#5415) (@yangala)
- feat: name a directory tree as one project with ~/.config/deja/projects (#5097) (@Maweill)
Fixes
- fix(aider): asker() stops re-walking the chat history after the session lookup gives up (#5606) (@biggdawg320)
- fix(cline): put back the SKILL.md install replaced on uninstall (#5629) (@Oscar-Williams)
- fix(cline): uninstall only the files deja wrote (#5556) (@6xiaoyan)
- fix(codex): a shell apply_patch after
cd <dir> &&is filed where the cd left it (#5613) (@dchaudhari7177) - fix(copilot): clearing deja's hook from a commented settings.json keeps the comments in the reader's list (#5607) (@shrinivas-sn)
- fix(copilot-chat): blame attributes lines a Copilot agent wrote with insert_edit_into_file (#5569)
- fix(embed): the rerank no longer sinks a session that has no vectors yet (#5609) (@zohartito)
- fix(files): the scope line names a hyphenated project the way the rows do (#5321) (#5602) (@dchaudhari7177)
- fix(goose): a refused /deja command leaves no recipe behind (#5582) (@shrinivas-sn)
- fix(hermes): install keeps the last of two identical deja entries instead of refusing (#5292) (#5605) (@shrinivas-sn)
- fix(hermes): read /branch and delegate_task marks from a Postgres store (#5616) (@dchaudhari7177)
- fix(index): a command removed from transcripts sharing an id leaves commands.gob on the next pass (#5485)
- fix(index): a copy that takes a shared row from another project keeps the turns both copies hold in its facts (#5505)
- fix(index): a deleted transcript that owns its row keeps what the pass read off it, and its repeated turn counts once (#5548)
- fix(index): a first build that publishes early keeps its Deferred list, malformed lines and failed reads for doctor (#5381) (@beiryu)
- fix(index): a pass and a rebuild count the same runs for copies of a session in several projects (#5513)
- fix(index): a pass mines a shared id's fixes from the copy its row names, as a rebuild does (#5516)
- fix(index): a re-read transcript drops a tool result that was only a recall block, as a rebuild does (#5559)
- fix(index): a slow SQLite store is read to the end, and one given up or failed is named and exits 3 (#5518)
- fix(index): a transcript rewritten and moved before the next pass leaves what a rebuild leaves (#5520)
- fix(index): a transcript that lands between deja index's check and its pass is no longer lost or doubled (#5515)
- fix(index): a transcript with nothing to index gets no session from an incremental pass, as a rebuild gives it none (#5565)
- fix(index): forgetting a session whose transcript was deleted no longer leaves that file kept until a second rebuild (#5546)
- fix(index): removed text leaves cooccur.gob on the replacing pass, and shared-id command tables match a rebuild (#5494)
- fix(index): the record offset table lists a session's records in log order after a rewrite moves turns to its kept copy (#5545)
- fix(install): a JSONC status-line round trip leaves the reader's comment on its line (#5310) (#5601) (@dchaudhari7177)
- fix(install): goose-auto --no-guidance no longer names a recipe it did not write (#5596) (@have-you-tried-restarting)
- fix(install): kimi-auto pre-flight checks the path the writer names (#5309) (#5615) (@liziye627-design)
- fix(install): name an adopted codex entry once and as written (#5581) (@shrinivas-sn)
- fix(install): refuse a config that spells deja's entry as an array of tables (#5583) (@shrinivas-sn)
- fix(install): refuse a config whose directory cannot be made before writing (#5611) (@dchaudhari7177)
- fix(install): uninstall drops the snapshot of deja's own text file and restores the reader's (#5584) (@shrinivas-sn)
- fix(install): uninstall keeps the reader's comment on the list entry before deja's (#5558)
- fix(kiro): prune empty ~/.kiro/settings on uninstall (#5594) (#5597) (@Kasa-Harendra)
- fix(mcp): recall's limit says the page is ~4 KB, and a page cut by size says "page full" (#5538)
- fix(openclaw): run the agent tools in the session's workspace (#5619) (@dchaudhari7177)
- fix(openclaw): uninstall keeps the reader's snapshot when plugins.slots.memory names deja (#5591) (@shrinivas-sn)
- fix(opencode): uninstall takes deja's entry out of a commented tui.json (#5554) (@liziye627-design)
- fix(pi): a compaction that kept a prompt's recall no longer stands in for the digest (#5614) (@dchaudhari7177)
- fix(plugins): deja_recall answers with the 4 KB recall page, not 222 KB of search --json (#5573)
- fix(search): a paged search counts a quoted phrase's unread matches by the text, not the postings (#5500)
- fix(skills): the shell fallback is deja recall, 4 KB instead of 222 KB of search --json (#5585)
- fix(sources): a command whose result lands one pass after its call gets its exit 0 (#5528)
- fix(sources): a goose, kiro-cli or pi command whose clean result lands a pass later gets its exit 0 (#5532)
- fix(sources): an apply_patch rename files its hunks under the new name, so blame finds them (#5572)
- fix(sources): blame sees CodeWhale write_file and fim_edit, Crush's replaced symbol and Reasonix delete_symbol (#5576)
- fix: a friction wall that stopped recurring or was settled leaves the session-start block (#5631)
- fix: deja fix knows package install errors behind a mirror or proxy (#5600)
- fix: deja install codex writes no type for the MCP server (#5603)
- fix: deja secrets --scrub redacts inside each JSON string, not the raw file (#5627)
- fix: project and harness exclusions are counted and named by their own source (#5506) (@madhusai3113)
- fix: the first screen names DEJA_EXCLUDE_HARNESSES for a store it excluded, not the exclude file (#5560)
Performance
- perf(index): a cold build derives each session's row on every core, not in the write loop (#5525)
- perf(index): a cold build drops each session's co-occurrence tokens once interned, not after the last session (#5539)
- perf(index): a cold build keys messages without allocating per word (#5575)
- perf(index): a cold build over a 5 GB store peaks at 4.7 GB, not 9.4 GB (#5498)
- perf(index): a cold build spills each token once per batch, not once per posting (#5537)
- perf(index): a pass that also sees a database store change reads only the sessions it changed (#5484)
- perf(index): deja index decodes the manifest once and walks the stores once (#5493)
- perf(redact): a cold build spends 17x less CPU redacting, with the same output (#5514)
- perf(search): a question with a word the store lacks reads each word's postings once, p95 420 to 170 ms on 19k sessions (#5547)
- perf(search): hits that each matched a turn of their own are no longer compared in pairs (#5550)
- perf(search): independent sessions with the same turns no longer make a search quadratic: 2400 take 0.13 s, not 46 s (#5502) (@Terminator637)
- perf(search): sessions that share turns but each go on no longer compare every pair of full records (#5542)
- perf(sources): grok, commandcode, kimi and kiro line readers stream long lines (#5475) (@littfed)
- perf: a cold build reads each transcript line and each tool output line once (#5592)
- perf: the search screen reads a page at a time and MCP recall searches once (#5497)
Documentation
- docs(changelog): 0.23.1 (#5534)
- docs(changelog): fold #5555 into 0.23.1 (#5564)
- docs(day-zero): ctx setup fails only on a one-directory corpus (#5531)
- docs(guide): add guide page for deleting Junie session history (#5088) (#5624) (@Kasa-Harendra)
- docs(guide): delete Antigravity conversation history (#5604) (@notsubash)
- docs(index): note the Codex and OpenClaw sub-agent changes under 72 and 73 (#5612) (@dchaudhari7177)
- docs(skill): name goose, Copilot CLI and prime-agent sub-agent runs (#5610) (@zening-cmd)
- docs: 0.23.1 changelog and site (#5630)
- docs: bring the site, architecture, security model and roadmap up to 0.23.0 (#5481)
Other
- chore: extension versions match the 0.23.0 npm release (#5483)
- chore: neutral names in fixtures and workflow comments (#5626)
- chore: pin the manifests to 0.23.0 (#5480)
- style: strict golangci-lint config and the fixes it asks for (#5598)
- test(cmd): async waits allow 2 min instead of a fixed 5 s, so loaded runners stop flaking (#5507) (@ganeshmshetty)
- test(cmd/deja): merge plugin wiring tests into one table-driven test (#5623) (@liziye627-design)
- test(hook): time the compaction freshness check against bare git calls on the same runner (#5566)
- test(index): each test that sets a home gets its own config, so one test's tombstone no longer drops the next test's session (#5574)
- test(redact): the parity sweep runs 8,000 texts under -race, so the package takes 2 min instead of 10-14 (#5562)
Install
curl -fsSL https://raw.githubusercontent.com/vshulcz/deja-vu/main/install.sh | sh
go install github.com/vshulcz/deja-vu/cmd/deja@v0.23.1
brew install deja-vu