github vshulcz/deja-vu v0.19.0

latest releases: v0.22.1, nightly, v0.22.0...
one month ago

Two things, mostly. deja now installs the way each harness installs everything
else — as a package in its own format, from its own catalogue — and a long bug
hunt went through the parts that report: the usage log, sync between machines,
and what doctor says when a file will not open.

Added

  • Gemini CLI installs this repository as an extension: gemini extensions install https://github.com/vshulcz/deja-vu brings the MCP server, the context file and the deja-search skill. The manifest sits at the root, which is also what the extensions gallery crawls. (#1725)
  • The Agent Plugins manifests are at the root too, so any host that reads the portable v1 format — Qwen Code among them — installs deja without a format of its own. (#1769)
  • A Kimi Code plugin, in extensions/kimi. One /plugins install gives Kimi the MCP tools, the shared skill, a /deja:recall command and recall on every prompt through its UserPromptSubmit hook. It stands down where deja install kimi already wired the same thing, so having both is not two of anything. (#1573)
  • A Grok Build plugin, with a licence in every bundle. (#1591)
  • A dsh plugin, and auto-recall that reaches the model rather than the transcript. (#1552)
  • The Codex plugin carries its own hooks: a marketplace install now brings session-start recall, per-prompt recall and pre-compaction capture with it, instead of only tools and the skill. It stands down where deja install codex-auto already wrote the same hook into Codex's own hooks.json. (#1583, #1584)
  • The opencode, dsh and Zed packages live in this repository, so a change to deja and the change to its packages land together. (#1562)
  • deja embed reaches an authenticated endpoint: DEJA_EMBED_KEY for any OpenAI-compatible URL, and OPENAI_API_KEY only for an HTTPS api.openai.com one — never forwarded implicitly to localhost or a third party. Contributed by @chrisgeo. (#1919)
  • PowerShell completion. (#1803)
  • The fix pair arrives when a command fails, rather than waiting to be asked. (#1550)
  • Recall says when a hit is the other machine's copy of a session this one already holds, and when a session's date is later than this machine's clock. (#1754, #1776)
  • An index run says how many lines it could not read, and doctor --json carries the sync state that used to exist only on the screen. (#1839, #1994)

Changed

  • The release archive carries gemini-extension.json and GEMINI.md. gemini extensions install reads the manifest out of the release asset rather than from git, so the documented command failed on every published version until now. (#1935)
  • deja install refuses rather than guesses in the places it used to guess: a guidance block it cannot bound, a cordis.patch.yml missing one of deja's markers, a goose extensions: list where a mapping was expected, an opencode.jsonc that uses trailing commas, a relative XDG_CONFIG_HOME, and a machine with no home directory. It also writes a config back with the line endings it already had. (#1666, #1669, #1691, #1694, #1696, #1698, #1700, #1702, #1706)
  • The usage log holds one definition of an event, one week for every counter that shows one, and a record size it can actually hold. Rotation keeps the newest events instead of emptying the file. (#1918, #1921, #1923, #1974, #1981, #1986)
  • doctor explains rather than accuses: a corrupt sidecar is not a missing one, an unreadable peers file is not "no machines", a transcript it may not open is named instead of the harness format being blamed, and a peer stamp ahead of this machine's clock is said out loud. (#1711, #1713, #1749, #1841, #1856, #1860, #1961)

Fixed

  • Two syncs at once no longer lose machines, and one machine named in two letter cases is one machine — in the watermark, in doctor's count, and in how a host name is matched, which is the way ssh matches it. (#1854, #1868, #1877, #1879, #1884)
  • ssh gets a connect timeout, so a sleeping machine costs seconds rather than minutes. (#1773)
  • A credential in an uppercase _KEY environment assignment is stripped at index time, and so is a secret whose JSON arrived with its quotes escaped. (#1766, #1958)
  • The PATH offer in install.sh sat behind a condition curl | sh can never meet, so nobody installing the documented way was ever asked. (#1852)
  • A truncated line — in the log, in the snapshots file, in the hook's dedup file — is closed before the next event is appended, rather than merged into it. (#1910, #1947, #1966)
  • Unicode folding covers Arabic hamza and madda, the three Greek marks written on a spacing diaeresis, and letters carrying two marks. (#1836, #1873, #1895, #1914)
  • The statusline gives the filename up before the memory half when the bar is too narrow, and uses the count form when even the title will not fit. (#1881, #1904)
  • The index resolves a shared session id the same way every time, counts the empty transcripts of the last build rather than of the process, follows a store directory that is a symlink, and says a store went away instead of greeting the reader as new. (#1745, #1764, #1851, #1998)

Changelog

Features

  • feat(codex): the listing metadata the plugin directory asks for (#1584)
  • feat(codex): the plugin brings its own recall, not just tools (#1583)
  • feat(completion): support PowerShell (#1803)
  • feat(doctor): report the sync state in --json, not only on the screen (#1839)
  • feat(extensions): keep the opencode, dsh and Zed packages in this repository (#1562)
  • feat(grok): a Grok Build plugin, and a licence in every bundle (#1591)
  • feat(index): say how many lines an index run could not read (#1994)
  • feat(kimi): a Kimi Code plugin that recalls what the other agents wrote (#1573)
  • feat(recall): say when a hit is the other machine's copy of a session this one holds (#1776)
  • feat(recall): say when a session's date is later than this machine's clock (#1754)
  • feat: carry the Agent Plugins manifests at the root (#1769)
  • feat: dsh plugin, and auto-recall that actually reaches the model (#1552)
  • feat: install deja into Gemini CLI as an extension (#1725)
  • feat: support authenticated embedding endpoints (#1919)
  • feat: the fix pair arrives when the command fails (#1550)

Fixes

  • fix(aider): drop bytes that are not utf-8 at ingest, like every other parser (#1741)
  • fix(blame): a path with a line number answers for the file (#1626)
  • fix(brief): a reader who turned colour off still gets the brief (#1597)
  • fix(brief): fit the wire line into a 60-column pane (#1554)
  • fix(brief): keep the first screen inside a 60-column pane (#1589)
  • fix(brief): say a store was locked instead of no agent ran here (#1980)
  • fix(brief): shorten a wide project before the title floor absorbs it (#1593)
  • fix(brief): show a project name the same way at every terminal width (#1845)
  • fix(compact): strip control bytes from the evidence block (#2001)
  • fix(completion): offer every role deja accepts, not the three it once had (#1659)
  • fix(completion): the bash function survives a shell with set -u (#1657)
  • fix(ctx): an id-prefix answer says when the decision was taken back (#1644)
  • fix(ctx): open the session a short id-prefix names instead of denying it exists (#1615)
  • fix(docs): dsh refuses plugin add without --profile (#1846)
  • fix(doctor): count a machine's sessions whichever case it spells its name in (#1877)
  • fix(doctor): emit the stale_stores the JSON schema documents, and name the real policy file (#1711)
  • fix(doctor): have --deep say what it compared instead of promising no memory was lost (#1713)
  • fix(doctor): learn what a peer calls itself, so its sessions are counted (#1888)
  • fix(doctor): line the Sync column up by what the terminal draws (#1822)
  • fix(doctor): name the transcript it may not open instead of blaming the harness format (#1749)
  • fix(doctor): name the zed, deepseek and omp stores it reads from (#1739)
  • fix(doctor): say when a peer's stamp is ahead of this machine's clock (#1856)
  • fix(doctor): say when the peers file cannot be read instead of reporting no machines (#1841)
  • fix(doctor): tell a corrupt sidecar apart from no sidecar (#1961)
  • fix(extensions): carry the licence into the Zed extension directory (#1565)
  • fix(extensions): one rule for what a package adds next to deja install (#1570)
  • fix(extensions): stop recalling twice when both installs are present (#1567)
  • fix(files): refuse a flag with no value, an unknown flag and an empty topic (#1629)
  • fix(fix,how): keep a transcript from forging a row of the listing (#1864)
  • fix(forget): say a deleted transcript is gone from this machine, not that it came from another (#1756)
  • fix(friction): one error stays one wall when pytest or a log stamps the line (#1638)
  • fix(friction): the trust note counts the sessions it hid, not their error lines (#1640)
  • fix(greeting): count in singular when there is one of something (#1599)
  • fix(handoff): an empty --to is refused, not read as no target at all (#1648)
  • fix(help): a hook command is documented or deliberately hidden, not skipped wholesale (#1655)
  • fix(help): wrap the install target list to the terminal, not to a fixed 76 columns (#1662)
  • fix(hooks): close a truncated dedup line before appending (#1968)
  • fix(hooks): recall the fix for an error even when the tool log runs past 1 MiB (#1718)
  • fix(how): match the command as a word, and refuse a flag that does nothing (#1631)
  • fix(how,files): say when the list was cut at the limit (#1633)
  • fix(id): an id pasted in the other case opens the session it names (#1621)
  • fix(index): clear the evicted-files counter per build, and catch the next one (#1862)
  • fix(index): count the empty transcripts of the last build, not of the process (#1851)
  • fix(index): follow a store directory that is a symlink instead of calling it empty (#1745)
  • fix(index): keep the commands that repair a build, not only the ones that fail (#1636)
  • fix(index): pluralise file and message counts on the incremental line (#1585)
  • fix(index): re-read the stores that needed a CLI once that CLI is installed (#1761)
  • fix(index): resolve a shared session id the same way every time (#1998)
  • fix(index): say a store went away instead of greeting the reader as new (#1764)
  • fix(index): say when only half a store could be read, in the run and in doctor --json (#1759)
  • fix(index): tell a run that waited for another build where the index stands (#1752)
  • fix(install): call a mistyped flag a flag, whether or not a target came with it (#1681)
  • fix(install): end deja's kimi hook block at the next comment, not the next table (#1700)
  • fix(install): ignore a relative XDG_CONFIG_HOME, as the spec requires (#1694)
  • fix(install): name the config a permission error stopped, not deja's scratch file (#1687)
  • fix(install): refuse a cordis.patch.yml where one of deja's markers is missing (#1702)
  • fix(install): refuse a goose extensions: list rather than writing a mapping into it (#1698)
  • fix(install): refuse a guidance file whose block deja cannot bound, and repair a duplicated one (#1706)
  • fix(install): refuse when deja cannot find a home directory, instead of wiring the working directory (#1691)
  • fix(install): say when it replaced a skill file it has no record of writing (#1704)
  • fix(install): stop blaming file permissions for a config deja could not parse (#1666)
  • fix(install): stop writing a stray comma into an opencode.jsonc that uses trailing commas (#1696)
  • fix(install): the PATH offer was behind a condition curl | sh can never meet (#1852)
  • fix(install): write a config back with the line endings it already had (#1669)
  • fix(json): a stemmed answer reports the stemmed tier, not close (#1617)
  • fix(json): drop a timestamp that was never set instead of writing year 1 (#1875)
  • fix(last): a bare argument that is not a count is refused, not ignored (#1619)
  • fix(lifecycle): a promote note is clipped like every other line on the screen (#1646)
  • fix(log): answer --last --json in JSON when there is no digest (#1976)
  • fix(log): stop calling an injection that sent bytes an empty result (#1955)
  • fix(mcp): answer from the index while a refresh runs instead of sending the agent away (#1734)
  • fix(mcp): answer ping instead of method-not-found, so a host keepalive does not read the server as dead (#1722)
  • fix(mcp): decide remember's index refresh with one lock attempt instead of a check and a wait (#1805)
  • fix(mcp): hold recall_context to the ~8KB it promises, and say when a digest is cut (#1798)
  • fix(mcp): keep the offset line on a full recall page, so the rest of the matches stay reachable (#1727)
  • fix(mcp): let blame answer from the snapshot while a rebuild runs (#1785)
  • fix(mcp): mark the excerpt the recall page budget cut, like every other cut line (#1800)
  • fix(mcp): name the phase while a build starts instead of an empty parenthesis (#1732)
  • fix(mcp): recall_context opens the session an id names (#1623)
  • fix(mcp): refuse a batch as an invalid request instead of claiming it did not parse (#1796)
  • fix(mcp): refuse a resource uri with no session id instead of serving whichever came first (#1730)
  • fix(mcp): take the environment block out of recall's budget instead of adding it on top (#1807)
  • fix(mcp): tell an agent which argument was wrong instead of handing back the JSON decoder's text (#1724)
  • fix(nfcfold): fold Arabic hamza and madda (#1914)
  • fix(nfcfold): fold letters that carry two marks (#1873)
  • fix(nfcfold): fold the three Greek marks written on a spacing diaeresis (#1895)
  • fix(notes): count a note deja cannot read (#2006)
  • fix(npm): the dsh package page rendered in Chinese (#1837)
  • fix(peers): stop two syncs at once from losing machines (#1884)
  • fix(peers): treat a host name the way ssh does, case and all (#1868)
  • fix(rank): score by sessions, gate by the rarer verdict (#1548)
  • fix(redact): redact a secret whose json arrived with its quotes escaped (#1766)
  • fix(redact): strip credentials from uppercase _KEY env assignments (#1958)
  • fix(release): ship the Gemini manifest in the archive (#1935)
  • fix(remember): bound and de-escape the project name the confirmation echoes back (#1793)
  • fix(remember): clean and bound a tag where it is written, and where it is echoed (#1811)
  • fix(remember): keep checking for duplicates past an oversized note (#1813)
  • fix(remember): keep one copy of a note instead of charging every later recall for the same fact (#1737)
  • fix(search): --since refuses a window that is not positive (#1611)
  • fix(search): a filter flag given an empty value is a mistake, not a wildcard (#1613)
  • fix(search): a one-word query scores on the word, not on the punctuation around it (#1604)
  • fix(search): a regex match with no width is not a match (#1607)
  • fix(search): run the co-occurrence rescue when the words never appear together (#1787)
  • fix(search): stop telling a reader who typed --all to add --all (#1609)
  • fix(show): tell the two halves of the repeated hour apart (#1789)
  • fix(stats): an empty top_projects is [] like its sibling, not null (#1650)
  • fix(stats): say which window the impact numbers cover (#1890)
  • fix(stats): the impact screen reads at one recall (#1653)
  • fix(statusline): let the filename give way so the memory half fits the bar (#1881)
  • fix(statusline): the quiet-day line counts one recall as one (#1601)
  • fix(statusline): use the count form on a bar too narrow for the title (#1904)
  • fix(sync): bound and de-escape peer names on the screens that report them (#1809)
  • fix(sync): bound the batch file name an import error reports (#1848)
  • fix(sync): bound the peer's output where the failure is turned into an error (#1820)
  • fix(sync): bound the ssh capture's error like the rest of the sync path (#1834)
  • fix(sync): give ssh a connect timeout so a sleeping machine costs seconds, not minutes (#1773)
  • fix(sync): one machine, one watermark, whichever case the name was typed in (#1879)
  • fix(sync): sanitise the directory in every sentence that names it (#1858)
  • fix(sync): stop calling a push with nothing to send an exchange (#1781)
  • fix(sync): treat one machine named twice as one machine (#1854)
  • fix(termwidth): count the wide emoji blocks the table stopped short of (#1595)
  • fix(termwidth): measure a name the same however it was typed (#1825)
  • fix(uninstall): take the shared skill file with the last harness that read it (#1685)
  • fix(usage): ask the snapshots file the same question as the log (#1947)
  • fix(usage): close a truncated line before appending the next event (#1902)
  • fix(usage): close a truncated snapshot line before appending (#1966)
  • fix(usage): count a blame and a resource read on both screens (#1908)
  • fix(usage): count an injection that carried no project session (#1963)
  • fix(usage): keep the injection log under its rotation threshold (#1970)
  • fix(usage): one rule for what counts as an event in the log (#1918)
  • fix(usage): one week for every counter that shows one (#1921)
  • fix(usage): record where a session-start digest went (#1950)
  • fix(usage): rotation keeps the newest events rather than emptying the log (#1923)
  • fix(view): redact the page it writes instead of trusting what the index kept (#1770)
  • fix(zed): one server id for the extension and the installer (#1571)
  • fix(zed): read a cut-short sqlite3 answer as the rows it delivered (#1568)
  • fix: align daily recall counts with weekly usage (#1569)
  • fix: an empty id prefix resolves to nothing, in both lookups (#1774)
  • fix: resume Grok Build sessions (#1707)
  • fix: version and security policy in the plugin bundles (#1719)

Performance

  • perf(ctx): render a digest's turns across cores, 4.5s to 1.2s on a 30001-message session (#1791)
  • perf(ctx): stop handing every transcript line to a regexp engine — 22.6s to 4.6s on a 30000-turn session (#1743)
  • perf(main): stop parsing every store to count its files (#1990)
  • perf(search): build the query side of the record check once (#1886)
  • perf(usage): stop re-reading a log that has nothing to drop (#1973)

Documentation

  • docs(architecture): say which machines deja treats as one (#1916)
  • docs(json): describe deja log --json and pin its keys (#1933)
  • docs(json): describe stats --impact --json and pin its keys (#1900)
  • docs(json): name the kind Claude sets, and pin the optional session keys (#1937)
  • docs(json): say that a peer stamped ahead gets a minute of slack (#1866)
  • docs(json): say what a week and a day mean in the stats numbers (#1940)
  • docs(json): the peer host is reported as written, not bounded (#1870)
  • docs(sitemap): every entry carries a lastmod, from the registry's own dates (#1899)
  • docs(termwidth): say that a cut returns composed text, and pin the brief's splice (#1843)
  • docs(usage): write down the rotation window the append accepts (#1909)
  • docs(zh): point the dsh plugin link at extensions/dsh (#1566)
  • docs: Chinese README, and publish the dsh plugin to npm on release (#1553)
  • docs: a page for the question people actually type (#1667)
  • docs: adding memory to opencode (#1688)
  • docs: changelog for 0.19.0 (#2013)
  • docs: finding an old session, and several agents on one repository (#1679)
  • docs: finish the move off the tap, including the demo GIF (#1767)
  • docs: guide pages for Claude Code, Codex, Cursor and Copilot (#1938)
  • docs: install from homebrew-core, not the tap (#1763)
  • docs: link the guide from the README, which is the page Google crawls most (#1896)
  • docs: measure the numbers instead of carrying them forward (#1549)
  • docs: memory pages for Gemini CLI and Qwen Code (#1757)
  • docs: memory pages for dsh, Kimi Code, Zed and Grok Build (#1689)
  • docs: name the one object-shaped answer that carries no schema_version (#1977)
  • docs: name where the harness packages publish from now (#1564)
  • docs: pages for exporting a session and for syncing across machines (#1673)
  • docs: pages for lost context, a full window, and resuming a session (#1771)
  • docs: pages for the repeated wall and for switching agents (#1672)
  • docs: publish llms.txt, the map an agent reads instead of crawling (#1871)
  • docs: put automatic recall and redaction on the first screen (#1560)
  • docs: refresh the outside-contribution numbers (#1580)
  • docs: say the words people search for, and guard the structured data (#1823)
  • docs: scoop install deja-vu, now that the manifest is in the main bucket (#1906)
  • docs: tell IndexNow when pages change (#1682)
  • docs: the home page had no robots meta, unlike every guide page (#1893)
  • docs: two more pages for questions people type, and a guard for the set (#1670)
  • docs: what memory costs in tokens (#1674)
  • docs: when the rules file grows, and auditing what an agent did (#1678)

Other

  • Merge pull request #1912 from vshulcz/merge/hunt-2026-08-23
  • Merge pull request #2011 from vshulcz/merge/hunt-2026-08-26
  • Merge remote-tracking branch 'origin/hunt/2026-08-23' into merge/hunt-2026-08-23
  • Merge remote-tracking branch 'origin/hunt/2026-08-23' into merge/hunt-2026-08-26
  • chore(dsh): 0.20.4, to republish with the English package page (#1849)
  • chore(scoop): canonical key order and checksums-based autoupdate (#1814)
  • chore(sync): drop the export helper the push path stopped using in #215 (#1892)
  • chore: Search Console verification file (#1882)
  • chore: name the homepage, repository and licence in the plugin manifest (#1555)
  • chore: open a discussion with every release (#1559)
  • chore: pin scoop, winget and the codex plugin to 0.18.0 (#1547)
  • chore: the dsh plugin lives in its own repository now (#1558)
  • ci: give every package a coverage floor (#1956)
  • ci: give peers and stats a coverage floor, and say which floors are tight (#1944)
  • ci: publish the harness packages from the release, at the release version (#1574)
  • ci: run the HOL plugin scanner on the Codex bundle (#1715)
  • ci: tell the plugin scanner which files are redaction fixtures (#1717)
  • compare: the tools that read the same session files (#2008)
  • grant discussions:write to the release job (#2016)
  • mcp: answer ping and resources/templates/list (#1746)
  • mcp: refuse a session uri that carries no id (#1750)
  • release: open the page with what changed, not with the install command (#1581)
  • stats: make the impact screen agree with a count of one (#1675)
  • test(atomicfile): cover WriteStream, which had none (#1957)
  • test(docs): end a doc section at the heading that ends it (#1952)
  • test(doctor): pin what a peer row with neither timestamp means (#1860)
  • test(hook): measure the task-git budget against a repo that has changes (#1996)
  • test(hooks): hold the session start to one project across worktrees (#1959)
  • test(hooks): pin the receiver both injection paths record (#1953)
  • test(index): measure the early exit against a log worth scanning (#2004)
  • test(index): pin that the index keeps what the transcript brought (#1992)
  • test(index): stand where the swap-window wait is instead of racing a goroutine against it (#1783)
  • test(json): catch a struct that embeds a type writing its own JSON (#1897)
  • test(json): pin the keys deja show and deja last emit to the document (#1911)
  • test(kimi): compare the two manifests whole instead of five keys of them (#1778)
  • test(mcp): pin the budgets the conclusions gate was measured at (#1802)
  • test(nfcfold): tie the composition table to the block the scan looks for (#1836)
  • test(notes): pin what re-promoting an old record does, and stop a flaky cap test (#1816)
  • test(peers): hold the shape that keeps the lock's fallback out of reach (#1905)
  • test(search): record what the close tier's length bucket still reaches (#1945)
  • test(search): record which tier joins a word to its marked form (#1942)
  • test(stats): hold the card and the page to the week the report carries (#1948)
  • test(usage): measure the shape that costs three bytes a character (#1987)
  • test(usage): measure what a record weighs instead of guessing (#1981)
  • test(usage): pin that a blank line in the log is read past (#1910)
  • test(usage): pin the record size this log can hold (#1974)
  • test(usage): pin why the environment block stays out of the impact ratio (#1964)
  • test(usage): state the room one event has, and hold the writers to it (#1986)
  • test(view): pin that a note's tag cannot close the page's script block (#1818)
  • test(windows): fix the two tests that fail on every Windows checkout (#1677)
  • warmup: name the phase before it is written (#1748)

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.0
brew install deja-vu

Don't miss a new deja-vu release

NewReleases is sending notifications on new releases.