Stay on npm install -g memtrace for everyday use. Nightly is the same command with new features as they land, and it is not always stable.
Sessions clean up after themselves, and reset never deletes your history
New
Clearing or resetting a store no longer deletes anything: everything it held moves to a sibling history archive next to the store, ready to restore by moving it back. The new memtrace history command lists archived generations, and only the explicit memtrace history purge --store <path> --delete-forever can permanently remove them.
memtrace stop now also collects engine processes left behind in other workspaces when the store's own records prove their owning session is gone, so a forgotten window can no longer leave a database engine running for days.
New features land on Nightly first: npm install -g memtrace@nightly is the same memtrace command, and it is not always stable. They still ship on the default install. memtrace install stays on the channel you already have.
A built-in CPU profiler: set MEMCORESELFPROFILE=1 and the engine samples its own hot functions and writes named stack reports into its normal log — no admin rights or external tools needed on any machine.
memtrace ui serves the dashboard on its own against an engine that is already running. It does not index, watch, or take workspace ownership, so the dashboard and the engine can be restarted independently and a status page can outlive the editor session that used to keep it alive.
memtrace claude install writes a Memtrace routing directive into a project's own CLAUDE.md, so Claude Code reaches for Memtrace before text search in that repository. It survives context compaction, can be committed so a team shares one rule, and memtrace claude uninstall removes it leaving the rest of the file byte-identical.
Directories that are not git repositories can now be indexed as a point-in-time snapshot, with --allow-non-git or MEMTRACEALLOWNONGIT. Symbols, relationships, impact and search all work; history-derived answers are unavailable by construction and now say so rather than returning an empty result that looks like nothing ever changed.
cleanupstalerecords gained a checkstalespans scope that reaches symbols left behind in files that still exist — the case the missing-file scope cannot see, which previously needed deleting the whole repository.
--index-ignored (or MEMTRACEINDEXIGNORED) indexes the files a repository's ignore rules would normally hide. Every ignore source is turned off together, parent directories included, so an ancestor cannot keep filtering a tree you asked to see in full. Off by default: a repository's ignore rules are written for building the product, and honouring them is what almost everyone wants.
Fields and constants are now first-class symbols with read and write edges, extracted across 18 language families and classified by each language's own write-once form — so getimpact finally answers who reads a feature flag, config constant, or magic number, with no getter workaround. Compound assignments record both a read and a write. Thanks to Magalz for the field report behind this batch.
linksymbols records cross-repository relationships at symbol granularity — queue producer/consumer pairs, gRPC seams, shared schemas the HTTP linker cannot infer — and getimpact walks them in both directions. An ambiguous name is refused with the candidates listed, never guessed.
ingestgraphfragment lets your own tools contribute nodes and edges for structure Memtrace cannot parse — generated stubs, in-house DSLs, build-graph output — with a provenance tag stamped on every contributed record and surfaced in queries, and rerunning generators rewrite their rows instead of duplicating them.
findcodereviewissues flags a value consumed inconsistently across call sites — the classic money, timestamp, and ID bug no single-file rule can see — listing every consuming site, and staying quiet when narrowing is unanimous and deliberate.
Annotation names and their arguments are captured and queryable: findsymbol can filter by annotation and getsymbolcontext surfaces them, across Java and Kotlin annotations and Python and TypeScript decorators.
Named milestone anchors bind a name to an instant, and getevolution can diff the graph between two named states — release-to-release change reports without hunting timestamps. Re-creating a name moves the anchor, because a re-cut release is the common case.
An opt-in query-level audit log (MEMTRACEQUERYAUDIT=1) records one line per tool call — who, what, when, outcome — exported with exportqueryaudit. Tool arguments are deliberately not recorded, so the audit trail can never become a second copy of your source under weaker access control.
Fixed
Closing an agent session no longer leaves its database engine running in the background — every exit path now shuts the engine down with the session.
Background agent sessions no longer advertise a dashboard port they never opened, which made memtrace start mistake a healthy session for a broken one and restart it, briefly taking every connected agent down with it.
Memory no longer spikes by hundreds of megabytes per code search in each connected agent: searches now reuse the running workspace engine for query embedding, the reranking model unloads when idle, and freed memory returns to the system promptly.
Recovering a store with damaged records no longer floods the engine log with megabytes of repeated warnings per minute; repairs are summarized instead.
Stopping Memtrace in one workspace can no longer discard the runtime record of a different workspace whose session is still running.
History and timeline questions no longer scan and decode the entire store: all-time and as-of queries are answered from the property index, so a daemon left running with no clients measures around one percent of a core instead of holding two or more cores forever.
Deleted or superseded code now stays deleted after a restart. Soft-deletes used to live only in memory, so every boot brought removed vectors back as live and searchable and the compactor re-reclaimed them each time; deletes are now durably logged and replayed on boot, with no store migration needed.
If the property index cannot record a write, the store now marks that index incomplete and answers from the full data until it heals, instead of silently missing rows.
A single slow engine call can no longer hold a client request open indefinitely: per-call deadlines fail fast with a clear error instead.
On NVIDIA cards, embeddings no longer route through DirectML when the runtime documents a better provider for that hardware — and when CPU is measurably faster, Memtrace says so plainly instead of pretending the GPU helps.
Windows no longer loops demoting and rebuilding the insights cache: file replacement follows one atomic rule everywhere, and Windows now matches macOS across path handling, locks, and Cortex startup.
Startup embedding and cross-repository relinking can no longer deadlock each other during boot.
Starting the dashboard next to a headless agent session takes over the store cleanly instead of leaving both processes wedged.
Stale overlay copies of a symbol no longer outrank the current version in search results, and a modified symbol now closes its superseded predecessor rows so watched repositories stop accumulating duplicates.
Cleanup no longer flags virtual paths as missing files, and branch-scoped statistics explain a near-empty scan instead of looking broken.
Starting no longer aborts with a multi-gigabyte allocation failure when a recovery checkpoint points into the middle of a record instead of at a record boundary. A damaged checkpoint now costs a slower start rather than a database that can never be opened again, and the recovery path can no longer shorten a log to a position it has not verified.
Repository enumeration is bounded and no longer stalls a whole agent session. If it outruns its deadline it reports what to do instead of leaving the client to give up in silence, and tools that need a repository will now read the store's own membership record when enumeration cannot answer — so a slow discovery call no longer blocks everything behind it.
A relationship query that finds no connections now says whether that is a conclusive answer. A count of zero used to read as proof that a symbol was unused even when the lookup itself had not resolved, which is the worst possible wording ahead of a deletion.
A background pass that processed nothing is no longer reported as a failure. An empty work-set cannot have failed, and calling it one led users toward wiping a store whose data was intact and only needed its index repaired.
The graph view only suggests running an index when the store is confirmed empty. While indexing is in progress, or while counts are briefly unavailable, it now says so instead of advising a second indexer against a store the first one is still writing.
The upgrade hint names sudo when, and only when, the install location actually needs it, so an upgrade on a system-owned install no longer fails with a permissions error after you have already confirmed it.
memtrace status confirms the dashboard is really listening before printing its address, and says so plainly when the port is recorded but nothing answers on it.
MCP sessions no longer leave behind lease files owned by processes that have exited, and a session that is stopped abruptly is cleaned up by the next start rather than accumulating. The Cortex socket is removed when the daemon that owned it stops.
doctor --fix now names the sessions it could not stop, which application owns each one, and the exact command to stop them — rather than reporting that it found processes and then leaving them running.
A workstation that sleeps overnight no longer fills the log with one identical heartbeat warning per cycle. The first failure is reported, the rest stay quiet, and a single line says when the network came back and how long it was gone.
The documentation assistant no longer tells Windows and Linux readers to press a key their keyboard does not have; the search shortcut now shows the modifier for the reader's platform.
The documentation assistant follows a streaming answer the way a terminal does: it stays pinned while you are at the bottom, releases as soon as you scroll up to read, and re-attaches when you scroll back down.
--allow-non-git passed inside an actual git repository no longer disappears without a word. The flag only opens the gate for a directory with no version control, so it now says it does not apply, names the repository it resolved, and points at --index-ignored when indexing ignored files is what you were after.
Files whose extension matches no supported language are now counted and reported by the scan instead of vanishing from every statistic. A tree Memtrace has no parser for used to be indistinguishable from an empty one.
Running out of file watches on the host no longer costs you the whole daemon. Exhausting the operating system's watch capacity used to abort startup outright — no dashboard, no agent connection, no way to reach an index that was already complete. Memtrace now starts without live watching, names the limit it hit and the exact command to raise it, and keeps serving search, graph and impact. Watcher failures it cannot explain still stop startup, because those are not something a host setting fixes.
memtrace install no longer depends on npm being resolvable from the shell it happens to run in — it now finds the npm that ships beside Node itself. And when the upgrade genuinely cannot run, it says what went wrong in one line instead of crashing with a stack trace that buried the reason.
Upgrades no longer complete silently WITHOUT their finishing step on newer npm versions whose script policy blocks install scripts by default: the installer now grants itself permission to run its own completion step, so the platform binary and the consented configuration always arrive together with the package.
Installs and upgrades now succeed even from a shell where Node itself is not on PATH: the installer carries its own Node location into every step it runs. It also stops a running Memtrace before replacing its files, so a live daemon can no longer make a Windows upgrade half-land on locked binaries.
findduplicatecode no longer reports a symbol as a duplicate of itself. Copies the index holds more than once — branch snapshots, working-tree saves, path-spelling variants — are collapsed before pairing, so each real duplicate appears exactly once and cites the correct original. Thanks to Trekkie for the report.
findduplicatecode now honors its branch parameter: results are scoped to the requested branch, or to the repository's current branch when omitted, and asking for a branch with no indexed code is a clear error instead of a silent unscoped scan. Thanks to Trekkie for the report.
The dashboard's exact-duplication figure now counts real duplicated function bodies instead of raw scan rows, which could overstate duplication roughly twenty to one. Thanks to Trekkie for the report.
cleanupstalerecords now treats filepathpattern as a strict boundary: combined with any staleness scope, nothing outside the pattern can be selected for deletion, a pattern that matches nothing deletes nothing, and the sampled paths always satisfy the pattern. Previously the scopes combined as a union, so a cleanup scoped to one file could silently select records across the whole repository; scrubs that intentionally span scopes now take one call per scope. Thanks to Trekkie for the report.
getrepositorystats can no longer present a healthy graph as empty: when an exact branch match finds almost nothing, statistics are recomputed with the same branch-ancestry visibility every other graph tool uses, and any remaining divergence is explained in the response with the store's real live counts and the likely cause — so zero edges never silently looks like a failed index. Thanks to Trekkie for the report.
getrepositorystats without a branch now reports the repository's primary indexed branch — the one listindexedrepositories shows — instead of whatever branch the local checkout happened to be on, and the tool reference now defines every node count and when indexingincomplete is set. Thanks to Trekkie for the report.
When the database backend dies or stops answering mid-session, the heavy graph tools — getcochangecontext, getevolution, getsymbolcontext — now fail within seconds with the clear endpoint-unreachable error, even for calls already queued behind another heavy query, instead of blocking for up to thirty minutes. Thanks to Trekkie for the report.
Cancelling or abandoning a tool call now stops its server-side work, so an abandoned heavy query no longer keeps burning CPU or starving the queries behind it. Thanks to Trekkie for the report.
memtrace index no longer stalls for five minutes and exits with an error when embeddings are enabled: the wait for cross-repository graph convergence now happens only after the index has published its results, so indexing and background relinking can no longer lock each other out.
indexdirectory now attaches to a repository's index job already in flight instead of starting a second run, which could race the first and leave the older job's record stalled forever.
Improved
The agent-tooling hook that routes code searches now asks the running workspace service directly instead of launching a new program for every terminal command, removing dozens of short-lived processes per minute during active coding sessions.
Symbol evolution views make one pass over the history window instead of one query per episode, so long histories load quickly.
Cross-repository topology lookups seek directly to the rows they need instead of walking unrelated ones.
Background maintenance now reports each tick's cost in the log, so a busy daemon can say what it was doing.
The documentation now covers clone detection and repository statistics: what findduplicatecode pairs and how its branch scoping works, what the dashboard's duplication figure counts, every getrepositorystats node count and when indexingincomplete is set, and how cleanup scopes combine. Thanks to Trekkie for flagging the gaps.
A branch-scoped symbol miss now names the branches that do carry the symbol, instead of returning the same empty answer as a symbol that does not exist.
Cross-repository calls stay connected from service map to graph
New
Python subprocess calls and commands embedded in Nextflow script and shell processes can now connect to matching command-line programs in another repository when the executable is statically identifiable.
R projects now retain structured evidence for base and Tidyverse pipelines, tidy-evaluation operators, data masks, tidy-select helpers, and formula lambdas instead of flattening those expressions into unrelated symbols.
Improved
Cross-repository service discovery now recognizes more C# and C++ HTTP clients plus gRPC, WebSocket, and common message-queue framework calls.
Django model relations, string URL views, class-based views, decorators, dynamic module imports, and common framework string references now leave inspectable graph evidence when their targets can be resolved.
Inferred relationships expose their confidence and reason in the graph inspector, so a framework or cross-repository link can be checked instead of accepted as an unexplained line.
Fixed
Opening a cross-repository call from the service map now keeps that relationship in the main graph and makes the connection visible instead of selecting an apparently isolated node. Agent impact and blast-radius queries follow the same call through its remote endpoint and handler, and identify the affected repositories explicitly.
Code previews now apply syntax highlighting to R and use one supported-language mapping for every language Memtrace indexes.
Python handlers and framework entrypoints no longer look dead merely because the framework reaches them through a decorator or a resolved string reference.
Malformed Kotlin input can no longer leave an extra-symbol query consuming a full core and gigabytes of memory indefinitely.
The first memtrace index or memtrace start used to keep embeddings and parsing on a full-speed CPU pool even after the indexer itself stepped down to a background slice of cores. Those jobs now share that same cap, so a first run on a passively cooled laptop stays usable. Pass --max-cores N if you want a smaller slice.
Parsed symbols are written as soon as resolve finishes, so findsymbol and the graph in /ui can start answering while modules are still being detected.
On Windows, indexer threads run at below-normal priority so the desktop stays in front while a first index is running.
Start Memtrace and sit still — idle CPU stays down
New
New features land on Nightly first: npm install -g memtrace@nightly is the same memtrace command, and it is not always stable. They still ship on the default install. memtrace install stays on the channel you already have.
Fixed
After memtrace start on a database you already indexed, Memtrace no longer rebuilds search indexes just to open it. Leave it running with no agent and no index job and the machine stays quiet.
On a large already-indexed store, start no longer counts every node per repository and no longer rebuilds search indexes in the background while you sit still. That was the leftover CPU after Skip.
Closing Claude Code or another editor's memtrace mcp no longer leaves memcore-server listening on 127.0.0.1:50051. On Linux the sidecar dies with the parent, including a hard kill. The next spawn reaps a leftover for this store, and WSL can see that port with ss when lsof is missing.
memtrace mcp can join a running memtrace start even when the npm wrapper started several seconds before the real binary. That timestamp mismatch used to look like an unverifiable runtime and closed the MCP connection.
getcochangecontext no longer times out on repositories whose working-tree history is a dense in-tree build. It skips those wide save episodes, uses the files already on each episode, and does not scan the graph once per episode. A 30-second client deadline is enough again; other tools on the same daemon are not starved by abandoned co-change calls.
Checking out a feature branch keeps the original main graph and applies only that branch's delta. It does not copy the whole graph. Changed nodes are restamped on the feature; checking main back out returns the original.
Cortex no longer rereads every decision document on a timer while nothing changed. Saving an ADR or an agent-rule file is what wakes capture.
Cortex Governance no longer reports the daemon as down when a request fails. If Cortex is running, the page says so, including when the editor has more than one folder open.
Insights tabs that already have something to show now paint it instead of spinning while another tab rebuilds. Reconnecting the dashboard no longer forces every tab to start over.
The All repositories graph no longer sits empty for tens of seconds just because graph work is happening somewhere else. If that view was already built, it paints immediately.
The All repositories graph also paints the repository graphs that are already ready while another repository is still rebuilding.
Asking an editor what Memtrace has indexed no longer comes back empty when that editor started Memtrace from your home folder. It joins the one running memtrace start and lists those repositories.
You do not have to sit in the workspace folder. After memtrace start, an editor opened on one repository in that folder joins the same runtime and lists every repository.
A leftover editor helper that never connected, including one whose folder we cannot see, is closed when start comes up so the next agent call can attach.
Starting with a different workspace than the one already in .memdb no longer moves that database aside and rebuilds from empty. Memtrace keeps the existing graphs, adds newly listed repositories, and refuses when the requested set would drop or replace members. Pass --clear only if you mean to discard the store.
Indexing a workspace no longer leaves later repositories empty because another graph pass briefly held the store. Those indexes wait for the lock instead of failing.
A new repository in the workspace is indexed when you run memtrace start or when the editor's memtrace mcp owns the store. A terminal start asks first (default yes). Large stores still skip re-walking repositories that already have a graph.
After memtrace start, Memtrace does not re-read the whole database to fill dashboard graph pictures. A file save patches the picture you already have. Indexing a repository writes that picture from the graph just built. Indexed repositories with no changes stay idle.
Cortex Governance now lists the docs for the repository you have selected, even when the editor window has more than one folder open.
The memtrace start banner now shows the real logo spiral and a title-case Memtrace wordmark, not a block MEMTRACE stencil.
Nightly memtrace start no longer repeats Memtrace on the version line.
The in-app Nightly What's new list is this soak's notes, not an older handwritten snapshot.
Scrolling to zoom the GPU graph no longer fights the browser. The wheel zooms instead of scrolling the page.
Any editor that runs memtrace mcp — Cursor, Claude, Codex, VS Code, Zed, and the rest — joins memtrace start whether the editor or Memtrace came up first. A live helper stays alive and attaches; start does not kill it to force a respawn, because Claude Code does not respawn a dead stdio server. Only a leftover helper from an older build that never registered is closed.
Nightly Discord notes now list only what this soak changed. They no longer repeat the whole pending release every time a new nightly ships.
Improved
The service map draws the function that makes an HTTP or gRPC call, with the method and the file it lives in. gRPC is a different color from HTTP.
A new API route shows up on the API tab once the graph has the endpoint. A route nobody calls will not grow a topology arrow, because there is no caller to draw.
Changed
On Apple Silicon, embedding uses the Neural Engine by default. Set MEMTRACEDISABLECOREML=1 if you want CPU only.
An editor session connects instead of pegging the CPU
Fixed
Opening Memtrace from Cursor or Claude no longer grabs every fast core on the machine. Each chat used to start a full-speed copy of the indexer, so a few open sessions drove idle CPU into the nineties and then the editor gave up waiting for tools. Those sessions now stay small. If yours is already stuck, reload the Memtrace MCP server after upgrading.
A second editor session can join a Memtrace that is still starting, instead of dying with a closed connection and launching yet another copy. The first session used to keep its address unpublished until the database finished opening, which is slow, and every retry piled on.
A session that joined an already-running Memtrace no longer starts its own file watcher or background Cortex process. That second copy was competing for the same store, which is part of why idle CPU climbed and tools flapped.
Claude gets workflow shortcuts wherever Memtrace is installed
New
Claude Code now has four manual shortcuts into Memtrace's canonical workflows: onboard, preflight, recall, and impact. Each shortcut hands its arguments to the matching skill instead of carrying a second copy of the workflow that can drift out of date. They ship through both the Claude marketplace and the npm fallback installer, so the available commands no longer depend on whether Claude could clone the marketplace. Native Rail remains the one enforcement path; this release does not install a second shell hook.
A watched repository is actually watched, and a running index says where it is
Fixed
A repository watched by an editor session is now genuinely watched. Asking to watch a folder reported success and listed the path, but when Memtrace was serving an editor directly - rather than through a separate background service - no file save ever reached the graph. Saving a file produced nothing for as long as you waited, while asking for a re-index picked the same change up in seconds. Saves now reach the graph within seconds again in that mode.
A running index reports the stage it is actually in. Progress was sent to the dashboard but not to the record that tools and assistants poll, so a large index looked frozen on the very first step from start to finish while the work proceeded normally underneath. Anything waiting for that record to move now sees it move.
Clearing a repository while re-indexing it now says that its commit history has to be rebuilt. The clear removes that history along with everything else, but the result reported nothing outstanding, so the gap was invisible until a history query came back empty. Clearing is still not a safe refresh - remove the repository and index it again instead - and this at least stops the result from hiding it.
A stalled internal lock can no longer block every write for as long as Memtrace keeps running. One lock could wait forever with no error and no way to see what it was waiting for; if that happened, re-indexing and cleanup stayed blocked and deleted code kept appearing in search until the process was restarted. It now gives up after a bounded wait and reports what it could not take.
Connecting an editor session to an already-running Memtrace no longer refuses in one specific case where the running instance was healthy and had published everything correctly. This does not cover every report of that refusal - if yours persists, the message now names exactly what it looked for.
Search spans the workspace, and the graph updates at the cost of the change
New
Searching without naming a repository now searches every repository in your workspace. Previously a search needed to know which repository held the answer before it could give you one, so the most natural question - asking without knowing where the code lives - either refused outright or quietly searched a single repository and reported nothing. Results from every repository are now merged into one ranked list.
Typing a name you already know puts that symbol first. An exact identifier match used to arrive somewhere inside a list of merely similar-looking code, because scores coming from different repositories were combined without recognising an exact match for what it is.
The repository list tells you whether the graph is current with your saves, not just when the last full index ran. Those are different questions, and only the second one used to be answered.
Cleanup now repairs duplicate entries left behind when two installations disagreed about a symbol's identity. Those duplicates could not previously be removed by any means, and a save now also heals a file whose history the watcher had lost track of.
Two installations pointed at the same database now say so, and the second one no longer writes to it. Reading stays open to both; indexing, watching and replaying history are refused with both installations named, because two builds that disagree about identity are where duplicate entries came from in the first place. Set MEMTRACEALLOWFOREIGNINSTALLWRITES=1 to allow it deliberately.
Changed
Saving a file now updates the graph by the size of your change rather than the size of your repository. Every save used to rebuild the whole graph, so keeping the view current got slower as a project grew instead of staying proportional to what you edited. Open dashboards receive just the difference and apply it in place.
Fixed
A search running while the graph is still being built now returns the last good answer, marked as possibly out of date, instead of nothing at all. An empty result was indistinguishable from the code not existing.
A dashboard showing an empty canvas over a populated database now says the view is still being built rather than reporting the repository as unindexed, which read as data loss.
Leaving a dashboard open can no longer postpone the graph being published indefinitely. Each refresh used to restart the waiting period the publisher depends on.
Reading the graph no longer waits on graph work that the answer does not depend on.
Clearing a repository now also clears its embeddings from the search index, and deleting an entry takes its embeddings with it, so a search can no longer return content that has already been removed.
Improved
Working out what a change affects no longer slows down as a repository grows, and a search that times out leaves its groundwork in place so the next identical search is fast instead of paying the same cost again forever.
The daemon stops working when there is nothing to do, and stop finishes the job
Fixed
Running Memtrace in one project no longer stops the database serving another. Starting anything — a session, an index, an editor's background server — swept up every storage server on the machine whose launching process had exited, on the reasoning that such a server belongs to nobody. That reasoning is wrong on macOS and Linux: a daemon started in the normal way outlives its launcher and is adopted by the system, which is what a healthy one looks like for the rest of its life. So each new invocation killed the storage server of every other project's running session, and the session it belonged to lost its database until something restarted it. Found by running two projects side by side on one machine. A server is now only collected when the scope is unambiguous — stopping the project it belongs to, or reclaiming a port that is genuinely needed — and never as a side effect of starting something. No indexed data was at risk; the affected sessions lost their connection, not their graph.
A store that has been indexed more than once no longer sends the daemon into a permanent rewrite. Attaching a vector to a symbol records a new copy each time, while the search graph keeps one entry per symbol — so a repository indexed twice holds two stored vectors per symbol and was read as having lost half of them. The response to apparent loss was to write every vector again, which added another copy per symbol and made the next reading worse, so the conclusion confirmed itself on every pass. In the field this ran at roughly three cores of continuous writing with no reads for hours on end, with the store growing the whole time. Apparent loss of that kind is now repaired by refilling the graph from the vectors already stored, which writes nothing; only genuine damage found while recovering triggers a rewrite.
Re-indexing a repository no longer leaves a second live copy of every vector behind. Attaching a vector to a symbol recorded a new copy and nothing ever removed the one it replaced, so a repository indexed twice held two live copies per symbol — measured on this release as 960 stored vectors against 480 symbols. That surplus is what the check above was reading as loss. A symbol's vector is now replaced rather than added to, and the new copy is written before the old one is dropped, so an interruption leaves a redundant copy the next pass clears rather than risking the only copy of a vector. The record log is append-only, so this does not shrink a store on disk; it stops the live count from multiplying, which is what drove the repeated re-indexing that grew one reported store to 3.6 GB. Copies written by an earlier version are left in place and are harmless.
Saving a file in a repository with a large number of ignored paths no longer stalls the watcher. Before deciding what changed, the watcher asks git which paths are ignored, and it sent the whole list before reading any of the answer. Past roughly sixty-four kilobytes of paths both sides were waiting for the other, so the check never returned and file watching stopped for that repository until the daemon was restarted. The two directions are now handled independently, with a timeout, and a batch of six thousand paths completes in well under a second.
Stopping now also reaps helpers that are not themselves Memtrace programs. This was named as a known limitation in 1.0.8: a stuck helper the daemon had spawned — a git process, for example — kept both itself and the daemon alive, and both had to be killed by hand. Stop now walks the owner's entire process tree, deepest first, and escalates until it is gone. It also finds that owner by inspecting running processes rather than by reading a file the dead process took with it, so an ownerless daemon is no longer invisible to it. Sessions belonging to other editors and agents are still left alone.
Blast radius on a symbol with very high fan-out now returns instead of running past any deadline. This was the other known limitation in 1.0.8: the walk read one symbol's edges to completion even once the answer was already capped. It now works to a time budget and returns what it found, marked incomplete, rather than not returning. MEMTRACEIMPACTWALKBUDGETMS raises or lowers the budget from its fifteen-second default.
The decision-memory handoff file no longer grows without bound. Captured sessions are appended to it and the background service records how far it has read, but nothing ever reclaimed the part already read — reported in the field at 2.53 GB with the service continuously working through it. The consumed portion is now dropped at startup, at the one moment no service is reading the file, and the unread remainder is preserved exactly.
Two Memtrace installations driving one store now say so. A globally installed copy and one built from source can be pointed at the same database, and the newer of the two writing under the older's assumptions is difficult to spot from the outside. Startup now records which installation claimed the store and warns when a different one attaches. An installation it cannot identify is never reported as a conflict.
Every session opens the same graph, and stop leaves nothing behind
Fixed
A shared workspace graph is now opened by every session inside it, not only by one started at the workspace folder itself. Marking a folder as a workspace is meant to give the repositories inside it one shared index, but a session started with no flags ignored that marking unless its working directory was the workspace folder. Started from a repository inside the workspace it opened a private database instead, so searches answered from a store holding a few unrelated repositories with your own repository simply absent, and one such store appeared per running editor or agent session.
Sessions started inside a git worktree no longer get their own private, near-empty graph. A linked worktree looked like a separate repository to the check that decides which database to open, so a session started inside one created and bound a worktree-local database. Nothing reported an error, and indexing wrote a full graph into the stray copy. Worktrees now open the graph of the repository they belong to.
A store that is being skipped is now named at startup. The two fixes above change which graph an existing session opens, and from the outside that looks identical to the problem they fix: the index appearing to vanish. Startup now lists the database it opened alongside any it stepped over, and states plainly that nothing was deleted. Leftover copies stay on disk untouched, and MEMTRACEMEMDBDATADIR pins a specific one.
Stopping Memtrace no longer leaves part of it running. It reported success while the supervising process kept consuming a core and a background service held nearly two gigabytes, both of which had to be killed by hand. The stop signal was sent once and never escalated, services were located through a file the dead process had taken with it, and a session that ended took nothing with it. Stopping now escalates until the process is actually gone and collects whatever is left ownerless, while sessions belonging to other editors and agents are still left alone.
Only one decision-memory service runs per machine again. Each session reaped every other session's service before starting its own, so two agents working in different repositories killed each other's and the supervisors restarted them in a loop, with several running at once against a store meant to have a single owner. Ownership is now decided once per machine, and a session that does not own it waits to take over rather than competing.
Blast radius answers in about a second instead of timing out. Impact, callers and references walked the graph one symbol at a time, and each step asked a question the database answers by reading every record it holds, so a two-hop query on a real repository never returned. They now ask once per step for the whole frontier, through the index.
The dashboard no longer starves the database it is reporting on. Health counted repositories in a way that reads and decodes every record in the store, and the dashboard polls health continuously, so every poll piled another full scan on the ones still running. The database saturated every core with no forward progress, and the abandoned requests tore down the connection that the indexer was using to write a repository's relationships. Health now computes at most one answer at a time and serves the last good one rather than starting more work.
A repository whose relationship write failed no longer reports every symbol as safe to change. Its symbols still resolved, so blast radius came back as no impact and low risk, which is indistinguishable from a genuine answer. An incomplete graph now reports unknown risk and marks the result incomplete.
An index that writes symbols but no relationships now says so. It reported completion with a symbol count and no relationships, which reads as success, and a repository in that state cannot answer a single impact, caller or reference question. Completion now carries an explicit warning naming what is missing and what to do about it.
Indexing reports progress through the database write. The bar stopped at 85 percent for the whole write stage, the longest one on a large repository, with no output at all, which was twice mistaken for a hang.
Changed
Blast radius may now run alongside background index maintenance. It previously waited for exclusive access, which is why a single background repair could make every impact question hang no matter which symbol was asked about. It now waits briefly and then proceeds, which is safe because the same release made that walk read a capped number of symbols in fixed-size pages.
Stopping always terminates. Memtrace stop used to report failure and leave the process family running if the supervising process did not answer in time. It now escalates to a forced stop after a grace period, so anything scripted around the old failure exit should be re-checked.
Cold starts stay inside their workspace and large graphs use less memory
New
A portable workspace manifest can now name repositories that live in different folders. Run Memtrace with an explicit workspace file when several repositories belong together; relative paths travel with the manifest, while duplicate and unsupported entries are rejected before anything starts.
Changed
Running memtrace start without a workspace now means a true cold start of exactly the repository or folder where it was invoked. Parent-folder markers, editor workspace files and another running Memtrace process no longer enlarge that scope implicitly.
Fixed
Repositories left in an older shared database no longer become members of the active workspace's main graph, repository list, watches or live insight scans. Workspace membership comes from the repositories discovered for this start, not from every repository record that happens to exist on disk.
Opening the dashboard on a very large graph no longer launches several full-graph analyses at the same time. Expensive graph and insight materializations now share one gate, while repository statistics load record payloads in bounded pages, substantially reducing peak physical memory.
Concurrent workspaces no longer adopt the same sidecar port or overwrite one another's runtime ownership. Start, stop, clear and reset operations are scoped to the selected store, confirm the owner and retain the store lock throughout cleanup.
A legacy or mismatched local database is no longer opened and trusted. Start and index move its payload into a recoverable sibling quarantine by same-filesystem rename, then rebuild a clean database for the exact workspace; standalone MCP and replay fail closed until that cold rebuild can be performed.
Health, Quality and Architecture stay current while agents or editors change the graph. Every successful or partial mutation invalidates the affected repository, stale values remain visibly marked while one serialized recomputation runs, and a durable five-second check catches changes written by another process.
Clear and reset refuse filesystem roots, home directories, project roots, symlink redirections and unrecognizable data directories. On Unix the recursive clear is pinned to the validated directory handle; platforms without that guarantee now refuse the operation instead of risking the wrong directory.
Test coverage measures maintained code, not frozen copies
Fixed
The Test tab now excludes immutable evidence copies from its coverage denominator. Frozen bot snapshots, materialized opponent zoos and saved policy candidates stay indexed and searchable, but they no longer count as separate code that needs a duplicate test suite. A repository whose maintained source was well covered could previously report roughly three percent simply because it kept thousands of those copies.
Insight panels tell the truth about every language
Fixed
Dead code is measured correctly in Java, C#, Go and every other supported language. Whether a function is part of a project's public surface was only ever worked out for Rust and JavaScript; everywhere else nothing counted as public, so anything not reachable from a web route was reported as dead. On a fully tested codebase that was a third of all functions. Visibility is now modelled per language, including Go's capitalisation rule, Kotlin and Swift defaults, leading-underscore conventions in Python, Dart and GDScript, Ruby's private sections, Elixir's private definitions, and static linkage in C and C++.
Improvements to how code is read now reach projects that were indexed by an older build. Re-indexing skipped any symbol whose source text had not changed, and the comparison carried nothing about how that text had been interpreted — so a smarter reading of the same file could never take effect. Upgrading now refreshes exactly the records the change affects, without re-computing embeddings.
The dependency and coupling view works for projects that import by package or namespace rather than by file path. Java, C#, Kotlin, Go, Python, Ruby, PHP, Swift, Dart, Elixir, Lua and C++ imports now resolve to the files they name, so a panel that reported no resolved imports at all now measures real architecture.
Cross-repository connections appear without restarting. The picture the interface reads was rebuilt before those connections were worked out, and the rebuild was skipped whenever a re-index produced no brand-new links — which is the normal case for a repository that was already connected. Indexing now settles first and the picture is always rebuilt afterwards.
Panels no longer show numbers from a graph that has moved on. Freshness was inferred from a derived file rather than announced when the graph changed, so on any branch other than the main one the panels could freeze indefinitely. Separately, repositories with no such file all shared a single cache key and could show each other's results.
Duplicate findings are actually duplicates. Comparison ignored names and text values, so two functions with the same shape were reported as copies of each other — a web controller matched a small network client, and two clients that differed only in the address they call were treated as identical. Findings on one service went from thirty-six to none, with genuinely unreachable code unaffected.
The dead-code grade takes its own confidence into account. Findings the analysis itself marked as uncertain still drove the score to the worst possible grade. Uncertainty means reflection or dynamic behaviour could not be ruled out; that now limits how far the score can fall, while findings that are certain still count in full.
An empty hotspot list explains itself instead of showing nothing. The view now reports how many functions were examined, how many changed recently, and how they compare with the threshold, so a quiet codebase is distinguishable from a broken one.
A single-project .NET service now produces architecture insight. Components were derived only from project files, so the ordinary shape of a .NET service had exactly one component and nothing to compare.
A repository containing several services now appears in the service map. Everything was grouped by repository, so services living together were treated as one box and every call between them was hidden as internal traffic.
The service map no longer scatters across an empty canvas. Services that call each other in both directions — the normal case — were laid out as if the loop had to be followed, spreading five services across twenty-four columns and pushing the diagram off screen with no way to bring it back. The view now fits itself on load, on resize, and whenever the selection changes.
Changed
There is now one high-performance graph renderer instead of two. Choosing Auto quietly selected an older renderer, so the three options in the menu produced three different-looking graphs. Auto and the high-performance option are now the same renderer, with the compatibility renderer as the automatic fallback.
Calls that cross a repository boundary stand out in the graph. They were drawn in the colour of whatever they came from and faded with distance — and those calls are long by nature, so the rarest and most valuable connections were the hardest to see. They are now drawn in red at a constant thickness.
Windows only, and worth knowing before you upgrade: the one-time re-index rebuilds the semantic search index in memory, and on Windows it is not always written to disk before Memtrace exits. Search is correct for that session; on the NEXT start the semantic half can go quiet and results fall back to keyword matching. Run an explicit re-index to restore it. The condition is now reported in the log instead of being silent, and a fix is coming in the next release. macOS and Linux are unaffected.
Ship with memory
Your next release deserves this paper trail.
Memtrace remembers what changed, why, and what it broke — for your agents and for you.