2 · Deploy
Deploying in Brutor is not “get the container running” — that part is yours. Deploying is giving the thing you built its production identity: an AI System entity with exactly the resources it needs, credentials that are scoped to it, a declared owner and intended use, and a lifecycle stage someone accountable signed off on. Everything in Govern, Observe and Assure hangs off what you create here.
All calls in this stage go to the Control Plane Admin API (:5050) with an admin token — or click the same things in the Admin UI. Wrap them in an idempotent setup script so dev, staging and prod are provisioned from code, not memory.
Create the AI System
Section titled “Create the AI System”curl -X POST http://localhost:5050/v1/admin/resource-groups \ -H "Authorization: Bearer $ADMIN_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "name": "support-copilot", "display_name": "Support Copilot", "description": "Answers customer questions, looks up orders, prepares refunds", "group_type": "ai_system", "system_kind": "agent", "parent_group_id": "<customer-success-team-group-id>", "inherit_resources": true }'{ "id": "group-01ABC...", "name": "support-copilot", "group_type": "ai_system", "system_kind": "agent", "inherit_resources": true}Three fields deserve thought:
system_kind—agentis the default; pick honestly (the six kinds), because it selects which lifecycle signals apply. Silence detection pages you usefully for anintegrationand uselessly for anassistant.parent_group_id— place the system under the team that owns it. The parent’s budgets, limits and policies apply to your system automatically (restrictively — a parent can only ever tighten), and the team’s cost roll-ups will include it.inherit_resources—truemeans your system also sees models and tools bound at the parent. Setfalsefor a strictly least-privilege system that should see only its own bindings.
Bind exactly what it needs
Section titled “Bind exactly what it needs”Bind each resource the agent actually uses — this is the permission set, and later it becomes the contract:
G=group-01ABC... # the AI System's id
# Models (bind a routing group? bind the virtual model AND every member)curl -X POST http://localhost:5050/v1/admin/resource-groups/$G/llm-models \ -H "Authorization: Bearer $ADMIN_TOKEN" -H "Content-Type: application/json" \ -d '{"llm_model_id": "<model-id>"}'
# MCP servers (the CRM the agent reads orders from)curl -X POST http://localhost:5050/v1/admin/resource-groups/$G/server-configs \ -H "Authorization: Bearer $ADMIN_TOKEN" -H "Content-Type: application/json" \ -d '{"server_config_id": "<crm-server-config-id>"}'
# A2A peers (the billing agent it delegates to) — PUT replaces the full setcurl -X PUT http://localhost:5050/v1/admin/resource-groups/$G/agent-cards \ -H "Authorization: Bearer $ADMIN_TOKEN" -H "Content-Type: application/json" \ -d '{"agent_card_ids": ["<billing-agent-card-id>"]}'Skills and knowledge bases bind the same way (Admin UI → Resource Groups → your system → Resources → Skills / Knowledge Base). Models are the exception in the UI: access is set on the model, under Resources → AI Models → Configuration → Edit → Access Control (why). Binding POSTs return 409 on repeat — provisioning scripts treat that as “already there”.
Verify the effective result — what the system actually resolves to, inheritance included:
curl http://localhost:5050/v1/admin/resource-groups/$G/effective-llm-models \ -H "Authorization: Bearer $ADMIN_TOKEN"Mint its credentials
Section titled “Mint its credentials”Two options, and mature deployments use both:
An API key bound to the system — the simplest production credential. The key is the governance scope: any process holding it executes inside support-copilot, its resources, limits and audit trail.
curl -X POST http://localhost:5050/v1/admin/resource-groups/$G/api-keys \ -H "Authorization: Bearer $ADMIN_TOKEN" -H "Content-Type: application/json" \ -d '{"name": "support-copilot-prod"}'The plaintext is returned once — put it straight into your secret manager.
An agent identity — when you want the agent to be a first-class principal with per-action grants rather than a bearer of a group key. Identity is anchored on your IdP (Okta, Entra Agent ID, SPIFFE); the gateway maps the workload token to the agent and applies default-deny grants:
curl -X POST http://localhost:5050/v1/admin/agent-identities \ -H "Authorization: Bearer $ADMIN_TOKEN" -H "Content-Type: application/json" \ -d '{"name": "support-copilot", "owner_label": "Customer Success", "idp_server_id": "<idp-id>", "idp_subject": "spiffe://acme/ns/agents/support-copilot"}'Then add the identity to the AI System’s memberships so the group’s stack applies to it. You’ll write its grants (allow / deny / approval-required per action) in Govern; start in dry_run mode. Full model: Agent identity & policies.
Declare what it is for
Section titled “Declare what it is for”The fields that make the system governable by people — owner, intended use, autonomy, risk tier — live on the AI System and are required evidence at the gate below. Set them in the Admin UI on the system’s Lifecycle tab (the open gate offers the owner and intended-use fields inline), under Resource Groups → Support Copilot → General → Ownership & Purpose, or via PATCH /v1/admin/resource-groups/{id}:
- Owner — the accountable human, not a team alias someone will rotate out of.
- Intended use / intended clients — what it’s for and what should be calling it. Conformance later compares these declarations against observed traffic — an undeclared caller on a high-risk system is the finding a risk owner reads first.
- Autonomy level —
autonomous,approval_required,restrictedorsuspended. Resolves min-wins with the hierarchy; you can tighten it automatically on drift later. - EU AI Act risk tier —
highadds a named-human-approver floor to every lifecycle transition.
Pass the gate
Section titled “Pass the gate”An AI System moves proposed → approved → active → deprecated → retired, and each forward transition demands evidence. In the Admin UI this is the Lifecycle tab — the default tab when you open a system: a stage diagram with the current stage marked, the open gate listing each requirement as satisfied or missing, and a button per requirement that does the thing (mint the contract, set the owner, approve, set liveness). The API below is the same gate. First, mint the contract — the hash-pinned snapshot of everything you just configured, generated from live config (never hand-written):
curl -X POST http://localhost:5050/v1/admin/ai-systems/$G/contracts \ -H "Authorization: Bearer $ADMIN_TOKEN"Then ask the gate what it needs — every reachable stage with each requirement marked satisfied or missing:
curl http://localhost:5050/v1/admin/ai-systems/$G/lifecycle \ -H "Authorization: Bearer $ADMIN_TOKEN"| Transition | Requires |
|---|---|
proposed → approved |
A contract minted for the current config; an owner; intended use |
approved → active |
The contract still current; an approver recorded on it; a liveness decision; the bound replay suite passed — satisfied, and said to be, while no suite is bound yet, refused if the bound suite is disabled or marked not replayable |
active → active (re-attest) |
No unapproved widening of permissions since the last approved contract |
active → deprecated |
A successor named, or “no successor” stated explicitly |
deprecated → retired |
No runs for the quiet period (30 days) |
Have the approver approve the contract (POST /v1/admin/contracts/{id}/approve, or Contract → Active → Approve in the Admin UI), make the liveness decision — for support-copilot, on_demand is right; a nightly pipeline would pick scheduled — and transition:
curl -X POST http://localhost:5050/v1/admin/ai-systems/$G/lifecycle \ -H "Authorization: Bearer $ADMIN_TOKEN" -H "Content-Type: application/json" \ -d '{"to_stage": "approved"}' # then: {"to_stage": "active"}Every transition is recorded with who approved it and who recorded it. The approver defaults to the admin making the call; pass approved_by only when someone else signed off (a risk committee, a paper approval) — the Lifecycle tab has an on behalf of field for the same purpose. The recorder is always the authenticated session and cannot be overridden, so “who let this system through” is answerable from the tab’s history, not from memory. A high EU AI Act risk tier adds a named-human-approval requirement to every transition on top of this.
Point production at it, and script it
Section titled “Point production at it, and script it”Deploy your agent process wherever it runs, with two things in its environment: the gateway URL and the production credential. If you built Develop faithfully, nothing else changes — same code, new key, and the run ledger starts on day one.
Finally: everything on this page should live in a re-runnable script per environment. The setup-script guide shows the idempotency pattern (create-or-409, capture plaintext keys once, verify effective views at the end).

