Only memory comes from the server's /mcp; notes, knowledge and skills stay local

Harness spec 3.0.0 (acp.md *Memory*): memory records are the server's for the
device as for a chat; everything else in the library is the device's own.

- `library: lembas` (the default when the login's token has the `memory`
  scope, or the older `library`) adds the server's /mcp with its `memory`
  tool alone, in place of this machine's memory tool; notes_*, knowledge_*
  and skill_* are always this machine's. No prompts, resources or
  instructions are taken from it.
- The memory in the prompt is the server's: the resource lembas://memory,
  read as a session starts (McpManager.readResource) and kept for it — put in
  while nothing has been sent, so the prompt never changes under a session.
- A session the client opened (session/new, or opened from the store) sends
  its id as `_meta.lembas.scope` on every memory call and on the resource
  read (App.setScope); a session of the device's own sends none.
- An instance's `library` context (its knowledge bases) is no longer read:
  the knowledge block names this machine's bases only.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
HomerandClaude Opus 5.5 committed 2026-10-27 21:07:37 +00:00
1 parent 6d5a25cdad
commit a73adc01f0
10 files changed
+134 -93

No files matched your search

+5 -8
View File
@@ -209,14 +209,8 @@ export function contextOf(meta: any): SessionContext | undefined {
if (m.personalization === null) out.personalization = null
else if (m.personalization && typeof m.personalization === "object")
out.personalization = { personality: str(m.personalization.personality), personality_custom: str(m.personalization.personality_custom), instructions: str(m.personalization.instructions) }
if (m.library && typeof m.library === "object")
out.library = {
bases: (Array.isArray(m.library.bases) ? (m.library.bases as unknown[]) : [])
.filter((b): b is { id: unknown; name: unknown } => !!b && typeof b === "object")
.map((b) => ({ id: str(b.id), name: str(b.name) }))
.filter((b) => b.id || b.name)
.map((b) => ({ id: b.id || b.name, name: b.name || b.id })),
}
// `library` (an instance's knowledge bases, 1.1.0) is not read: the CLI's knowledge bases are its
// own (spec 3.0.0), and a 3.0.0 instance sends none.
if (m.prototypes && typeof m.prototypes === "object") out.prototypes = { offered: m.prototypes.offered === true, sources: str(m.prototypes.sources) }
return Object.keys(out).length ? out : undefined
}
@@ -595,6 +589,8 @@ export class AcpAgent {
session.id = id
session.turns = turnLog(id)
markRemote(session.app.store, id)
// The client's chat: its memory calls land in that chat's data group (acp.md *Memory*).
session.app.setScope(id)
this.takeContext(session, p)
this.sessions.set(id, session)
this.adopt(session)
@@ -668,6 +664,7 @@ export class AcpAgent {
session.app = createApp({ cwd: dir, ...(L ? { mode: L.maxMode } : {}), asker: this.asker(session), modelTitles: false, resuming: id })
session.app.resume(id)
markRemote(session.app.store, id)
session.app.setScope(id)
if (L) session.app.engine.mode = clampMode(session.app.engine.mode, L.maxMode)
this.sessions.set(id, session)
this.adopt(session)