> ## Documentation Index
> Fetch the complete documentation index at: https://docs.userepo.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Scopes

> How Repo enforces what each agent is allowed to see and do.

Every API key carries two scope dimensions:

1. **Allowed actions** — what verbs the key can perform (`search`, `ask`, `ingest`, etc.)
2. **Allowed providers** — which data sources the key can retrieve from (`slack`, `notion`, etc.)

Both are enforced server-side. A scoped key cannot bypass its restrictions by crafting a clever request — the filtering happens before any data leaves the database.

## Why scope agents narrowly

The agent you ship to production is almost certainly not allowed to do everything you, the developer, can do in the console. A customer-support agent reading Slack #support is a different blast radius than an admin script that can mint new keys.

The pattern:

* **Admin key** — Lives in your secrets manager. Used by your backend to mint per-agent keys.
* **Per-agent keys** — One key per logical agent, scoped to the narrowest set of actions + providers it actually needs.

If a key leaks, you revoke that one key. The blast radius is the scope of that single agent.

## Action scoping

When you call `/v1/api-keys` (POST) to create a key, pass `allowedActions` as an array. Repo rejects requests for any action not in the list:

```bash theme={null}
# Key created with allowedActions: ["search", "context"]
# This will fail with 403:
curl -X POST https://api.userepo.com/v1/ask \
  -H "Authorization: Bearer repo_scoped_key" \
  -d '{"query": "..."}'

# Response:
# {"error":"API key not allowed to perform 'ask' action"}
```

## Provider scoping

`allowedProviders` is an optional array of provider IDs. `null` means "no restriction" — the key sees everything the org has connected. An array means "only these providers."

```json theme={null}
// Key restricted to Slack + Notion
{
  "allowedProviders": ["slack", "notion"]
}
```

When the key calls `/v1/search` or `/v1/context`:

1. The retrieval query runs against the full org index.
2. Hits from excluded providers are filtered out *before serialization*.
3. The response includes an `exclusions` array explaining which providers were filtered and why — so your agent knows the data exists but it wasn't allowed to see it.

```json theme={null}
{
  "exclusions": [
    {
      "type": "provider_scope",
      "provider": "gmail",
      "reason": "The authenticating API key is not allowed to retrieve this provider."
    }
  ]
}
```

This is critical for honest agent behavior: the agent can tell its user "I have additional context I'm not allowed to share" instead of pretending the data doesn't exist.

## Source-level access policies

Beyond key scopes, individual source items carry their own `accessPolicy` metadata captured at ingest time. Examples:

* **Notion**: `mode: "provider_scope"` — the integration grants per-page access; retrieval is governed by what the integration was given.
* **Google Drive**: `mode: "source_acl"` — each file carries its sharing settings; Repo preserves them and can re-enforce on retrieval.
* **Gmail**: `mode: "provider_scope"` — mailbox-level access; bound to the OAuth grant.
* **Slack**: `mode: "channel_scope"` — limited to channels the bot was added to + the channel allowlist.

Future work: `/v1/context` will support an `actingAsUserId` parameter so an agent representing a specific human can be further scoped to only that human's accessible sources. This is on the roadmap and not yet live.
