Build1 publisher3 min readPublished Updated
The server injects up to five project notes before the agent takes its first turn
A developer running nine parallel Claude Code sessions moved project-memory recall out of the opening prompt and into server-side search that runs before the model's first turn, keeping the old instruction as the empty-result fallback.
The Engineer · Build desk

What happened
- The server now runs the semantic search when a session spawns, before the model gets a single turn, and injects the hits directly into the session's first message.
- On a fresh project with empty memory, or when the embedding backend is down, the injected block is empty and the prompt reverts to asking the model to search for itself.
- An end-to-end test seeds two notes with a staging port of 6443, a deploy host called callisto and a make ship-v2 command, against a workspace README deliberately wrong about all three.
Compiled by The EngineerSomething wrong?How this is made
Why it matters
- constraint Retrieval precision now sets what the agent believes it knows, and the shipped code passes no relevance score to the model, so a weak match arrives formatted exactly like the note that mattered.
- cost Recall stops being an occasional tool call and becomes a charge on every session start, paid in first-message tokens by whoever runs the cockpit.
- decision Anyone maintaining a memory tool for coding agents now has a worked alternative to weigh: leave recall as a call the model may skip, or own it in the message the server assembles.
`_memory_preseed(query, top_k=5)` calls `memory_search` on the server, then formats each hit as a line carrying the note name, its description and a snippet, with a star prefixed when the note has `priority` set [10]. The model sees list order and the star; the code shown does not pass relevance scores through. If the hit list comes back empty the function returns an empty string [10].
The design came out of a compliance failure. A session reimplemented an error format the team had standardised weeks earlier, because nothing told it the decision existed, and the decision was written down in a markdown note the session never opened [3]. The first fix told each session to "Start by calling the memory_search tool to load any relevant project context" [4]. "And it mostly works. Mostly," the author wrote on dev.to [5]. Stronger wording, moving the instruction last, and tool descriptions that begged came next [7], and then the conclusion: "I was trying to make a non-deterministic thing reliable by asking harder. Wrong layer." [8] The post does not report how often a session actually skipped the call, so the one-in-nine framing is an argument about odds rather than a measurement, and the author's stated concern is that a skipped read is silent [6][21].
The release ships an end-to-end test that seeds a throwaway instance with two notes whose facts appear nowhere in the code, against a workspace README deliberately wrong about all three [15]. The spawned session is asked "what port does staging run on, which host do we deploy to, and with what command?", and passing means answering 6443, callisto and `make ship-v2` [16]. The transcript records the session saying it answered "without needing to search the codebase" [17]. A session under the old instruction that did call `memory_search` would answer the same three values. So the test verifies that server-side recall reaches the model, and comparing the two designs would mean spawning the same task both ways and counting the misses.
`top_k` defaults to 5 and the cockpit keeps about nine sessions alive [10][1], so a full round of spawns puts up to 45 note lines into first messages [20]. Each line is a note name, a description and a snippet [10]. Whether that is cheap in your setup depends on how long your descriptions run and whether the injected block sits inside a prefix your provider caches.
The store is the part I would copy. Notes are markdown with YAML frontmatter, the same files Claude Code already writes, one fact per file, with the `description:` doubling as the embedding text and an optional `priority: high` [18]. The index is incremental sqlite with the vectors in the same store, no pgvector and no ANN library, and the author reports that dot-product over a warm in-process model is instant at a few hundred notes [19]. For that to transfer you need the same conditions: a few hundred notes, one process, and the embedding model resident in it.
The convention is one fact per file [18]. The example injected block shows `[staging-stack]` carrying the staging port and the deploy host on a single line [11]. Because the description is the embedding text, a note holding two facts is only retrieved by whichever one the description mentions.
What to watch
- A published compliance count: the same task spawned with and without injection, misses tallied.
- A relevance threshold in _memory_preseed, so weak top-5 hits fall back instead of being injected.
- What replaces the sqlite dot-product scan once a project runs past a few hundred notes.