RBAC & Permissions

Roles, zones, and the configuration file that governs who — human or agent — can do what inside an Aura deployment.

Overview

Aura's permission model is built around two primitives: roles (what kind of actor you are) and zones (what region of the codebase a given actor is permitted to act in). Both are enforced at the Mothership and at the pre-commit hook, not at the application layer — which means an actor who has bypassed the CLI cannot bypass the controls.

The model is deliberately small. Four roles. Explicit zones. No inheritance trees, no wildcards that silently widen access, no "effective permissions" calculator required to answer the question can this agent delete this function. The answer is always readable directly from the config file.

This page documents the four roles, the zone primitive, how agent identities differ from human identities, and the exact config file format.

The four roles

| Role | Intended holder | Can read | Can write | Can administer | | --- | --- | --- | --- | --- | | admin | Platform team lead | All | All | Yes | | contributor | Engineers, trusted agents | Zones they own + public | Zones they own | No | | reader | Security reviewers, auditors, managers | All | None | No | | agent | Autonomous AI agents | Zones they own + public | Zones they own, with additional guardrails | No |

The agent role is not a demotion of contributor — it has the same zone-scoped write surface — but it is subject to additional guardrails that do not apply to humans:

  • Agent writes that delete a function require an explicit aura_log_intent entry naming the function and a reason. The pre-commit hook blocks deletions otherwise.
  • Agents cannot disable strict mode, even if strict_mode_locked is false.
  • Agents cannot claim a zone currently owned by a human without the human's acknowledgement message flowing through Sentinel.
  • Agents have per-minute rate limits on intent log append, configurable per agent identity.

These are not moral judgments about agents; they are load-bearing safety properties for teams operating fleets of autonomous coders.

The zone primitive

A zone is a named glob pattern over the repository path space, optionally scoped to specific function identities. Every zone has exactly one owner identity and zero or more cooperators.

[[zone]]
name = "billing-core"
paths = ["services/billing/**"]
owner = "user:alice@example.com"
cooperators = ["user:bob@example.com", "agent:refactor-bot"]
require_review = true
min_reviewers = 1

When an actor attempts to modify a file inside services/billing/, the Mothership checks:

  1. Is the actor the owner? Write allowed.
  2. Is the actor a cooperator? Write allowed, review required per require_review.
  3. Otherwise — write is blocked at the pre-commit hook with a clear message pointing to the zone owner.

Zones can be narrower than whole directories. A zone can target a specific function identity:

[[zone]]
name = "auth-token-issuance"
function_ids = ["fn:a1b2c3d4e5f6..."]
owner = "team:security"

This is useful when a critical function lives inside an otherwise open directory and must be protected individually.

Zone ownership vs. file locking

Aura zones are not file locks. They do not prevent two people from reading or from drafting changes concurrently. What they prevent is the commit of a change that lands inside someone else's zone without their consent. This preserves the parallel-development property that made Git famous, while ensuring that accountability remains unambiguous.

When an agent or human pulls changes from a teammate, the Mothership automatically checks destination zones before applying. If the incoming change would land inside a zone owned by the current actor, and the push originated from a non-cooperator, the sync subsystem raises an impact alert that must be reviewed via aura_live_impacts and resolved via aura_live_resolve.

Identities

An identity is a stable string of the form <kind>:<local-part>. The three supported kinds:

  • user: — a human identity, resolved against your directory.
  • agent: — an autonomous AI agent identity, pinned to a cryptographic public key.
  • team: — a named group that expands to a set of user: and agent: identities.

Directory integration is pluggable. Supported providers:

  • OIDC: any provider speaking OpenID Connect Discovery. Azure AD, Okta, Keycloak, and Google Workspace are tested.
  • SAML: SAML 2.0 for enterprise SSO portfolios.
  • Static file: YAML list of identities and public keys, for air-gapped deployments.
  • mTLS: identity carried in the client certificate subject.
[directory]
provider = "oidc"
issuer   = "https://auth.example.com/"
client_id = "aura-mothership"

[directory.group_mapping]
"aura-admins"        = "role:admin"
"platform-eng"       = "role:contributor"
"security-auditors"  = "role:reader"

Agent identities are registered separately, because agents do not log in through a browser:

[[agent]]
identity = "agent:refactor-bot"
public_key = "ed25519:…"
role = "agent"
rate_limit_per_minute = 120
owner = "user:alice@example.com"

The owner field is important: every agent has a human owner who is accountable for the agent's behavior. If an agent produces a problematic commit, the human owner is the audit signal.

Config file format

Permissions live in /etc/aura/permissions.toml on the Mothership. The file is hot-reloaded on change; the Mothership logs a permissions_reload event into the intent log each time.

[defaults]
role = "reader"               # anyone not otherwise configured is read-only
require_review = false
public_zones = ["docs/**", "examples/**"]

# --- Roles ---
[[role_grant]]
identity = "user:alice@example.com"
role = "admin"

[[role_grant]]
identity = "team:platform-eng"
role = "contributor"

[[role_grant]]
identity = "user:auditor@example.com"
role = "reader"

# --- Teams ---
[[team]]
name = "platform-eng"
members = [
  "user:alice@example.com",
  "user:bob@example.com",
  "agent:refactor-bot",
]

# --- Zones ---
[[zone]]
name = "billing-core"
paths = ["services/billing/**"]
owner = "team:platform-eng"
require_review = true
min_reviewers = 1
reviewer_role = ["contributor"]

[[zone]]
name = "auth-token-issuance"
function_ids = ["fn:a1b2c3d4e5f6..."]
owner = "team:security"
require_review = true
min_reviewers = 2

# --- Agents ---
[[agent]]
identity = "agent:refactor-bot"
public_key = "ed25519:MCowBQYDK2VwAyEA…"
role = "agent"
rate_limit_per_minute = 120
owner = "user:alice@example.com"

Strict mode and break-glass

strict_mode is the global switch that turns every permission check into a hard block at the pre-commit hook, including the intent-vs-AST drift check. When strict_mode_locked = true, a human with the passcode is required to disable it.

[policy]
strict_mode = true
strict_mode_locked = true
strict_mode_passcode_file = "/etc/aura/secrets/strict-passcode"

Break-glass procedure:

  1. The on-call engineer runs aura admin break-glass --reason "incident #4218".
  2. The CLI prompts for the passcode.
  3. Strict mode is disabled for a bounded window (default 30 minutes).
  4. An emergency intent record is written, referencing the reason.
  5. At the end of the window, strict mode re-enables automatically. The emergency record remains in the intent log forever.

This is the only supported way to bypass permission checks. There is no silent override.

Permission enforcement points

Permission checks happen at four points. A request that fails any one is rejected.

  1. CLI pre-flight: Local check before the CLI attempts any action. Fails fast for offline users.
  2. Pre-commit hook: The hook verifies zone ownership and intent-vs-AST drift before Git accepts the commit.
  3. Mothership push: The Mothership re-verifies on aura_live_sync_push. Defense in depth — a tampered local hook does not get past this.
  4. Peer receive: When another peer pulls, the Mothership verifies the originating push was authorized. A compromised peer cannot inject unauthorized changes into teammates.

Auditing permission changes

Every permission change — adding a role, claiming a zone, rotating an agent key — is itself an intent record. The hash chain covers permissions state, not just code changes. That means an auditor running aura audit verify can prove that no permission was silently granted or revoked inside the review window.

aura audit export --window 2026-Q1 --include permissions

The resulting evidence package includes a permissions-events.ndjson file with every change and the actor who performed it.

Integration with Git platforms

Aura's RBAC is independent of GitHub, GitLab, or Bitbucket permissions. Aura controls semantic changes; the Git platform controls branch protection and merge gates. The two layers complement each other:

  • A developer may have write access on GitHub but lack a zone grant in Aura. Their push is accepted by GitHub but blocked by the pre-commit hook.
  • A developer may have a zone grant in Aura but lack write on GitHub. Their local work succeeds but cannot be pushed to the remote.

Run both. They answer different questions.

Patterns and anti-patterns

Patterns we have seen work well at scale:

  • One zone per service, owned by the service's primary team. Cooperators for adjacent teams who occasionally contribute.
  • Dedicated zones for agent fleets, so an agent owner can see exactly what their agents touched.
  • Review required on anything in services/*/security/ paths, independent of team ownership.

Anti-patterns we recommend against:

  • Giving admin to more than three humans. Use contributor with well-scoped zones instead.
  • Using agent role for human accounts "to reduce risk" — it removes the ability to break glass.
  • Overlapping zones that both claim the same paths. The Mothership will refuse to start.

See Also