Access
Declare who can run what. role blocks derive roles from verified identity attributes, and policy grants map those roles to agents, workflows, and tools.
role blocks derive roles from verified identity attributes. policy grants determine which agents those roles may invoke and which workflows they may start directly. Agent grants also accept nested workflow and tool restrictions. See Enforcement for which restrictions are currently enforced.
By default, every organization member can run everything in a deployment. Adding a policy grant changes the project to deny by default: a principal can reach only what a matched role grants. Access rules live in .swirls files and are reviewed, versioned, and deployed with the project.
Assign member attributes on the project's Access page, or supply claims through OIDC federation. Decisions are recorded in the audit log. For outbound credentials, see Connections.
The model: identity asserts facts, the file decides what they mean
The identity source never assigns a Swirls role. It only asserts facts about the principal: a Swirls user carries their organization role and any attributes assigned in the dashboard, and a federated user carries the verified claims from their identity provider's JWT. Your role blocks decide which facts to trust and what they mean. The claim keys named in match rules are the only attributes the policy engine ever reads; anything else the identity source sends is inert.
The role block
A top-level block that derives a named role from attribute values:
role finance {
description: "Finance team"
match {
department: "finance"
}
}
role exec {
match {
org_role: [ "owner", "admin" ]
}
}| Field | Type | Required | Notes |
|---|---|---|---|
description | string | No | Human-readable description of the role. |
match | block | Yes | Attribute conditions, one per line. |
Match semantics:
- A scalar value is an equality test:
department: "finance"matches when the principal'sdepartmentisfinance. - A list value is a membership test:
org_role: [ "owner", "admin" ]matches either value. - Multiple conditions in one
matchblock must all hold (AND). Declare separate roles for OR. - A principal whose attribute is itself a list (for example,
groups) matches when any of its values intersects the condition. - An empty
matchblock matches no one;swirls doctorwarns about it.
Role names match ^[a-zA-Z0-9_]+$, and duplicate role names are an error.
The policy block
A top-level block that attaches grants to role names:
policy {
allow finance -> agent accountant {
workflows: [ brex, quickbooks ]
}
deny finance -> agent ceo_pa
allow exec -> agent *
}Each grant is allow or deny, a role name, ->, and a target agent <name> or agent *. The policy block takes no name, and agent * (every agent in the deployment) is the only wildcard.
- An omitted body grants all of the agent's workflows and tools. The body's only keys are
workflows:andtools:, bare-identifier arrays that narrow the grant. denyalways wins overallowfor the same target, across every role the principal matched. Agent grants and direct workflow grants are separate targets.- A principal matching multiple roles gets the union of their grants.
- Declaring any grant flips the project to deny by default. Principals matching no granting role cannot run the deployment. Remove every grant to return to the open posture; an empty
policy { }enforces nothing.
Roles without grants are inert. Define them first, deploy, and confirm who matches in the dashboard before adding grants.
Direct workflow grants
Use workflow <name> to grant a direct workflow entry point:
policy {
allow finance -> workflow prepare_quote
deny suspended -> workflow prepare_quote
}The workflow must exist in the project. Direct grants accept neither wildcards nor nested bodies. For MCP workflow tools, publish the workflow on the channel as well. Both publication and a matching direct grant are required, even if the deployment otherwise has no policy. An agent grant does not grant direct MCP access.
Where attributes come from
Swirls users
Members of your organization carry two kinds of attributes:
org_role: the organization role (owner,admin, ormember), managed on the Members page in the dashboard. Use it for org-wide rules like an admin role.- Project attributes: facts like
departmentorgroup, assigned per project in the dashboard under your project → Access. The page reads the active deployment, offers only the attribute keys your deployedroleblocks reference, and previews which roles each member matches as you assign values. Assignments in one project never affect another.
Only organization owners and admins can assign project attributes, and a project attribute can never override org_role.
Federated users (OIDC)
A federated credential and its verified claims belong to one project registration. Organization provider inheritance reuses settings while giving each project its own audience and identities. The same issuer and subject in two projects produce separate principals. Role grants can narrow access within the bound project; they cannot grant access to another project. The project boundary applies even when no policy is declared. Federated principals have no Swirls organization membership or org_role.
Principals authenticating through OIDC Federation carry the verified claims from the JWT they exchanged. Your identity provider is the attribute source: put department, groups, or any other fact in the token, and match rules evaluate it directly. See map identity claims to access roles for provider setup.
MCP credentials
Organization owners and admins assign trusted attributes to a credential on the project's Connectors page. Attributes can hold a string or a list of strings. Tool arguments and OAuth dynamic registration cannot assign them. Direct MCP workflow runs use this credential's identity and attributes; they do not inherit the project owner's access.
Enforcement
Access is evaluated when a run starts, bound to the principal who triggered it. Every entry point takes the same path: chat, forms, webhooks, schedules, and the API all evaluate the policy before a run begins. Runs started by schedules and triggers evaluate as the principal who owns the trigger.
A principal matching no granting role cannot start a run on a deny-by-default deployment. The decision is stamped into the run's short-lived scoped execution credential, and during the run each agent invocation is checked against the granted agent set, so a workflow can never reach an agent its principal was not granted, including agents reached mid-run. Grants and denials are recorded in the audit log.
Direct MCP workflow grants are enforced during discovery, calls, and execution credential minting. Agent invocations are checked at the agent boundary. Nested workflows: and tools: narrowing in agent grants is recorded on the execution credential but is not yet enforced at those finer boundaries. Use agent profiles to restrict an agent's tools in the meantime.
Enforcement fails closed. An unresolvable principal is denied, a deployment that declares a policy refuses to run unenforced, and a policy that cannot be read denies rather than falling open.
Validation
swirls doctor checks role name shape, duplicate role names, empty match blocks, and direct workflow targets. It does not verify an agent grant's role, agent, nested workflow, or tool references. Check those names before deploying; a misspelled grant can surface as a runtime denial.
Common mistakes
- Writing an
access { }block. There is noaccessblock; it is a parse error. Opt-in is implied by declaring grants. - A typo in an agent grant. Agent grant references are not checked against declared blocks at author time; the misspelled grant can deny at run time.
- Confusing direct and nested workflow grants.
deny sales -> workflow prepare_quotedenies that direct entry point. It does not subtract the workflow from an agent grant's nested workflow list. - Expecting the IdP or dashboard to assign roles. Identity sources assert facts; only
roleblocks in the file assign meaning. - Confusing
rolewith agentprofile. See below.
role is not profile
These are different layers. A top-level role controls who may invoke an agent. An agent's profile controls what the agent may do when it runs: its tools, system prompt, and sandbox. Use both: a role grants the accountant agent to the finance team, and a profile keeps the accountant agent scoped to read-only tools for routine work.
Example: map an org chart
The CEO and CFO reach every agent. The accountant reaches the accountant agent's bookkeeping workflows. HR reaches the HR agent.
role exec {
match {
title: [ "ceo", "cfo" ]
}
}
role accounting {
match {
department: "accounting"
}
}
role hr {
match {
department: "hr"
}
}
policy {
allow exec -> agent *
allow accounting -> agent accountant {
workflows: [ brex, quickbooks ]
}
allow hr -> agent hr_assistant
}Deploy with git push or swirls deploy, then assign title and department to members on the project's Access page, or include them as claims in your identity provider's JWTs.
Further reading
- Audit log: the record of who did what, including access grants and denials
- OIDC federation: bring your identity provider's claims as the facts roles match
- Connections: the outbound mirror image of access
Project Networks
Declare private connectivity boundaries, expose selected project interfaces, and identify outbound consumers that need a tailnet route.
Audit log
The append-only record of who did what across your organization. Read it on the Audit page in the dashboard or query it with the SDK using cursor pagination.