Authorization
How Gibson decides what an agent, tool, or plugin may do. Every component has a human owner. Read, write, and execute are separate grants. A deny at tenant, team, or user scope always wins.
Authorization is an OpenFGA model, the Google Zanzibar relationship model. The model file and its generated registry are the source of truth. The registry is generated. Nobody edits it by hand.
The short version: an agent cannot do anything nobody granted it, and every agent traces back to a named person.
Every component has a human owner
Agents, tools, and plugins are not users with a flag set. They are their own principal types, and each one declares an owner:
type agent_principal
relations
define owner: [user]
define belongs_to: [tenant]
define cannot_invoke: [component]
tool_principal and plugin_principal have the same shape.
What that gets you: the model records which human is answerable for each agent as a relation. It is not a convention that someone has to keep up. You cannot enroll an agent that belongs to nobody. The answer survives when the person changes teams.
Read, write, and execute are separate
Every component carries three effective relations:
| Relation | What it allows |
|---|---|
can_read | See the target component's state, recent runs, and metadata |
can_configure | Change the target's settings |
can_execute | Invoke it — run the agent, call the tool |
A grant of one is not a grant of another. An agent with can_read on a tool
cannot run it.
A deny at any scope wins
Three scopes can switch a component off. The model subtracts them from the grant. It does not race them:
can_execute: (direct_execute and in_tenant_catalog) but not any_execute_deny
Here any_execute_deny is the union of the tenant-, team-, and user-scoped
disables. The same shape applies to read and configure.
What that gets you: one kill switch that no grant elsewhere can out-vote. If you disable a component at tenant scope, no team grant and no user grant can enable it again. One write turns a component off. You do not need to find and undo every grant that turned it on.
in_tenant_catalog is the second half. A component is reachable only if your
tenant has enabled it. A component published to the platform is not
automatically available inside your tenant.
An agent that acts as itself needs two keys
When the caller is a component and not a person, the model requires both the owner-side grant and a per-component grant:
can_read_as_component: can_read and component_read_enabled
can_write_as_component: can_configure and component_write_enabled
can_execute_as_component: can_execute and component_execute_enabled
component_*_enabled is absent by default, and absent means denied. The owner
approves it at install time.
What that gets you: a grant to a person for a tool does not silently grant that tool to every agent the person owns. The agent's own authority is a separate and narrower decision. The owner makes it once, and it is visible as its own tuple.
Block a specific pairing
Two relations handle the cases a grant cannot express:
cannot_invokeon a principal blocks named components outright.can_be_invoked_byon a component controls which agents may call it.
So you can allow an agent broad execute rights and still fence off one tool. You do not need to rebuild the grant set.
Where a person manages this
A person manages grants in the dashboard's grants table, over the tenant grants API. The operator's walkthrough covers roles, the permissions tab, and the deploy wizard. It is on Roles & permissions. This page is the model underneath it.
What a human does and does not do
A person does: own components, write and revoke grants, enable or disable a component at tenant, team, or user scope, and set the mission constraints.
A person does not: approve individual actions while a mission runs. That is a deliberate decision, recorded as an ADR. See Runtime. A person declares control before the agent starts. The agent does not request control while it works.
What to check
- Every principal type declares
owner: [user]. can_read,can_configure, andcan_executeare independent.- The model subtracts deny from the grant, so a disable at any scope wins.
component_*_enabledis absent by default, and absent denies.- The authz registry is generated, and CI fails if a hand edit drifts from it.
Identity
How every caller proves who it is. Gibson runs two identity planes, SPIFFE mTLS inside the cluster and the Capability Grant Protocol for agents that run anywhere else. This page also lists every static credential in the platform.
Isolation
One gate decides how a component runs. It denies the component, puts it in a Firecracker microVM, or runs it in process. It reads the component's declared content trust and the deployment shape, and it fails closed.