Desktop 0.1.5: the tools stopped answering small questions with the whole graph
An assistant pays for every byte a tool hands back. Meronq's handshake was built with that in mind — it sends a vitality-focused slice, not the whole Canonical Engineering Model. The rest of the tool surface was not, and nobody had measured it.
We measured it. memory_sync on a real Unity project returned 84,484 bytes — the entire CEM plus the entire project scan — to answer "did the sync work". project_list returned 46,190 bytes, because the local registry had accumulated 240 projects and 227 of them pointed at temp directories that no longer existed.
0.1.5 is about that number.
Sync tools answer with a summary
memory_sync, project_scan and github_sync share one code path. It now returns counts, what the sync changed, warnings, and a hint — the graph only when you ask with detail="full".
| before | after | ||
|---|---|---|---|
memory_sync (Unity project) |
85,061 B | 3,528 B | −95.9% |
memory_sync (this monorepo) |
137,358 B | 1,521 B | −98.9% |
project_list |
46,190 B | 2,377 B | −94.9% |
handshake (brief) |
21,956 B | 19,254 B | −12.3% |
Roughly 21,000 tokens down to 880 on the first row. Nothing is lost: the graph is in SQLite either way, memory_search reaches it, and the full payload is one argument away.
The handshake improvement is a side effect worth naming: it was sending the ADR list twice, once at the top level and once inside the project index. Extracting a shared slim-index helper removed the copy.
A ceiling, with an escape hatch
Every tool result now passes a 32,000-byte limit. An oversized object comes back as a notice carrying its actual size and a hint — not a truncated JSON fragment, because half a JSON object is not JSON and an agent cannot parse it. An oversized string keeps its head, which is usually the useful part of a log.
A caller who explicitly passes detail="full" raises the ceiling instead of being overruled. The limit exists to stop tools dumping by default, not to argue with someone who asked for everything.
project_list stopped shipping dead rows
It lists what exists on disk, counts the rest, and names project_unregister. The cause of the pile-up turned out to be our own test suite: project init registered into the real ~/.meronq/projects.json whenever no session was passed, so every full test run left rows behind. It takes an isolated registry home now.
Assistant cards
- The Desktop shell version is visible in the header, in the connect summary, and on the sidecar's
/health. - Agent-mode MCP clients announce themselves as
local-agent-mode-<server>— no "claude" anywhere in the name — so their tool calls were landing on "Any other MCP client". They now attribute to Claude Code, and the raw client name is in the version tooltip so a wrong mapping is visible rather than silent. - The client version shown is the latest one reported. Events written inside the same millisecond used to leave a stale version in place, depending on database scan order.
Getting it
- Windows: installer. Existing installs update in place.
- macOS: Apple silicon · Intel. These are downloads only — the macOS builds ship without updater signatures, so in-app updates do not apply to them yet.
What did not ship
Embedding-based selection. The bundled multilingual-e5-small can rank and cluster, and an MMR pass over the stored vectors already produces a more representative slice than the current one — seven entity types instead of three in a twenty-item budget. It is not enabled, because what goes into those vectors is still name + summary + type + layer, and component summaries are formulaic enough that the model reads the template rather than the meaning. Clustering at cosine 0.95 happily merged 64 distinct Unity modules into one group. Fixing what gets embedded comes first.
Also still open in this sprint: access rows written outside the MCP dispatcher — the handshake's own presence row and every Desktop sidecar call — carry no response size. That is why 970 handshake rows in this repository hold 11 sizes.