Summary
In a project linked to a workspace, a plain "remember this for the team" request is not persisted where other linked checkouts can read it. Two memory stores compete, and the one the model reaches for by default is the wrong one:
- Altimate Memory blocks (
altimate_memory_write / altimate_memory_read): local Markdown blocks, mirrored to the workspace by memory-sync, loaded into every linked checkout's overlay with an origin label. This is the store the workspace feature is built on.
- The engine's memory hub (
datamate_add_memories / datamate_search_memory, served by the datamate MCP server): a separate SaaS store with asynchronous extraction. Memories saved there did not show up in GET /datamates/memory/list minutes later, and datamate_search_memory in another checkout did not find them either.
The engine's always-active "Datamate MCP Workflow" instructions tell the model to "call add_memories to persist significant decisions", while the description of altimate_memory_write never says it is the team-shared, workspace-synced store. So on a natural prompt the model uses (2), and the decision is invisible to the rest of the team.
Reproduction (v0.12.0, ALTIMATE_WORKSPACE=1, engine 0.7.1, two repos bound to the same workspace)
Repo A, TUI:
Record this team decision: event tables use an append-only incremental strategy with a monthly full refresh, because source rows are never updated, only appended. Save it to memory so the whole team sees it.
Observed: the model calls datamate_add_memories only. No block appears under .altimate-code/memory/, nothing is added to altimate-workspace-memory-index.json, and the workspace memory list stays unchanged.
Repo B (different git remote, same workspace), TUI:
I'm about to build an incremental model for click events here. What strategy did the team decide on for event tables, why, and where does that decision come from?
Observed: the model searches thoroughly on its own (datamate_search_memory, altimate_memory_refresh, altimate_memory_read scope=all, grep, git log) and answers "I don't see a team-specific ADR or memory for event tables in this repo/workspace". It does see an older block from repo A that had been written with altimate_memory_write, which shows the mirror and the cross-project overlay work.
Control: the same flow with the prompt changed to name altimate_memory_write (scope project, id decisions/event-tables-incremental) works end to end: the block is mirrored (index gains the record), and repo B answers "append-only … Recorded by: workspace project orders-analytics, memory block decisions/event-tables-incremental". End users will not write that prompt.
Recordings and the exact tapes are in demos/workspace-pilot/ (e2-decisions-travel.tape) on the workspace_learning worktree.
Second, smaller defect in the same path
MemoryStore.write mirrors with void mirrorBlock(...) (packages/opencode/src/memory/store.ts:321), fire-and-forget. A session that saves a block and exits a few seconds later can lose the upload; /workspace → Sync is then required. For a bound workspace the mirror should either be awaited (it is one request) or flushed before the process exits.
Suggested fix
- When the project is bound and workspace memory is enabled, tell the model which store is the team's: append a line to the workspace section of the system prompt (
awareness.ts already renders ## Workspace), e.g. "Team memory: save decisions and conventions with altimate_memory_write; they sync to the workspace and to every linked checkout. The datamate_* memory tools are the engine's separate store." Alternatively make the altimate_memory_write description say this when bound.
- Await or flush
mirrorBlock when bound.
- Consider whether the engine's memory hub should be hidden or de-prioritised when the workspace memory feature is on, since two stores with the same "remember" semantics will keep diverging.
Summary
In a project linked to a workspace, a plain "remember this for the team" request is not persisted where other linked checkouts can read it. Two memory stores compete, and the one the model reaches for by default is the wrong one:
altimate_memory_write/altimate_memory_read): local Markdown blocks, mirrored to the workspace bymemory-sync, loaded into every linked checkout's overlay with an origin label. This is the store the workspace feature is built on.datamate_add_memories/datamate_search_memory, served by thedatamateMCP server): a separate SaaS store with asynchronous extraction. Memories saved there did not show up inGET /datamates/memory/listminutes later, anddatamate_search_memoryin another checkout did not find them either.The engine's always-active "Datamate MCP Workflow" instructions tell the model to "call
add_memoriesto persist significant decisions", while the description ofaltimate_memory_writenever says it is the team-shared, workspace-synced store. So on a natural prompt the model uses (2), and the decision is invisible to the rest of the team.Reproduction (v0.12.0,
ALTIMATE_WORKSPACE=1, engine 0.7.1, two repos bound to the same workspace)Repo A, TUI:
Observed: the model calls
datamate_add_memoriesonly. No block appears under.altimate-code/memory/, nothing is added toaltimate-workspace-memory-index.json, and the workspace memory list stays unchanged.Repo B (different git remote, same workspace), TUI:
Observed: the model searches thoroughly on its own (
datamate_search_memory,altimate_memory_refresh,altimate_memory_read scope=all, grep, git log) and answers "I don't see a team-specific ADR or memory for event tables in this repo/workspace". It does see an older block from repo A that had been written withaltimate_memory_write, which shows the mirror and the cross-project overlay work.Control: the same flow with the prompt changed to name
altimate_memory_write(scope project, iddecisions/event-tables-incremental) works end to end: the block is mirrored (index gains the record), and repo B answers "append-only … Recorded by: workspace project orders-analytics, memory block decisions/event-tables-incremental". End users will not write that prompt.Recordings and the exact tapes are in
demos/workspace-pilot/(e2-decisions-travel.tape) on theworkspace_learningworktree.Second, smaller defect in the same path
MemoryStore.writemirrors withvoid mirrorBlock(...)(packages/opencode/src/memory/store.ts:321), fire-and-forget. A session that saves a block and exits a few seconds later can lose the upload;/workspace→ Sync is then required. For a bound workspace the mirror should either be awaited (it is one request) or flushed before the process exits.Suggested fix
awareness.tsalready renders## Workspace), e.g. "Team memory: save decisions and conventions withaltimate_memory_write; they sync to the workspace and to every linked checkout. Thedatamate_*memory tools are the engine's separate store." Alternatively make thealtimate_memory_writedescription say this when bound.mirrorBlockwhen bound.