Governed applications and third party agents
This page explains how the Platform registers an application (an agent application, an assistant, a workflow or a third party agent), deploys its versions only after an approval, gives a third party agent its own identity and suspends it at once when needed.
Domain eai.domains.applications (tables eai.applications, eai.application_deployments,
eai.application_identities, migration sql/postgres/V155, row level security forced). Portal screen:
Agents > Applications (/agents/applications).
Concepts
| Element | Values | Description |
|---|---|---|
kind | agent_app, assistant, workflow, external_agent | Type of application. external_agent always gets the origin third_party. |
origin | internal, third_party | Who built the application. Default internal. |
status | draft, approved, active, suspended, retired | Life cycle. Only an active application can call a tool, an MCP server or a model with its own credential. |
environments | 1 to 10 names, default dev | Environments a deployment may target. |
risk_level | low, medium, high | Declared risk of the application. Default medium. |
agents, tools, mcp_servers, models, plugins | lists of names or glob patterns | Resources granted to the application. A call to a resource that matches no pattern is refused. |
The name has 1 to 128 characters: lowercase letters, digits, ., _ and -, starting and ending with a letter or a digit.
API endpoints
| Route | Roles | Effect |
|---|---|---|
GET /v1/applications | any tenant member | Lists the applications of the tenant, sorted by name. |
POST /v1/applications | tenant_admin, developer, application_owner | Creates an application in draft. Audit application.create. |
GET /v1/applications/{app_id} | any tenant member | Reads an application (id or name) with its deployments. |
POST /v1/applications/{app_id}/deployments | tenant_admin, developer, application_owner | Requests the deployment of a version to an environment and opens an approval application_deployment (approvers tenant_admin, security_officer). |
POST /v1/applications/{app_id}/deployments/{deployment_id}/activate | tenant_admin, developer, application_owner | Activates the deployment once its approval is approved; the previous active deployment of the environment is retired. |
POST /v1/applications/{app_id}/external-agents | tenant_admin | Registers a third party agent: an API key with the role agent, shown once. |
POST /v1/applications/{app_id}/status | tenant_admin, security_officer | Sets suspended or retired with a mandatory reason; active deployments follow. |
Deploy a version
-
Create the application. The registry is the list of what may run and with which resources.
curl -X POST -H "X-API-Key: $EAI_API_KEY" -H 'Content-Type: application/json' \-d '{"name": "invoice-assistant", "kind": "assistant", "environments": ["dev", "prod"], "tools": ["erp.*"], "models": ["gpt-*"]}' \<control-plane-url>/v1/applicationsExpected result:
201with"status": "draft".If it fails:
409 conflictmeans the name is already used in the tenant;403means your role is nottenant_admin,developerorapplication_owner. -
Request the deployment. The deployment is never active on request: it waits for a human approval.
curl -X POST -H "X-API-Key: $EAI_API_KEY" -H 'Content-Type: application/json' \-d '{"version": "1.2.0", "environment": "prod", "reason": "Quarterly release"}' \<control-plane-url>/v1/applications/invoice-assistant/deploymentsExpected result:
201with anapproval_id.If it fails:
400 invalid_requestmeans the environment is not inenvironments;409 conflictmeans this version is already deployed to that environment;409 application_suspendedmeans the application is suspended or retired. -
Approve. A
tenant_adminor asecurity_officerother than the requester decides withPOST /v1/approvals/{approval_id}/decide(portal: Agents > Approvals inbox). The approvals domain enforces the separation of duties.Expected result: the approval is
approved. -
Activate.
POST /v1/applications/{app_id}/deployments/{deployment_id}/activate.Expected result: the deployment is
active,approved_bynames the approver, the application becomesactive.If it fails: an approval that is not approved refuses the activation and writes the audit event
application.deployment.activatewithdenyand the reasonapproval_required.
Third party agents
POST /v1/applications/{app_id}/external-agents creates a service identity bound to the application: an API key
named app:<application>:<name>, with the role agent only, the project of the application and the scopes
tools:invoke, models:invoke plus up to 20 scopes you ask for. The key is returned once in api_key.
Store the key at once in your secret manager: the Platform keeps only its hash and cannot show it again.
At every call made with that key, the Tool Gateway, the MCP Gateway and the Model Gateway call the guard of the
domain (services/control-plane/src/eai/domains/tools/service.py, services/control-plane/src/eai/domains/mcp/gateway.py,
services/control-plane/src/eai/domains/llm/gateway.py):
- application not
active:403 application_suspended, auditapplication.callwithdeny; - resource matching no granted pattern:
403 application_tool_not_granted, auditapplication.callwithdeny.
Suspend an application
POST /v1/applications/{app_id}/status with {"status": "suspended", "reason": "..."} refuses every call of the
application at once and suspends its active deployments. The SOC reaction SUSPEND_APPLICATION uses the same entry
point. retired ends the life of the application.
Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
404 application_not_found | Unknown id or name in the tenant. | Check GET /v1/applications. |
404 application_deployment_not_found | Deployment id unknown for this application. | Read the deployments with GET /v1/applications/{app_id}. |
403 application_suspended on a tool or model call | The application bound to the key is not active. | A draft or approved application becomes active when a deployment is approved and activated. A suspended or retired application refuses new deployments (409 application_suspended) and the status route only accepts suspended and retired: register a new application. |
403 application_tool_not_granted | The resource is not in the granted lists. | Add the name or a pattern to tools, mcp_servers or models of the application. |
Proof: services/control-plane/tests/test_applications_registry.py.