Getting Started: a first secure agent
Version française : ../../fr/guides/getting-started.md
This tutorial takes you from an empty tenant to a first governed agent: you sign in to the portal, create a
project and an API key, scaffold, test and deploy an agent, start a run, approve the action it asks for and follow
its trace. Who: a developer with the tenant_admin role for steps 1 to 3 (or an administrator who does them for
you), then the developer role. Duration: about 30 minutes.
Prerequisites
The Python SDK and the CLI install together; access uses a tenant API key or an OIDC token. The tenant is always resolved from the credential, never from the request body.
pip install -e sdks/python
enterprise-ai login --base-url https://ai.acme.example --api-key eai_...
enterprise-ai doctor
| Need | Check |
|---|---|
| A portal account (Keycloak OIDC or local account) | You can open the portal sign in page. |
Python 3 and pip | python3 --version |
The opa and fga binaries for the authorization tests | opa version, fga version (a missing binary is an error, never a skip) |
| A second person with an approver role for step 8 | The requester never approves its own request. |
The examples use https://ai.acme.example and eai_.... Replace them with the address of your Control Plane and
the key created at step 3. Without --base-url, the CLI reads EAI_BASE_URL, then the active profile.
Tutorial
-
Sign in to the portal. The portal is the console of the Control Plane: every screen you use below calls the same API as the CLI, under your identity.
Screen: open the portal address, then Sign in. With a local account the portal calls POST /v1/auth/login; with Keycloak it follows the OIDC flow of your organization.
Expected result: the Overview page shows the health, usage and spend of your tenant.
If it fails: 401
invalid_credentialsmeans a wrong user name or password; 429account_lockedmeans too many attempts (wait fordetails.retry_afterseconds); 403local_auth_disabledmeans your site only accepts OIDC. -
Create a project. A project groups agents, models and budgets, and every API key, activation and run belongs to one project of the tenant. Each project has the
dev,test,stagingandprodenvironments.Screen: Administration > Projects and environments > New project, give a slug (
support) and a name. API: POST /v1/projects withslugandname(both required).curl -X POST -H "X-API-Key: $EAI_API_KEY" -H 'Content-Type: application/json' \-d '{"slug": "support", "name": "Support"}' https://ai.acme.example/v1/projectsExpected result: the project appears in the list with its environments (GET /v1/projects/{project_id}/environments).
If it fails: 403
forbiddenwithdetails.required_rolesmeans you lacktenant_admin; 409conflictmeans the slug is already taken in the tenant. -
Create an API key. The CLI, the SDKs and your CI authenticate with a tenant key bound to a project and an environment; its scopes cannot exceed yours.
Screen: Administration > API keys > New API key, choose the project
support, the environmentdevand the smallest scope list. API: POST /v1/api-keys (namerequired, plusproject,environment,scopes,roles,expires_in_days).Expected result: the secret
eai_...is displayed once. Copy it into your secret manager, then run theenterprise-ai logincommand of the prerequisites with it;enterprise-ai doctorreports theauthenticationcheck asPASS.If it fails: 403
forbiddenwithdetails.reason: scope_not_heldmeans you asked for a scope you do not hold. At use time, 401invalid_api_keymeans a mistyped key and 401api_key_revokeda revoked one: create or rotate it (POST /v1/api-keys/{key_id}/rotate). -
Create the agent project. The template gives you a valid manifest, its policies and its tests, so the first deployment already passes the gates. The details are in the next section.
Expected result:
enterprise-ai validate -f agent.yamlreports the manifest as valid.If it fails: the CLI lists each schema error with its JSON path; fix
agent.yamland validate again. -
Test then deploy the agent. Deployment goes through the quality gate: an agent that fails its authorization or security tests is never deployed. The commands are in "Test then deploy" below.
Screen: Agents > Registry shows
ticket-helperwith its version and status.Expected result: the agent is listed as active in
dev(enterprise-ai agent inspect ticket-helper).If it fails:
enterprise-ai test authznames the failing OPA or OpenFGA test;enterprise-ai test securityexits with code 1 above the threshold. -
Start a first run. A run is one execution of the agent on a task; it receives a signed ExecutionContext and every model and tool call is checked.
Screen: Agents > Runs > Start run. CLI:
enterprise-ai run start ticket-helper --task "..." --follow. API: POST /v1/agents/{agent_id}/runs with ataskobject.Expected result: the run goes from
pendingtorunning, thensucceeded, or towaiting_approvalwhen an action needs a human decision.If it fails: 409
agent_not_activemeans the agent is suspended or killed (details.status); 429rate_limitedmeans a quota window is full. -
Find the run waiting for an approval. A sensitive action (a write, a payment, a production promotion) pauses the run instead of running unchecked.
enterprise-ai runs list --state waiting_approvalenterprise-ai runs get <run_id><run_id>: identifier printed byrun start.Expected result: the run shows the state
waiting_approvaland the approval it waits for.If it fails: an empty list means no action of the task needed an approval; the run already finished.
-
Approve the action. Separation of duties: a second person with an approver role decides, never the requester.
Screen: Agents > Approvals inbox, open the request, then Approve or Reject. API: POST /v1/approvals/{approval_id}/decide with
{"decision": "approve"}or{"decision": "reject"}and an optionalcomment.Expected result: once the quorum is reached the approval becomes
approvedand the run resumes; a rejection ends the run with the codeapproval_rejected.If it fails: 403
separation_of_dutiesmeans the requester tried to approve; 403forbiddenmeans the approver lacks the required role (details.required_roles); 409approval_closedmeans the request is already decided or expired; 409already_decidedmeans you already voted. -
Watch the trace. The trace proves what the agent did: each step, each model and tool call, each policy decision and its audit event.
enterprise-ai run events <run_id>enterprise-ai logs <run_id>Screen: Agents > Runs, open the run for its steps; Observability > Traces for the spans. API: GET /v1/runs/{run_id}/steps, GET /v1/runs/{run_id}/events and GET /v1/telemetry/traces.
Expected result: the steps list the model calls through the gateway, the tool calls through the Tool Gateway and the approval decision.
If it fails: 404
not_foundon the run means it belongs to another tenant or project than your key.
Create the project
enterprise-ai create agent copies the template sdks/python/src/enterprise_ai/templates/agent-basic: a manifest valid against contracts/v1/agent-manifest.schema.json, OPA policies and their tests, unit tests, AGENTS.md and RULES.md. The secure-agent template is an alias of agent-basic.
enterprise-ai create agent ticket-helper --template secure-agent
cd ticket-helper
enterprise-ai validate -f agent.yaml
Test then deploy
enterprise-ai test authz runs opa test and the OpenFGA model tests (a missing binary is an error), enterprise-ai test security starts a red team run. Deployment goes through the quality gate.
enterprise-ai test authz
enterprise-ai test security --threshold 0
enterprise-ai deploy agent -f agent.yaml --env dev
enterprise-ai run start ticket-helper --task "Summarise this ticket" --follow
What protects the agent
Every model call goes through the gateway (POST /v1/gateway/chat/completions), every tool through the Tool Gateway (POST /v1/tools/{name}/invoke); the run receives a signed ExecutionContext (see ExecutionContext Reference) and every action yields an ActionContext (ActionContext Reference).
Verify
| Check | Command or screen | Expected result |
|---|---|---|
| Profile and connection | enterprise-ai doctor | every check PASS (configuration, connectivity, tls, authentication, versions, clock) |
| Agent deployed | enterprise-ai agent inspect ticket-helper | status active |
| Run finished | enterprise-ai runs get <run_id> | state succeeded |
| Decision recorded | Agents > Approvals inbox | approval approved with two distinct people |
Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
401 invalid_api_key | key mistyped or truncated | copy the key again, run enterprise-ai login --api-key ... |
401 api_key_revoked | key revoked or rotated | create a new key in Administration > API keys |
401 unauthenticated | no credential sent | run enterprise-ai login, or set EAI_API_KEY |
403 forbidden | missing role or scope | ask a tenant_admin for the role named in details.required_roles |
409 agent_not_active | agent suspended or killed | resume it (POST /v1/agents/{agent_id}/resume) once the cause is understood |
403 separation_of_duties | requester approving its own request | have another approver decide |
409 approval_closed | approval already decided or expired | start the run again |
429 rate_limited | quota window full | wait for the window, or review enterprise-ai quotas usage |
Next steps
- Agent Development Guide: manifest, tools, budgets and delegations.
- Testing Guide: functional, security and conformance tests.
- API Reference: the Control Plane API and the Navin Manager API.
- CLI reference: every command and option.