Skip to content

Scope agent memory/climate to project so one agent can work across groups without context bleed #45

Description

@kejiali

Summary

When the same agent participates in multiple groups (projects), its memory,
climate, and persona are keyed only to agent_id — they are global across all
conversations. Only the raw message thread is scoped per conversation (via
conversation_reads). The result: an agent working in group B "remembers" and
acts on the context from group A, mixing its group A work into group B.

This makes running several independent projects with the same agent set
impractical. Today you either accept the bleed, manually wipe memory files, or
spin up a separate agent per project (N projects → N agents) even when the
underlying LLMs are identical.

Concrete symptom (BYOA)

Agent nova sits in multiple project groups. Its memory index
(~/.cumora/agents/<id>/memory/MEMORY.md) ends up indexing five unrelated
projects (paper review, article review, PPT repo, OpenRouter plan, …). In a new
group about one project, nova reads all five and treats the others as
background — exactly the "agent1 in group2 treats its group1 work as
background" symptom.

Root cause

  • agent_memory / agent_workspace (memory) are keyed by agent_id only
    (server/src/db/migrate.ts).
  • Retrieval in server/src/agents/runtime/inproc-client.ts (loadMemory)
    filters only agent_id + path LIKE 'memory/%' — no project/conversation
    dimension.
  • Climate (loadClimate) is likewise per-agent and global.
  • projects + conversations.project_id exist, and the wake prompt already
    surfaces "Project: " to the agent — but that is a label, not an
    isolation boundary.
  • The plumbing to fix this already exists: agent_memory.source stores
    conversationId, and conversations.project_id links a conversation to a
    project — it is just not used to filter memory.

Why the current workarounds are painful

  1. Manual wipe (documented in COORDINATION.md under "memory pollution"):
    read each memory file, delete the overfit ones, re-wipe every time pollution
    re-accumulates.
  2. One agent per project: for N projects you maintain N agents (and their
    homes) even though you may only have 2 underlying LLMs — defeating the point
    of a reusable agent identity.

Proposed fix

Add a scope dimension to memory and filter retrieval on the current
conversation's project (fall back to global when a conversation has no project):

  1. Add nullable project_id to agent_memory / agent_workspace, or derive it
    from source.conversationId → conversations.project_id.
  2. In loadMemory, join the current conversation(s) to their project and
    include global memories + the current project's memories, excluding other
    projects'.
  3. Optionally scope climate the same way (or keep it global and document the
    tradeoff).
  4. For BYOA, scope the injected MEMORY.md digest / memory-directory read to
    the current conversation's project.

Related

I did not find an existing issue or discussion covering cross-group context
isolation or per-project memory scoping. This is distinct from the documented
agent↔agent isolation (separate home dirs), which works fine — the gap is
within a single agent across groups.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions