Skip to main content

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
NeedCheck
A portal account (Keycloak OIDC or local account)You can open the portal sign in page.
Python 3 and pippython3 --version
The opa and fga binaries for the authorization testsopa version, fga version (a missing binary is an error, never a skip)
A second person with an approver role for step 8The requester never approves its own request.
note

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​

  1. 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_credentials means a wrong user name or password; 429 account_locked means too many attempts (wait for details.retry_after seconds); 403 local_auth_disabled means your site only accepts OIDC.

  2. 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, staging and prod environments.

    Screen: Administration > Projects and environments > New project, give a slug (support) and a name. API: POST /v1/projects with slug and name (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/projects

    Expected result: the project appears in the list with its environments (GET /v1/projects/{project_id}/environments).

    If it fails: 403 forbidden with details.required_roles means you lack tenant_admin; 409 conflict means the slug is already taken in the tenant.

  3. 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 environment dev and the smallest scope list. API: POST /v1/api-keys (name required, plus project, environment, scopes, roles, expires_in_days).

    Expected result: the secret eai_... is displayed once. Copy it into your secret manager, then run the enterprise-ai login command of the prerequisites with it; enterprise-ai doctor reports the authentication check as PASS.

    If it fails: 403 forbidden with details.reason: scope_not_held means you asked for a scope you do not hold. At use time, 401 invalid_api_key means a mistyped key and 401 api_key_revoked a revoked one: create or rotate it (POST /v1/api-keys/{key_id}/rotate).

  4. 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.yaml reports the manifest as valid.

    If it fails: the CLI lists each schema error with its JSON path; fix agent.yaml and validate again.

  5. 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-helper with 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 authz names the failing OPA or OpenFGA test; enterprise-ai test security exits with code 1 above the threshold.

  6. 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 a task object.

    Expected result: the run goes from pending to running, then succeeded, or to waiting_approval when an action needs a human decision.

    If it fails: 409 agent_not_active means the agent is suspended or killed (details.status); 429 rate_limited means a quota window is full.

  7. 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_approval
    enterprise-ai runs get <run_id>

    <run_id>: identifier printed by run start.

    Expected result: the run shows the state waiting_approval and the approval it waits for.

    If it fails: an empty list means no action of the task needed an approval; the run already finished.

  8. 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 optional comment.

    Expected result: once the quorum is reached the approval becomes approved and the run resumes; a rejection ends the run with the code approval_rejected.

    If it fails: 403 separation_of_duties means the requester tried to approve; 403 forbidden means the approver lacks the required role (details.required_roles); 409 approval_closed means the request is already decided or expired; 409 already_decided means you already voted.

  9. 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_found on 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​

CheckCommand or screenExpected result
Profile and connectionenterprise-ai doctorevery check PASS (configuration, connectivity, tls, authentication, versions, clock)
Agent deployedenterprise-ai agent inspect ticket-helperstatus active
Run finishedenterprise-ai runs get <run_id>state succeeded
Decision recordedAgents > Approvals inboxapproval approved with two distinct people

Troubleshooting​

SymptomCauseFix
401 invalid_api_keykey mistyped or truncatedcopy the key again, run enterprise-ai login --api-key ...
401 api_key_revokedkey revoked or rotatedcreate a new key in Administration > API keys
401 unauthenticatedno credential sentrun enterprise-ai login, or set EAI_API_KEY
403 forbiddenmissing role or scopeask a tenant_admin for the role named in details.required_roles
409 agent_not_activeagent suspended or killedresume it (POST /v1/agents/{agent_id}/resume) once the cause is understood
403 separation_of_dutiesrequester approving its own requesthave another approver decide
409 approval_closedapproval already decided or expiredstart the run again
429 rate_limitedquota window fullwait for the window, or review enterprise-ai quotas usage

Next steps​