Skip to content

Agents

An agent is an AI actor hired onto one app group’s roster. Each agent carries its own machine ConnectedId (Type=AI) — permissions attach to that badge, not to a borrowed key, so an agent shows up in the same access review as the person who created it. Agents take no seat, never appear in member lists or SCIM /Users, and are born with a TTL: creation without an expiry is rejected, and an expired agent is automatically suspended.

Base path: /api/org/{slug}/app-groups/{groupId}/agents (authenticated). Mutations are hard-gated by the org.agent.* scopes.

Method · RoutePurposeRequired scope
GET /List the roster (joined with badge status)membership
GET /templatesKind template catalog (preset scopes per kind)membership
POST /Hire an agent (kind, displayName, expiresAt, scopes[]?, description?, systemPrompt?, model?)org.agent.hire
PUT /{agentId}Update name / description / system prompt / model / TTLorg.agent.update
POST /{agentId}/suspend · /{agentId}/activateSuspend or reactivateorg.agent.suspend
DELETE /{agentId}Revoke — roster row retired, badge deactivatedorg.agent.revoke
  1. Issues a machine badge — ConnectedId with Type=AI, UserId=null, MembershipType=None.
  2. Finds or creates the role for that kind — AGENT_{KIND}, e.g. AGENT_DESIGN. ⚠️ This role is shared by every agent of that kind in the organization. Widening it widens all of them at once. Hire a different kind when you want a different authority.
  3. Brings the role’s templates up to the kind template — on every hire, not only the first. Scopes the catalog has gained since the role was created are added (never removed: a scope a person deliberately took off the role stays off), and every badge already holding the role is re-snapshotted. The same sync runs at boot, so the roles screen and the badge never disagree about what an agent may do. org.agent.hire is always refused — agents do not hire agents. custom has an empty template, so a custom agent starts with no scopes at all until someone adds permissions to AGENT_CUSTOM through the normal roles screen.
  4. Assigns the role to the badge (snapshotting permissions — the snapshot is the agent’s toolset).
  5. Gives the agent a manager — a reporting edge from the badge to the person who hired it. This is what lets an agent file an approval: the approval line walks the requester’s reporting tree, and an agent with no one above it could never be routed. Move it under someone else on the org chart if the hirer is not the right approver.
  6. Writes the roster row, recording expiresAt (TTL, required, must be in the future) and the ConnectedId of the person who hired it.

The first hire of each kind in an organization takes a little longer than the rest — that is when the role, its permissions and the reporting line are created. The dashboard says so on the hire dialog.

GET /templates returns the preset catalog. Every preset scope is a real entry in the derived permission catalog — nothing invented:

KindWhat it doesWrites?Opens pull requests?
designScreens and branding (HTML/CSS)screensyes
dbTable schemas and queries; reads the dataschemas, queriesyes — migrations
apiKey issuance and webhook wiringkeys, webhooksyes
testScenario verificationnothing — read/list onlyno, by design
infraApp settings and client registrationapp configyes
customPick scopes yourselfstarts with zeroonly if you grant it

A kind is a permission bundle, not an expertise

Section titled “A kind is a permission bundle, not an expertise”

This is the part people most often read backwards. A design agent is not better at design than a db agent — they are the same model. Axowl does not run the model (see Where an agent runs); your runtime does. What a kind changes is what the badge may touch, and that difference is real: a test agent cannot write anything, and that is enforced on the server against its badge, not requested in a prompt. You can say “this agent cannot change our data” and mean it literally.

So pick a kind by blast radius, not by job title. If you want an agent that reads your database and proposes migrations, db is the bundle for that — not because it knows SQL better, but because that is the set of doors its badge opens.

Every kind except custom also carries the employee scopes — org.work_item.list/read and org.reporting_instance.create/read/list. They let an agent see the organization’s approval forms, submit a document and follow its stamps. They are deliberately on test too: submitting a request is asking, not writing. No kind carries org.reporting_instance.approval_step.* — an agent never stamps.

harnessReady: false means the Axowl console cannot drive that kind for you yet — it does not mean the agent is unusable. Every kind is hireable today, and its badge, scopes, TTL, gate and audit trail work the same either way.

Every agent is assigned to a person — its operator. The operator is who the agent borrows authority from: the gate is the intersection of what the badge holds and what that person holds, so an agent can never do more than its operator can.

The person who hires an agent becomes its first operator. PUT /{agentId}/operator hands it to someone else — this is how an admin creates an agent and gives it to the engineer who will actually run it.

Assigning is a transfer of authority, not a label. Two things happen at once:

  • The gate re-clamps to the new operator. If they hold less, the agent can do less, immediately.
  • Existing credentials for that agent are revoked. Whoever held them can no longer drive it. The new operator issues a fresh one. Without this, the previous holder could keep working under the new operator’s authority — the delegation rule inverted.

The transfer is sealed (agent.operator_assigned), so “under whose authority did this machine act” has an answer for every point in time.

Two limits worth knowing:

  • Only a person can be an operator. Machines do not delegate to machines.
  • If the operator’s badge is suspended or deleted, the agent has no delegating user and every gated tool refuses. It does not quietly fall back to whoever issued the key.

An operator can issue their own agent’s credential (POST /{agentId}/credential) without holding organization-wide key permissions — they can create one for the agent assigned to them, and nothing else.

Axowl issues and enforces the authority; it does not require you to run the model here.

  • Your runtime (any kind). The agent’s badge is a machine ConnectedId, so it can obtain an M2M token and call the public API directly. Scope enforcement, denial events and the TTL apply exactly as they do in the console — the gate lives on the server, not in the harness.
  • The Axowl console (kinds with harnessReady: true). For teams with no agent runtime of their own, the console runs the model for you and applies the result through the same gate. Token usage is metered per badge; agents never consume a seat.
  • Tool gate. Every write an agent produces is checked against its badge’s permission snapshot before being applied — the check is server-side, so it holds whether the agent runs in the Axowl console or in your own runtime. A denial is not silent: it is recorded in the reply (“denied — agent lacks org.record_schema.update”) and sealed as an agent.action_denied audit event.
  • An agent can ask, but never approve. Through MCP (axowl_request_permission, axowl_approval_submit) an agent files an approval under its own badge, exactly as a member would from the dashboard; when the last person stamps it, the form’s scopes land on the badge. Two rules are enforced where the approval line is derived, so they hold for any client: a machine requester never self-approves (a form whose risk level would auto-approve for a person is raised so that at least one human in the agent’s reporting line must stamp — if nobody there is capable, the document stays submitted), and stamping itself is a passkey act that only a person can perform. See MCP server.
  • Suspension cuts credentials. Suspending or revoking an agent flips its badge status, which immediately blocks M2M token issuance and console execution.
  • Lifecycle is sealed. agent.hired, agent.suspended (manual or expired via the TTL worker) and agent.revoked are all sealed audit events — a revocation is an append-only fact, not a row someone can quietly delete.
  • Billing. Each console reply row carries the agent’s badge id alongside its token usage, so per-agent cost is a single aggregation over existing metering — agents are billed by usage, never by seats.

See also Service accounts (machine badges for external systems) and Roles & permissions.