Repository navigation
feat: the client declares its author in the X-Author header and notes read by default in the author's own scope - #379
Conversation
The Hermes client takes its author and sends the X-Author header beside X-API-Key; its prefetch renders a hit's author only when it differs from the reader's own. The Claude Code context block takes the reader's author for the same rule, the hooks' requests carry the header, and .mcp.json forwards it from the plugin option.
The Hermes client takes its author and sends X-Author beside X-API-Key on every request; a prefetch hit line names its author only when another agent wrote it. The provider passes the configured author to the client. The Claude Code plugin sends X-Author on every hook request and on the MCP server connection, and its context block marks foreign authors the same way.
… notes ADR-0015 records the decision and ADR-0014's Status links the superseded sentence. The consolidation procedure consolidates per persona: the env file carries MEMORY_AUTHOR, groups take the author parameter, and the write bodies carry no author. The configuration doc adds MEMORY_AUTHOR beside MEMORY_API_KEY. CONTEXT.md defines Author and Shared. The REST and tool references, the data flow, both integration READMEs, and the connect-agent skill describe the header, the shared flag, the scoped reads, and the foreign-author rendering.
An author-less profile would send an empty X-Author header and be refused on every call; is_available now requires the author beside the URL and the key.
Consolidation groups default to exactly the header author's notes and params echo the resolved author; a slug search drops author-less documents and cards; a mixed-author verdict is rejected per verdict; duplicates take the three-way author; archive discovery replaces the default scope with a slug or all; the author-less-note sentence moves to ADR-0015.
…idation pair query
…nd bump the plugin to 0.2.0
Runtime evidence — branch deploy on the operator's host (2026-10-19, HEAD 6fb5c1f)Deploy:
Raw output: Deviation from the issue's last acceptance criterion: the two clients were REST calls with different |
Summary
Several agents share one memory store, each with its own persona. Until now the model filled the
authoron every write and every client searched every note with no author shown, so one persona received another's notes as its own memory (live repro on 2026-10-19 in theperlicaprofile).The author now comes from one request header,
X-Author, set once in each client's configuration. The server requires it on every keyed route, attributes every write to it, and returns by default only the header author's notes plus notes saved withshared: true. Theauthorfilter of the read tools and routes is three-way: omitted,"all", or a slug. Note ids hash author and content. Consolidation runs per persona: groups are built among one author's notes, a merged note keeps the members' author, and the action rows carry the header author. Theconsolidatorkey and author are gone. The Hermes provider and the Claude Code plugin send the header from theirauthorsetting and show an author on a prefetch line only when it is another agent's. ADR-0015 records the decision.Design: issue #378 (settled with the owner). Spec reviewed three times by gpt-6.1-sol; implementation reviewed on two axes by Opus, with every finding fixed.
Related issues
Closes #378. Supersedes #282 (closed).
Runtime evidence (required for ingest / retrieval / serving behavior)
Branch deploy verified on the operator's host: two REST clients with different
X-Authorvalues; a private note of one is absent from the other's default/search, ashared: truenote appears in both, a request without the header or withallgets 400, a bodyauthorgets 400, and the groups route echoes the header author. Full table and raw output in the evidence comment.Verification
uv run pytestpasses: 1741 unit tests; the integration suite against a throwaway Postgres and the live embedder passes excepttests/serve/test_turns_integration.py::test_concurrent_appends_to_one_session_get_distinct_seqs, which fails intermittently in full runs (Lock is bound to a different event loop, the module-level pool lock incore/db.pyreused acrossasyncio.runloops) and passes alone every time; pre-existing and unrelateduv run ruff format --check .anduv run ruff check .passdocker compose build mcppasses (the branch deploy rebuilt api and mcp)Checklist (core principles)
doc_rowsand theturnslane.envtests/serve/test_author_scope_integration.py,tests/serve/test_note_scope.py, consolidation, Hermes and Claude Code hook tests)Operator steps after merge (outside the PR)
X-Authornext toX-API-Keyin themcp_serversheaders of thenatsume2andperlicaHermes profiles; the provider'sauthorsetting is now required.memory-base@memory_layer, now 0.2.0) so its hooks and.mcp.jsonsend the header; remove the hand-patched hook copy.MEMORY_AUTHOR=<slug>in the consolidation env file; retire theconsolidatorkey; register a run forclaude-codenotes.