The Namespace Model
Every memory in Gnosis lives in exactly one namespace. Namespaces are the unit of isolation, access control, and search scoping. There are three kinds.
Personal Namespace
Your default. Keyed by your user ID, private to you. When you call memory_search, your personal namespace is always included. This is where the vast majority of your memories live — preferences, decisions, facts, tasks, file paths.
To write here explicitly, pass collection: "me" on any write tool. If your MCP server has a default collection configured, omitting the collection parameter writes to that default — "me" is the only way to force-write to personal in that case.
No one else can see your personal namespace unless you explicitly grant access (via agent owner_access or by publishing memories to a collection).
Collection Namespace
A shared bucket identified internally as col:{slug}. When you write a memory with collection: "Team Notes", it's stored in the collection's namespace, not yours. Collections come in two types:
- Collaborative — every member can read and write. Use this for teams working on shared context: project decisions, architectural notes, onboarding knowledge.
- Knowledge pack — only the owner writes; everyone else reads. Use this for curated reference material: style guides, runbooks, API documentation. The owner controls what goes in. Members benefit from search inclusion without the noise of unreviewed contributions.
Within a collection, members are assigned one of two roles: member (read + write) or reader (read only). The collection creator is automatically an admin with full control over membership.
Agent Namespace
Each agent identity gets its own isolated namespace. An agent named research-bot stores and retrieves memories in a namespace completely separate from your personal one. Two agents under the same account cannot see each other's memories unless they share a collection.
This isolation is the point. A code review bot accumulates different context than a research assistant. Mixing them would degrade search quality for both. Separate namespaces keep each agent's memory corpus focused.
Search Fan-Out
When your AI calls memory_search or memory_deep_search, the query automatically fans out across your personal namespace and every collection you belong to. There is no parameter to enable this, no configuration to set. It happens on every search.
Automatic, Transparent, Deduplicated
The server resolves your collection memberships, builds a list of accessible namespaces ([user_id, col:team-notes, col:api-docs, ...]), and runs the query across all of them in a single database operation. Results are merged, ranked, and returned as a unified list. Your AI doesn't know or care which namespace a result came from.
This creates a deduplication challenge. When you publish a personal memory to a collection, the same content now exists in two namespaces with identical embeddings. The database returns both copies at the same distance, and both consume result slots — displacing unique candidates that should have ranked.
Gnosis handles this with an over-fetch and dedup strategy. When collections are present, the database fetches up to 2x the normal candidate pool. After retrieval, results are deduplicated by content hash — the first copy survives, duplicates are dropped. The pool is then truncated back to the original target size before ranking. The result: collection users see the same retrieval quality as users with no collections.
The 2x factor is a practical ceiling, not a per-collection multiplier. A user in 50 collections doesn't trigger a 50x fetch. Duplicates only exist in collections where memories were published (copied), not in collections where different people wrote different things. In practice, most users publish to 1–3 collections.
Collection-Scoped Search
Fan-out is the default, but you can narrow scope. Pass collection_filter: "personal" to search only your namespace. Pass collection_filter: "team-notes" to search only that collection. The same scoping applies to task_feed, memory_retrieve, and memory_delete — every read operation respects the same namespace model.
Collection Operations
The collection_manage tool exposes nine actions. Here's the practical flow from creation to daily use.
Create and Invite
Call collection_manage(action: "create", name: "API Docs", type: "knowledge_pack"). You're now the admin. Add members by email: collection_manage(action: "add_user", name: "API Docs", user: "dev@company.com", role: "reader"). The invitee sees a pending invitation on their next init_core_memories call and can accept or decline.
Until the invitee accepts, they have no access. There is no way to force-add someone — membership requires explicit acceptance.
Write to a Collection
Once a collection exists and you're a member (or admin), write to it by passing the collection name in any add call: memory_add(content: "...", collection: "API Docs"). The memory is stored in the collection namespace, not your personal one. It's immediately searchable by all members.
For a persistent default, set the X-Default-Collection header in your MCP server configuration. Every memory_add call without an explicit collection parameter will write there instead of your personal namespace.
Membership Management
Admins can list members (action: "members"), add new ones (action: "add_user"), and remove existing ones (action: "remove_user"). Members can leave by declining or being removed. Only admins can delete the collection itself (action: "delete").
| Action | Who Can Call | Effect |
|---|---|---|
create | Any user | Creates a new collection. Caller becomes admin. |
list | Any user | Lists your collections and pending invitations. |
add_user | Admin | Sends an invitation to join by email or agent name. |
remove_user | Admin | Removes a member from the collection. |
members | Any member | Lists current members and their roles. |
accept | Invitee | Accepts a pending invitation. |
decline | Invitee | Declines a pending invitation. |
publish | Member or Admin | Copies personal memories into the collection by ID. |
delete | Admin | Deletes the collection and all its memories. |
Publishing Memories
Publishing copies personal memories into a collection. The originals stay in your personal namespace, untouched. The copies live in the collection namespace and are searchable by all members.
Call collection_manage(action: "publish", name: "Team Notes", memory_ids: ["id-1", "id-2"]). The server reads each memory from your personal namespace, duplicates it into the collection namespace with the same embedding and metadata, and skips any that already exist (by content hash) to prevent double-publishing.
Curation, Not Delegation
Publishing is the mechanism for sharing curated knowledge. You choose which memories to share, one batch at a time. The collection doesn't get a live feed of everything you store — only what you explicitly publish. This keeps collections focused and prevents personal context from leaking into shared space.
Published memories are full copies, not references. If you later edit the original in your personal namespace, the collection copy is not updated. If you delete the original, the collection copy persists. Each namespace owns its copy independently.
Agent Identity
Agents are separate accounts that operate under your main account. They share your OAuth token but have their own memory namespace, their own topic landscape, and their own session state. An agent named dev-claude calling init_core_memories sees only what dev-claude has stored, not your personal memories.
Creating and Using Agents
Call agent_manage(action: "create", name: "research-bot"). The server creates the agent and returns a setup instruction: add the header X-Agent-ID: research-bot to your MCP server configuration. All calls with that header operate in the agent's namespace. No separate authentication — the same OAuth token routes to the right namespace based on the header.
Owner Access
By default, agents are fully isolated. They can't see your personal memories, and you can't see theirs through normal search. The owner_access setting on each agent controls whether that boundary is relaxed:
none(default) — the agent only sees its own namespace. Complete isolation. Use this for bots that should build their own context independently.reader— the agent can search and read your personal memories, but cannot write to your namespace. Use this for assistants that need your context but shouldn't modify it.member— the agent can read and write to your personal namespace. Use this for agents that act as extensions of you — storing findings directly in your memory.
Update at any time: agent_manage(action: "update", name: "research-bot", owner_access: "reader"). Changes take effect on the agent's next request.
Agents in Collections
Agents can be added to shared collections just like human users. Call collection_manage(action: "add_user", name: "Team Notes", user: "research-bot") with the agent's name instead of an email address. The agent sees collection memories in its search fan-out and can write to the collection (if its role permits). This is how you build multi-agent workflows that share state through a common collection.
Collection-Gated Signals
Signals are zero-content pointers — a list of memory IDs sent from one account to another. They carry no payload, no message, no metadata. The recipient retrieves the referenced memories to see what was communicated.
Every signal routes through a shared collection. The sender specifies a collection, the server verifies that both sender and recipient are members, and the signal is delivered. If either party lacks membership, the signal fails.
Collections Are the Access Control
There is no global broadcast, no DM channel, no way to signal someone you don't share a collection with. The collection membership check is the entire access model. If you want to signal an agent, add it to a collection first. If you want to revoke someone's ability to signal you, remove them from the collection.
This design prevents spam and controls information flow. A signal is only useful if the recipient can retrieve the referenced memories, and they can only retrieve memories stored in namespaces they have access to. The collection is the trust boundary for both the notification and the content.
Signals auto-expire after 48 hours. Recipients see pending signals on their next init_core_memories call or via signal(action: "check"). After processing, the recipient calls signal(action: "ack") to consume the signal.
Dashboard Namespace Scoping
The web dashboard reflects the same namespace model the API uses. A namespace selector lets you switch between your personal memories, any collection you belong to, or any agent you've created. The view updates to show only memories in the selected namespace — counts, topics, types, and search results all scope accordingly.
This isn't a separate permissions layer. The dashboard reads from the same endpoints your AI does. If your AI's search includes a collection, the dashboard can show it. If an agent has owner_access: "none", the dashboard shows the agent's namespace as a separate, isolated view.
Transparency Model
Gnosis never sees the user's message. The AI client — Claude, GPT, Gemini, whatever is running the conversation — decides when to call Gnosis tools. Each call is an explicit, typed tool invocation with parameters the user can inspect in their conversation log. There are no background syncs, no passive data collection, no ambient listening.
When the AI calls memory_add, the user sees the call, sees what was stored, and sees the response. When the AI calls memory_search, the user sees the query and the results. When the AI calls signal(action: "send"), the user sees who received what. Every operation is visible, auditable, and attributable to a specific tool call in a specific conversation turn.
This is a consequence of MCP architecture, not a policy choice. The server has no channel to the user's conversation except through tool responses. It cannot inject content, suggest actions, or observe context. It receives structured requests and returns structured responses.