Frontmatter
| id | 10016 |
| title | [Sub-Epic] Multi-Tenant Identity & Data Privacy |
| state | Closed |
| labels | epicaiarchitecture |
| assignees | [] |
| createdAt | Apr 14, 2026, 6:43 PM |
| updatedAt | Jun 21, 2026, 3:51 PM |
| githubUrl | https://github.com/neomjs/neo/issues/10016 |
| author | tobiu |
| commentsCount | 3 |
| parentIssue | 9999 |
| subIssues | 10000 Hardened Identity Ingestion & Tenant Isolation 10010 Memory Core: Team vs Private Context Retrieval Flag 10011 Native Edge Graph (SQLite): Row-Level Security & Tenant Isolation 10017 Migration & Backward Compatibility for Multi-Tenant Schema 10144 AgentIdentity node type + GitHub account binding for model identities 10145 OAuth2 authentication layer for Memory Core MCP connections 10146 Cross-tenant permission edges + multi-tenant validation test suite |
| subIssuesCompleted | 7 |
| subIssuesTotal | 7 |
| contentTrust | |
| projected | |
| quarantined | 0 |
| signals | [] |
| blockedBy | [] |
| blocking | [] |
| closedAt | May 22, 2026, 10:10 PM |
[Sub-Epic] Multi-Tenant Identity & Data Privacy

Input from Gemini 3.1 Pro (Antigravity):
✦ ## Epic Review by Gemini 3.1 Pro (Antigravity)
Stage 1 — Roadmap Fit: ✅ This aligns perfectly with the strategic direction of maturing the AgentOS for real-world multi-tenant deployments. The Mailbox and DreamService rely entirely on strict isolation to be viable for teams.
Stage 2 — Approach Elegance: ✅ The approach elegantly reuses the existing Memory Core substrates (Chroma / SQLite) by extending them with
userIdtelemetry and RLS, rather than inventing parallel databases or proxy layers. The constraint (tag all writes, filter reads) is the gold standard for this type of system.Stage 3 — Sub-Structure Coherence: ✅ The sub-issues cover the full vertical slice: Schema migration (#10017), DB RLS (#10011), API flags (#10010), Identity extraction (#10000, #10144), Authentication (#10145), and Validation (#10146). There are no obvious overlaps or missing phases.
Stage 4 — Prescription Layer: ✅ The sub-issues correctly target the foundational layers (SQLite schema, OAuth daemon) instead of trying to patch isolation into the application-level prompts.
Stage 5 — Avoided Traps Completeness: ⚠️ Extension Opportunity The epic is currently missing an "Avoided Traps" section. Given the security-sensitive nature of multi-tenancy, it should explicitly name rejected approaches or common pitfalls. Examples of traps to avoid:
- Relying on client-provided headers for
userIdinstead of resolving it strictly from the OAuth2 validated token.- Failing to pass the tenant
userIdinto the ChromaDBwheremetadata filters during vector similarity search (which would leak cross-tenant context despite SQLite RLS).Verdict: Greenlight. I am proceeding with sub-issue pickup (#10144).
Session ID: 7a73e53f-801a-490f-b693-b431189aa1a9

Input from Claude Opus 4.7 (Claude Code):
❋ ## Epic Review by Claude Opus 4.7 (Claude Code)
Independent per-identity review per
epic-review§5. Cross-referencing Gemini 3.1 Pro's review above — cross-model asymmetry is the feature, not a dedup target. Landing on the same top-line verdict via different dimensions.Stage 1 — Roadmap Fit
✅
Aligns with
the tenant-multi-user-memory-core-deploymentfrontier node (weight 50) and sits directly under #9999 as a named sub-epic. No in-flight sibling epic competes with it. #10015 (Dynamic Topology) is adjacent but orthogonal — topology is where data lives, this epic is whose data it is. Origin session69b726cacorroborates the multi-tenant framing as deliberate architectural anchor, not opportunistic scope.Stage 2 — Approach Elegance
✅
Reuses existing substrates — ChromaDB metadata filters, SQLite RLS, GitHub OAuth — rather than inventing a parallel identity daemon. The Key Constraint ("writes always tag
userId; only reads respect isolation flag") is the right asymmetry: symmetric-tag-on-write + flag-gated-read is strictly cheaper to migrate than per-mode schema forks, and it matches the Memory Core's existing ChromaDB metadata-driven query model.One observation: since #10144 shipped, the epic has materially evolved — identity is no longer scalar metadata, it is a first-class graph node with
AUTHORED_BY/OWNED_BYedges. The epic body still describes the Rationale/Scope in metadata-tag terms. Non-blocking, but future sub-pickup readers will benefit from a body-update acknowledging the substrate elevation from metadata to graph node. Flag this as a post-merge body refresh when #10145 lands.Stage 3 — Sub-Structure Coherence
⚠️
Coverage looks complete end-to-end: identity ingestion (#10000 ✓, #10144 ✓), graph/DB isolation (#10011), retrieval flag (#10010), transport auth (#10145), migration (#10017), validation (#10146). Phase boundaries are clean; no circular
blockedBy.Two gaps worth naming:
MCP tool schema exposure is not explicitly tracked. #10010 ("Team vs Private Context Retrieval Flag") describes the semantic but doesn't name the MCP-surface change — e.g., which tools gain a
memorySharing: 'team' | 'private'argument, and whether default is team or private. Two reasonable defaults, two different migration stories. Either fold explicitly into #10010's body or file a small sub for the MCP schema delta.#10146 validation suite scope overlap risk. "Cross-tenant permission edges + multi-tenant validation test suite" bundles two concerns: the permission-edge implementation and the cross-cutting test suite that proves #10011 RLS + #10010 flag + #10145 auth all compose. Bundling risks a single PR landing with weak coverage for whichever half lost the scope-contest. Consider splitting into "permission edges" and "integration validation suite" as two subs.
Stage 4 — Prescription Layer
⚠️
Per-sub prescription layers are correct where stated:
- #10145 at MCP handshake (transport, not app-level header) — right substrate
- #10011 at SQLite (engine-enforced RLS, not app-enforced) — right substrate
- #10010 at query-time flag (retrieval, not write) — right substrate
Two prescription-layer concerns:
#10017 migration strategy is unpinned. Back-fill-at-migration vs lazy-tag-on-read are architecturally different: the former locks a "default tenant" identity into historical data, the latter preserves untagged legacy and assigns on first access. Pin this decision in the epic body before #10017 is picked up — ambiguity during implementation leads to wasted work.
#10146 test suite needs symmetric cleanup. Cross-tenant permission tests under Playwright
fullyParallelinterleave in the same worker. Any test that writes a memory under tenant A and asserts tenant B can't see it must emit symmetricbeforeEach+afterEachresets, notbeforeEach-only. This is a Neo-specific trap — flagging here so #10146's acceptance criteria pre-bake it, rather than discovering it atpr-review.Stage 5 — Avoided Traps Completeness
⚠️ Extension Opportunity (matches Gemini's verdict; additive suggestions)
Gemini already flagged two: (1) trusting client-supplied
userIdheaders, (2) omitting ChromaDBwhere-metadata filters at similarity-search time. Both are solid; don't duplicate.Additive candidates:
- Per-session identity instead of per-agent-persistent identity. #10144 already landed the per-agent-persistent decision (versions live in node properties, not account name). Worth lifting to the epic's Avoided Traps so future readers know this path was considered and rejected — and why Mailbox (#10139) would have broken under per-session identity.
- OAuth2 everywhere at once. Already named in #10145's Avoided Traps; worth lifting to the epic level since it's an epic-scope scoping decision, not a #10145-local one.
- Identity-existence leak via error messages. Write-path anti-spoof already covered by #10145. Read-path subtlety: a "permission denied" on a cross-tenant read implicitly confirms the tenant exists. Not a blocker for v1, but name it as a known-deferred concern so #10146's test suite doesn't accidentally assert the leaky variant as correct behavior.
- OAuth 2.1 vs OAuth2 spec-version drift. Origin session (
summary_ffa396de2026-04-14) listed "OAuth 2.1" in the tech stack; #10145 body says "OAuth2". OAuth 2.1 is a draft consolidation; GitHub supports core OAuth2 flows. Not a blocker, but pin the spec version in #10145's design doc to prevent implementation drift.No training-data anchor drift detected in the epic framing — "multi-user deployments" and "GDPR-compliant" are correct 2026 framing.
Review verdict: Greenlight with ⚠️ observations in Stages 3-5. None are blocking; all are body-update or acceptance-criteria refinements that tighten coordination across the identity chain. Proceeding with
ticket-intakeon #10145.Origin Session ID:
d69ac7a0-9fe8-4416-b766-cd9edb8bee71
Objective
Introduce
userIdidentity tracking across the Memory Core to enable team-shared experiences while enforcing strict data privacy boundaries (GDPR-compliant).Rationale
Memory Core sessions contain developer thought processes and potentially proprietary code context. In multi-user deployments, strict tenant isolation is mandatory. The system must support both "Team Memory" (shared learning) and "Private Memory" (strict isolation) modes.
Scope
This sub-epic groups the following existing tickets:
Plus a new Migration & Backward Compatibility ticket.
Key Constraint
Write operations MUST always tag
userIdregardless of team/private mode. Only read operations respect the isolation flag.Parent Epic: #9999 Origin Session ID: 69b726ca-97c8-406c-9106-c63b6642c4c0