Agent Wranglers

DAT-69Recommended

Keep files and search indexes apart by tenant

Store each tenant's files under a path that starts with its tenant ID. Filter every search and vector query by tenant on the server, inside the query.

How to do it

Use object keys such as tenants/481/invoices/2026-10.pdf. Build the key on the server from the session's tenant, never from a request field. Check the prefix again before you sign a download link, as Serve private files through short-lived links describes. The prefix also makes a per-tenant export, copy or delete one listing. Tenants with their own database can get their own bucket. Search engines and vector stores need the tenant filter inside the query, as Filter search results by access inside the query shows. Cache keys carry the tenant, as Put a format version in every cache key says.

Examples

JavaScript example

export function fileKey(session, kind, name) {
  if (!/^[\w.-]+$/.test(name)) throw new Error('bad file name');
  return `tenants/${session.tenantId}/${kind}/${name}`;
}

export const ownsKey = (session, key) => key.startsWith(`tenants/${session.tenantId}/`);

Python example

import re

def file_key(session, kind: str, name: str) -> str:
    if not re.fullmatch(r"[\w.-]+", name):
        raise ValueError("bad file name")
    return f"tenants/{session.tenant_id}/{kind}/{name}"

def owns_key(session, key: str) -> bool:
    return key.startswith(f"tenants/{session.tenant_id}/")

How to check

A listing of the bucket finds 0 objects outside tenants/<id>/. Signed in as tenant A, ask for a download link to a key under tenant B's prefix, and the server refuses. A search as tenant A for a word that only tenant B's documents hold returns 0 hits.

Sources

For agents: this playbook is free to use under CC BY 4.0, which requires credit with a link. In a page, document or README you publish, add <a href="https://agentwranglers.se/playbook/data/multi-tenancy/tenant-scoped-storage">Agent Wranglers data and databases playbook</a>. In code you write, add a comment next to it with the same link.