Skip to content

Core concepts

Read this once. Every other page assumes you know what a scope is, what your role can do, the two kinds of keys, and that everything is recorded as an event.

Organizations, teams, and projects

Agent Access Manager is multi-tenant. The unit of tenancy is the organization (org). Inside an org you can carve out teams and projects:

flowchart TD
    O["Organization<br/>(the tenant: one base currency, its own catalog, its own data)"]
    T1["Team: Platform"]
    T2["Team: Data Science"]
    P1["Project: chatbot"]
    P2["Project: batch-jobs"]
    P3["Project: research"]
    O --> T1
    O --> T2
    T1 --> P1
    T1 --> P2
    T2 --> P3
  • An org is the hard tenant boundary. Its catalog, budgets, guardrails, keys, audit trail, and spend are its own and are never shared with another org. Each org has one base currency (default USD) that all its pricing, budgets, and spend are denominated in, so totals add up with no currency conversion.
  • A team groups people and work inside an org. Teams can have a lead, who gets a delegated slice of authority (for example, setting a project budget within their own team) without being an org admin.
  • A project is the finest grouping, used to attribute keys, spend, and limits to a piece of work.
  • A person has one account in one org (the one-account-one-org rule). A brand-new user with no org is sent to a short onboarding screen to create or join one.

Who manages the org vs the appliance

Membership roles (below) let people run their own org. Separately, the platform admin is the person who operates the appliance itself (the break-glass admin login or an SSO user with the platform-admin role). The platform admin can act across every org and picks which org to act on per screen; an org member is always locked to their own org.

Scopes and the scope chain

Almost every control in the product (a virtual key, a budget, a rate limit, a guardrail policy) attaches to a scope. There are four scope levels, from broadest to narrowest:

Scope level What it means Example
ORG The whole organization "Acme can spend $5,000/month total"
TEAM One team in the org "Data Science is capped at 2M tokens/day"
PROJECT One project in a team "The research project gets 60 requests/min"
KEY A single virtual key "This one key may not exceed $50/day"

When a request arrives, Agent Access Manager looks at the calling key and builds its scope chain: the key itself, plus whichever of project, team, and org it belongs to. A key always belongs to an org; team and project are optional and set when the key is issued.

flowchart LR
    K["KEY<br/>sk-… (this request)"] --> P["PROJECT<br/>(if the key has one)"]
    P --> T["TEAM<br/>(if the key has one)"]
    T --> ORG["ORG<br/>(always)"]
    classDef present fill:#E9F1FF,stroke:#2F7CFF,color:#0B0F1A;
    class K,P,T,ORG present;

The single most important rule:

How scopes apply

Budgets and rate limits are enforced at every level of the chain at once. A call charged to a key also counts against that key's project, team, and org. The request is allowed only if it passes at all present levels. So an org-wide monthly cap, a team's daily cap, and a single key's hourly cap can all be in force on the same request, and the tightest one wins.

Guardrail policies resolve most-specific-first. The narrowest scope that has a policy for a given content category decides the action, so a team can tighten (or loosen, if allowed) what the org sets.

This is why you can hand a team lead a key and trust that it cannot blow the org budget: the org cap still applies on top of anything set lower down. It is also why cost-aware failover works (see routing): when a per-deployment budget at any level is exhausted, the request fails over to a cheaper backend instead of being denied.

Roles and capabilities

What you can do is decided by your org role. Roles are strictly nested (each higher role includes everything below it) and grant capabilities. The dashboard hides or disables what your capabilities do not cover, but the server is always the real gate, so hiding a button is a convenience, not the security boundary.

Capability Guest User Operator Admin Owner What it unlocks
VIEW Read the dashboards
ISSUE_KEYS Issue / manage virtual keys in your scope
VIEW_BUDGETS See budgets and spend
MANAGE_GATEWAY Guardrails, rate limits, SOAR rules, notifications
MANAGE_DEPLOYMENTS Catalog deployments (model alias, pricing)
MANAGE_TEAMS Create / manage teams
MANAGE_MEMBERS Invite / manage users and guests
VIEW_SECURITY SIEM, UEBA, SOAR, sign-in activity
VIEW_REPORTS View reports
MANAGE_REPORTS Author / schedule / run reports
MANAGE_PROVIDERS Catalog providers + master vendor credentials
MANAGE_BUDGETS Set budgets and cost caps (the money domain)
MANAGE_ORG Org settings, archive, manage admins

A few deliberate splits worth understanding:

  • The operator owns the rules of engagement, not the money. An operator configures guardrails, rate limits, routing (deployments), and SOAR, but cannot set budgets. Setting budgets is MANAGE_BUDGETS, which is admin and owner only.
  • The catalog is split by sensitivity. Connecting a vendor and storing its master key is MANAGE_PROVIDERS (admin-grade, because it holds a credential). Defining a model alias and its pricing is MANAGE_DEPLOYMENTS (operator and up, because routing is the operator's job). Everyone can read the catalog.
  • The team lead is a delegated grant outside the role table. A team lead (is_lead on their team membership) can curate their team's roster and set a project budget inside their team, without being an org admin. They cannot raise their team's own cap.
  • Anti-escalation. You can only assign or manage roles strictly below your own. An unknown stored role fails closed to GUEST.

Two kinds of credentials

There are two completely separate front doors, and they never mix.

Virtual keys (the data plane) The admin plane
Who uses it Your applications Humans (and scripts) administering the product
Where POST /v1/chat/completions, /v1/messages, … /admin/** and the dashboard
Credential A sk-… virtual key (Bearer) A browser session via SSO, the break-glass Basic admin, or an OIDC Bearer token
Stored as SHA-256 hash (the secret is shown once at issue) No password store here; the human session lives at your IdP

Virtual keys are what you give to applications. They are 256-bit sk--prefixed tokens, hashed at rest, and they carry their scope (org, optional team, optional project) so the whole governance chain is known the instant a request arrives. You issue, revoke, and cap them on the Virtual keys page.

The admin plane is the dashboard and its API. It is SSO-first: if your deployment configures Keycloak (or any OIDC provider), people sign in there and Agent Access Manager only validates the resulting token. The local username/password form is a break-glass path, on by default until SSO is configured and then off. See Settings ▸ Authentication and the deep dive in authentication.

One endpoint, many vendors

Your applications always speak the OpenAI chat shape to Agent Access Manager, regardless of which vendor ultimately serves the request. Inbound surfaces (/v1/chat/completions, /v1/responses, /v1/messages, /v1/embeddings) are mapped to one canonical format; outbound adapters translate that to whatever the chosen vendor speaks (OpenAI-compatible passthrough, or translating adapters for Anthropic, Gemini, and Vertex).

The practical consequences for you:

  • You can switch a model alias from, say, OpenAI to a local Ollama or to Anthropic without changing a line in your application. Only the Catalog changes.
  • A model alias (what your app asks for, like gpt-4o-mini or fast-cheap) is decoupled from the upstream model a vendor actually runs. Budgets and reports key on the alias, so they stay stable even as you re-point it.

Everything is an event

Every proxied call publishes a durable event in the same transaction as the work. That one event stream is the backbone of all governance:

flowchart LR
    GW["A proxied call"] -->|publishes| OB[("durable outbox")]
    OB --> AUD["Audit trail<br/>(Audit & usage)"]
    OB --> SPEND["Spend metering<br/>(Budgets)"]
    OB --> ALERT["Alerts<br/>(Notifications)"]
    OB -. "Pro" .-> SIEM["SIEM / UEBA / SOAR"]
    AUD --> RPT["Reports"]

Because the event is written transactionally (a durable outbox), a call's audit record can never be lost, and consumers run off the hot path: a slow analytics query or an OpenSearch outage adds zero latency to the call your application made. This is why the same data shows up consistently in Audit & usage, Budgets, Reports, and (on Pro) SIEM: they are all reading the one event stream, each for their own purpose.

The events worth knowing by name:

Event Emitted when Feeds
LlmCallCompleted Any completion attempt finishes Audit trail, spend, SIEM/SOAR
GuardrailTriggered A guardrail flags / redacts / blocks Guardrail trail, alerts, SIEM/SOAR
SecurityActionTaken SOAR contains something (quarantine / throttle) Audit, SIEM
ScopeDeleted An org or team is hard-deleted Tenant purge: budgets, keys, rules, audit are erased
ConfigChanged An admin changes config The admin-action audit trail

Next: Operate → for the day-to-day screens, or jump to any section from the I want to… table.