Govern & operate
Access control
Provision people, put them in groups, control which models they may run, and share data read-only — enforced in the database, not just hidden in the interface.
Open Admin → IAM (superadmins only). Everything here is enforced by row-level security in the database, which is the reason it holds: an agent, an API call and the UI all hit the same rules, so there is no path that quietly bypasses them.
The six tabs
| Tab | What you do there |
|---|---|
| Users | Invite, create, ban, delete; grant/revoke superadmin; manage group membership |
| Groups | Create, rename, delete groups and manage members |
| Access | Model rules and resource grants |
| Budgets | Per-group spend caps — see Budgets |
| Settings | Public-signup toggle, the default model-access policy (allow vs deny), trace retention, and the current superadmin list |
| SSO | SAML identity provider configuration |
Roles
There are two: superadmin and everyone else. The account named by ADMIN_EMAIL is the permanent bootstrap superadmin — it keeps the role even if its row is deleted, so you cannot lock yourself out. Superadmins can promote and demote others.
Note
Users
Two ways to add someone:
- Email invitation — they set their own password. Preferred; no credential ever passes through you.
- Manual with a temporary password — for when email delivery isn't configured or you're provisioning in bulk. Have them change it.
Users can be banned (blocks sign-in, preserves their content) or deleted. Ban first when someone leaves — deletion is not reversible.
Groups
A named set of users. Model rules and resource grants attach to groups, so onboarding becomes "add to Engineering" rather than a dozen individual grants — and offboarding becomes one removal.
Model rules
Control which models a person may run. What "no rules" means is an instance choice — Settings → Default model access:
| Situation | Allow by default (the default) | Deny by default |
|---|---|---|
| User has no rules, and no group with rules | Unrestricted — every model available | No models at all, until a rule allow-lists them |
| Rules apply (their own or a group's) | Allowed = the union of those rules | Allowed = the union of those rules (identical) |
| Superadmin | Rules apply to them like anyone else | Bypasses entirely — the lock's administrator can't be locked out |
Rule is openai + * | Every model from that provider | Every model from that provider |
Rule is openrouter + openai/* | Prefix match — those models only | Prefix match — those models only |
Flipping to deny is safe to stage
Why it works this way
Enforcement is server-side at the point every chat request is dispatched, so it covers the playground, saved agents, swarm nodes, API runs — and public embeds, which execute their owner's stored model for anonymous visitors and are checked against the owner's effective rules on every request. Pickers also filter to allowed models, but that's convenience — the check that matters happens on the request. Disallowed models return a clear error rather than failing obscurely.
Resource sharing
Grant a user or group read-only access to a resource owned by someone else, under Admin → IAM → Access. Ten resource types are grantable, enforced by a database constraint:
| Type | What the grantee gets |
|---|---|
| 📚 Knowledge base | Their agents can search it |
| 🗄 SQL data table | Queryable, subject to row filters and column masks |
| 🔑 Secret | Usable by reference; the value is never shown |
| 📊 BI dashboard | Viewable, subject to row filters and column masks |
| 🧮 Semantic model | Its metrics and dimensions become askable |
| 🗂 Data catalog source | Its crawled tables and profiles become browsable |
| 🤖 LLM key / ☁️ LLM credential | Calls bill to the owner's key |
| 🏢 Database / warehouse connection | Queryable — see below |
| 🔌 App source | Syncable — see below |
Recipients see a Shared badge; edit and delete controls are hidden and writes are blocked by the database regardless.
Because most grants are enforced in row-level security, agent tools inherit them automatically — a shared table becomes queryable by that user's agents with no extra wiring.
Narrowing a grant: row filters and column masks
Sharing a dataset or dashboard does not have to mean sharing all of it. Two optional restrictions can be attached to a grant on a SQL data table or a BI dashboard — the two types that serve rows. Neither applies to the other eight, and the platform refuses to save them there.
| Restriction | Shape | Effect on the grantee |
|---|---|---|
| Row filter | a column and a list of values | They see only rows where that column matches one of those values |
| Column mask | a list of column names | Those columns are removed server-side — from the column list and from every row |
A regional lead granted the sales table with a row filter of region ∈ (EMEA) and a column mask of salary can query the table freely, see only EMEA rows, and never receive the salary column in any answer.
Both are applied on the server, before the data leaves it — on stored dashboard snapshots, on live warehouse queries, and on the rows an agent's SQL tool reads. There is no path that applies one and not the others.
Grants add up — they never subtract
A masked column is also unfilterable
A restriction that cannot be checked returns nothing
Aggregated widgets go empty for a filtered grantee
SELECT product, sum(revenue) FROM sales GROUP BY product has no region in its output, so a grantee filtered to region ∈ (EMEA) sees an empty widget rather than a global total that ignores their filter. The fix is to project the filter column — group by region, product — so the rows can be vetted. An empty widget is the restriction working, not a broken query.Shared connections run as their owner
Connections are the exception to the row-level rule, because those rows carry an encrypted credential. There is deliberately no row-level policy granting a recipient access to them — that would let a grantee fetch the ciphertext straight from the API with their own token. Instead the grant is resolved server-side and the row is loaded with the service role, so a grantee gains the use of a connection without ever receiving it. {{secret:NAME}} references resolve as the owner too, never against the grantee's own vault.
A shared app source syncs as its owner, into the owner's datasets — so a grantee re-running a stale sync refreshes the real datasets rather than building a parallel copy under their own account. Sharing the source lets someone keep it healthy; to let them read the resulting data, share those datasets too. Grants are resolved fresh on every call, including scheduled runs, so revoking one takes effect on the next use. Full details in Data sources.
Signup policy and SSO
- Invite-only
- Turn off public signup and the database itself rejects new accounts that weren't invited or admin-created. Enforced at the trigger, so it also covers OAuth signups.
- SSO
- Connect a SAML identity provider so people sign in with your corporate directory. Can be made the enforced path.
Worked example — onboarding an analytics team
- 1
Groups → New group
Name itanalytics. Groups are how you avoid granting things person by person. - 2
Users → Add user → Invite by email
They set their own password, so no credential passes through you. Repeat for the team, then add each to analytics from their row. - 3
Access → Model rules → principal: group analytics
Addopenai+gpt-4o-miniandopenai+gpt-4o. The team is now restricted to those two; everyone outside the group is still unrestricted unless a rule applies to them. - 4
Access → Resource grants
Grantanalyticsread access to therevenuedata table and theFinance policiesknowledge base. Their agents can now query both with no further wiring. - 5
Budgets → new cap, scope group analytics
Set a monthly USD ceiling before handing out access, not after the first surprise. - 6
Settings → turn OFF public signup
Do this before you share the URL. Invitations and admin-created users keep working.
A sensible rollout
- Sign in as
ADMIN_EMAILand confirm you have the IAM page. - Create groups that mirror how people actually work, not the org chart.
- Turn off public signup before sharing the URL.
- Set model rules on groups — start permissive, tighten with evidence from Analytics.
- Share the data collections teams need read access to, rather than duplicating them.
- Pair rules with budget caps: rules decide what, budgets decide how much.