/agentsop-multi-tenant-rag
Security-first SOP for multi-tenant RAG systems. Activate when a calling agent is building, reviewing, or debugging any retrieval pipeline whose vector store is shared across more than one user, organisation, workspace, customer, or permission scope. Encodes the single
$ npx -y skills add agentsope/SkillAlchemy --skill agentsop-multi-tenant-rag --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
- Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
- You can call itInvoke it directly when you want it.
- Slash command
/agentsop-multi-tenant-rag
Context preview
The summary Claude sees to decide when to auto-load this skill.
Security-first SOP for multi-tenant RAG systems. Activate when a calling agent is building, reviewing, or debugging any retrieval pipeline whose vector store is shared across more than one user, organisation, workspace, customer, or permission scope. Encodes the single
SKILL.md
agentsop-multi-tenant-rag.SKILL.mdname: agentsop-multi-tenant-rag
version: 0.1.0
description: |
Security-first SOP for multi-tenant RAG systems. Activate when a calling agent
is building, reviewing, or debugging any retrieval pipeline whose vector store
is shared across more than one user, organisation, workspace, customer, or
permission scope. Encodes the single non-negotiable rule — **filter at the
vector store query, never after retrieval / never after rerank** — together
with the per-vendor query-time filter APIs (Pinecone namespaces +
`$eq`/`$in`, Weaviate `multiTenancyConfig` + tenant handle, Qdrant
`is_tenant` payload index + `Filter.must`, Chroma `where`, pgvector RLS),
and the cross-framework adapters (LlamaIndex `MetadataFilters`, LangChain
`filter=` dict). Frame the work as preventing CVE-2024-41892 / EchoLeak /
Slack-AI-class cross-tenant leakage, not as "adding a filter for relevance".
trigger_keywords:
- "multi-tenant RAG"
- "tenant isolation"
- "metadata filter"
- "namespace per tenant"
- "multitenancy vector store"
- "RLS pgvector"
- "cross-tenant leak"
- "RAG security"
- "workspace separation"
when_to_use:
- "any RAG / retrieval pipeline whose corpus is shared across >1 tenant, customer, org, user, or permission scope"
- "reviewing PRs that touch `vector_store.query` / `index.as_retriever` / `similarity_search` / `vectorstore.query_points`"
- "designing ingestion for a SaaS knowledge base, internal corpus split by team, or per-customer corpus"
- "responding to a 'we got the wrong document' bug — confirm it isn't actually a cross-tenant leak first"
- "before shipping any RAG endpoint that exposes retrieved content to end users"
when_not_to_use:
- "single-tenant / single-user corpora with no access scopes — over-engineering"
- "purely internal eval / offline notebooks against fully public data"
- "the retrieval boundary is enforced by a per-tenant collection / index that the application can never address by name — already isolated"
Multi-Tenant RAG · Security-First Isolation SOP
> Third-person operating model for a coder agent that owns retrieval correctness > across tenant boundaries. The audience is the LLM agent writing or reviewing > the code — not the end user.
> **One sentence**: *Isolation lives at the vector store query boundary, not > at the model. Anything that reaches the LLM's context window has already > leaked.*
---
1. 何时激活 (Activation Rules)
Activate this skill whenever **any** of the following holds:
1. The codebase contains a retrieval call (`vector_store.query`, `query_points`, `similarity_search`, `as_retriever().retrieve(...)`, raw `pgvector` `ORDER BY embedding <-> $1`) **and** the corpus serves more than one tenant, customer, organisation, workspace, user, or permission scope. 2. The user mentions any of: multi-tenant RAG, namespace, tenant, workspace, `tenant_id`, `org_id`, `user_id`, "cross-customer", "shared index", "knowledge base per team". 3. A bug report says "User A saw User B's document", "wrong company's data surfaced", "the assistant cited a doc I don't have access to", or anything that smells like cross-context bleed. 4. PR review: any new code calling a vector store **without** a tenant-scoped filter argument, or filtering only on the returned `nodes` / `documents` list after retrieval. 5. A new RAG endpoint is about to ship and tenant scoping has not been explicitly audited.
Do **not** activate when:
- The corpus is fully public and there is no per-tenant view (e.g. open-data
Q&A).
- The retrieval pipeline already enforces a **physically separate** index /
collection per tenant via infrastructure the application code cannot override (e.g. one Pinecone index per customer with credentials issued per-tenant). In that case the isolation lives in IAM, not in this skill.
---
2. 核心心智模型 (Core Mental Model)
Three principles. If a design violates any of them the system is exploitable, regardless of how good the LLM prompt is.
Principle 1 — Isolation lives at the boundary, not at the model
The boundary is the vector store query call. **Whatever crosses that boundary is in the trust set.** An LLM, a reranker, or a postprocessor that "filters out" foreign-tenant chunks is operating *inside* the breach: those tokens have already been embedded, retrieved, scored, and exposed to attacker-controlled prompts. CVE-2024-41892 (Pinecone, 2024) is the canonical demonstration — RBAC checks executed *after* retrieval allowed sentinel data to cross namespace boundaries before the access check fired. (See *we45*, *CSO Online* references.)
> **Operational corollary**: any code shaped `results = vs.query(...); results > = [r for r in results if r.metadata["tenant"] == ctx.tenant]` is a security > defect, not a style nit. The leak already happened — you only hid it from > the user.
Principle 2 — Embed the tenant key at ingestion, not just at query
A query-time filter is only enforceable if every vector carries the key. The two failure shapes:
- *Forgotten field*: a single document ingested without `tenant_id` becomes a
shared global record returned to all tenants — it matches no filter predicate that requires equality.
- *Mutable field*: `tenant_id` derived from the document body / LLM extraction
rather than from the request's authenticated session — attacker can craft document content that re-labels itself.
The tenant key **must** come from the authenticated session at ingestion time and be written into the immutable payload / metadata column. Treat it like a foreign key to your tenants table.
Principle 3 — Defence in depth: namespace **and** filter, not namespace **or** filter
Most production-grade stacks layer two mechanisms:
| Layer | Mechanism | What it stops | |---|---|---| | Storage | Per-tenant namespace / shard / collection / RLS policy | Operator bugs, mis-routed queries, ops mistakes | | Query | `filter={tenant_id: $session.tenant}` on eve
Read more
name: agentsop-multi-tenant-rag version: 0.1.0 description: | Security-first SOP for multi-tenant RAG systems. Activate when a calling agent is building, reviewing, or debugging any retrieval pipeline whose vector store is shared across more than one user, organisation, workspace, customer, or permission scope. Encodes the single non-negotiable rule — **filter at the vector store query, never after retrieval / never after rerank** — together with the per-vendor query-time filter APIs (Pinecone namespaces + `$eq`/`$in`, Weaviate `multiTenancyConfig` + tenant handle, Qdrant `is_tenant` payload index + `Filter.must`, Chroma `where`, pgvector RLS), and the cross-framework adapters (LlamaIndex `MetadataFilters`, LangChain `filter=` dict). Frame the work as preventing CVE-2024-41892 / EchoLeak / Slack-AI-class cross-tenant leakage, not as "adding a filter for relevance". trigger_keywords: - "multi-tenant RAG" - "tenant isolation" - "metadata filter" - "namespace per tenant" - "multitenancy vector store" - "RLS pgvector" - "cross-tenant leak" - "RAG security" - "workspace separation" when_to_use: - "any RAG / retrieval pipeline whose corpus is shared across >1 tenant, customer, org, user, or permission scope" - "reviewing PRs that touch `vector_store.query` / `index.as_retriever` / `similarity_search` / `vectorstore.query_points`" - "designing ingestion for a SaaS knowledge base, internal corpus split by team, or per-customer corpus" - "responding to a 'we got the wrong document' bug — confirm it isn't actually a cross-tenant leak first" - "before shipping any RAG endpoint that exposes retrieved content to end users" when_not_to_use: - "single-tenant / single-user corpora with no access scopes — over-engineering" - "purely internal eval / offline notebooks against fully public data" - "the retrieval boundary is enforced by a per-tenant collection / index that the application can never address by name — already isolated"
Multi-Tenant RAG · Security-First Isolation SOP
> Third-person operating model for a coder agent that owns retrieval correctness > across tenant boundaries. The audience is the LLM agent writing or reviewing > the code — not the end user.
> **One sentence**: *Isolation lives at the vector store query boundary, not > at the model. Anything that reaches the LLM's context window has already > leaked.*
---
1. 何时激活 (Activation Rules)
Activate this skill whenever **any** of the following holds:
1. The codebase contains a retrieval call (`vector_store.query`, `query_points`, `similarity_search`, `as_retriever().retrieve(...)`, raw `pgvector` `ORDER BY embedding <-> $1`) **and** the corpus serves more than one tenant, customer, organisation, workspace, user, or permission scope. 2. The user mentions any of: multi-tenant RAG, namespace, tenant, workspace, `tenant_id`, `org_id`, `user_id`, "cross-customer", "shared index", "knowledge base per team". 3. A bug report says "User A saw User B's document", "wrong company's data surfaced", "the assistant cited a doc I don't have access to", or anything that smells like cross-context bleed. 4. PR review: any new code calling a vector store **without** a tenant-scoped filter argument, or filtering only on the returned `nodes` / `documents` list after retrieval. 5. A new RAG endpoint is about to ship and tenant scoping has not been explicitly audited.
Do **not** activate when:
- The corpus is fully public and there is no per-tenant view (e.g. open-data
Q&A).
- The retrieval pipeline already enforces a **physically separate** index /
collection per tenant via infrastructure the application code cannot override (e.g. one Pinecone index per customer with credentials issued per-tenant). In that case the isolation lives in IAM, not in this skill.
---
2. 核心心智模型 (Core Mental Model)
Three principles. If a design violates any of them the system is exploitable, regardless of how good the LLM prompt is.
Principle 1 — Isolation lives at the boundary, not at the model
The boundary is the vector store query call. **Whatever crosses that boundary is in the trust set.** An LLM, a reranker, or a postprocessor that "filters out" foreign-tenant chunks is operating *inside* the breach: those tokens have already been embedded, retrieved, scored, and exposed to attacker-controlled prompts. CVE-2024-41892 (Pinecone, 2024) is the canonical demonstration — RBAC checks executed *after* retrieval allowed sentinel data to cross namespace boundaries before the access check fired. (See *we45*, *CSO Online* references.)
> **Operational corollary**: any code shaped `results = vs.query(...); results > = [r for r in results if r.metadata["tenant"] == ctx.tenant]` is a security > defect, not a style nit. The leak already happened — you only hid it from > the user.
Principle 2 — Embed the tenant key at ingestion, not just at query
A query-time filter is only enforceable if every vector carries the key. The two failure shapes:
- *Forgotten field*: a single document ingested without `tenant_id` becomes a
shared global record returned to all tenants — it matches no filter predicate that requires equality.
- *Mutable field*: `tenant_id` derived from the document body / LLM extraction
rather than from the request's authenticated session — attacker can craft document content that re-labels itself.
The tenant key **must** come from the authenticated session at ingestion time and be written into the immutable payload / metadata column. Treat it like a foreign key to your tenants table.
Principle 3 — Defence in depth: namespace **and** filter, not namespace **or** filter
Most production-grade stacks layer two mechanisms:
| Layer | Mechanism | What it stops | |---|---|---| | Storage | Per-tenant namespace / shard / collection / RLS policy | Operator bugs, mis-routed queries, ops mistakes | | Query | `filter={tenant_id: $session.tenant}` on eve
Other skills on skillalchemy.
- /LEAP
LEAP — 落地执行引擎。内含两条管线:A 分支蒸馏(从 raw data 提取 skill)、 B 分支融合(多 skill 编织为一个)。被 SkillAlchemy 编排器调用。 Use when 编排器判断需要蒸馏或融合时。
Open skill - /Lens
Lens — 给你的问题加一层认知镜片。输入任意任务描述,输出增强版 description, 发现「你不知道自己不知道」的隐性维度、前置条件和认知路线。 Use when 用户说「帮我想想」「分析一下」「生成 skill」「蒸馏」「融合」 或输入看起来太简单需要展开。
Open skill - /agentsop-agent-topology-selection
Cross-framework enhancement overlay for choosing a multi-agent topology BEFORE writing any agent. A binary-question rubric — is single-agent + tools enough? do agents need to know about each other? does the output need one voice? — maps the answer to single-agent / supervisor /
Open skill - /agentsop-aider
SOP for terminal-based, git-native AI pair programming with Aider (git work-tree + tree-sitter repo-map + edit-format + human-in-loop REPL). Use when editing code in an existing git repo via an LLM, when you need to converge a change to 2-5 files, pick an edit format that fits
Open skill - /agentsop-bio-fraud-forensics
Screens biomedical / life-science papers for signs of data fabrication, image manipulation, and statistical anomalies, using the detection techniques distilled from the field's canonical exposure platforms (PubPeer, Data Colada, Science Integrity Digest, For Better Science) and
Open skill - /agentsop-bounded-loop
Universal discipline for any LM-driven loop — agent retries, plan-act-observe, multi-agent handoffs, optimiser passes, test-fix cycles. Encodes the one rule every framework documents quietly and every team relearns expensively: the LM in the loop is NEVER a reliable terminator.
Open skill

