Environment Settings
Environment settings are configuration that applies to a whole environment (one account and environment pair), rather than to a single agent. They are grouped into sections, each identified by a namespace key. Each section is read and replaced as a unit.
Today there is one section, passport, which sets the Agent Passport policy for the environment. More sections may be added later. They will use the same endpoints, permissions and audit event.
Environment settings are an administrator responsibility. The permissions are granted to the Agent Builder Administrator role.
| Permission | Allows |
|---|---|
cin-agent-builder.environment-settings.read | Every endpoint that changes nothing: listing sections, reading a section, and the impact preview. |
cin-agent-builder.environment-settings.edit | Replacing a section (PUT). |
edit does not include read. A client that reads a section before replacing it needs both.
Endpoints
| Method | Path | Permission | Description |
|---|---|---|---|
GET | /v1/environment-settings | read | List every section, with its current or default value. |
GET | /v1/environment-settings/{namespace} | read | Get one section and its ETag. |
GET | /v1/environment-settings/{namespace}/impact | read | Preview what each value would do, before changing it (sections that support it). |
PUT | /v1/environment-settings/{namespace} | edit | Replace one section. Requires If-Match. |
A section that has never been set is returned with its default value, revision: 0 and source: "DEFAULT". A section that has been set has source: "OVERRIDE". Responses are never cached (Cache-Control: no-store).
Reading a section
GET /v1/environment-settings/passport
Example response:
{
"namespace": "passport",
"properties": {
"passportMode": "REQUIRED_FOR_NEW"
},
"revision": 4,
"source": "OVERRIDE",
"updatedAt": "2026-10-02T14:05:11Z",
"updatedBy": "8c1f0a8e-..."
}
The response carries an ETag header, for example "passport-v2-4". Treat it as opaque and send it back exactly as received when you replace the section. Comparison is strict: a tag the server didn't issue never matches, even if it looks equivalent (for example "passport-v2-04").
Replacing a section
PUT /v1/environment-settings/passport
If-Match: "passport-v2-4"
Content-Type: application/json
{ "passportMode": "REQUIRED_FOR_ALL" }
If-Match protects against lost updates. If someone else changed the section since you read it, the write is refused with 412 Precondition Failed, and the response's ETag is the current one. Read the section again, check it, and retry with the new ETag.
If-Match: * replaces the section unconditionally, whatever its current revision. It gives up lost-update protection, so use it only for break-glass automation.
The body is the whole section. Fields you leave out are not kept from the old value, and an empty body {} is rejected.
| Status | Meaning |
|---|---|
200 | Section replaced. The body's revision is the new revision. |
400 | Invalid body, or a malformed If-Match. |
403 | Caller lacks environment-settings.edit. The body is {"detail": "..."}. |
404 | Unknown namespace. |
412 | If-Match didn't match the current revision. |
428 | If-Match is missing. |
503 | Writes are not yet activated in this deployment, the section is busy, or the database is unavailable. Retry later. |
Every successful change is recorded in the audit trail as a cin-agent-builder.environment-settings.updated event. The event records the section's settings before and after the change, the new revision, and who made it. Because every value goes into the audit trail, settings never hold secrets.
Passport policy (passport section)
The passport section has one setting, passportMode. It decides which agents need an issued Agent Passport before they can be invoked.
passportMode | New agents and versions | Existing agents without a passport | Agents with a passport |
|---|---|---|---|
DISABLED (default) | No passport is requested. | Invocable. | Invocable. Passports are not checked. |
REQUIRED_FOR_NEW | Each new agent or version requests a passport, and can't be invoked until it is approved. | Still invocable (grandfathered). | Invocable only while the passport is issued and not expired. |
REQUIRED_FOR_ALL | As for REQUIRED_FOR_NEW. | Refused until a new version gets an approved passport. | Invocable only while the passport is issued and not expired. |
Global agents (platform-provided agents shared across tenants) are exempt in every mode, including REQUIRED_FOR_ALL. They are never refused for passport reasons. A copy of a global agent made in your tenant is a tenant agent and follows your policy.
Agents that use other agents
A topology manager's experts and a tool agent's task-agent tools are checked against the same policy when the agent is invoked. If any one of them is refused, the whole invocation is refused, and the error names the agent that caused it.
This applies at every depth: a task agent used as a tool that itself has task-agent tools has those checked too, before anything runs. A chain of task-agent tools that calls back into itself, or that is nested more than 5 deep (by default), is refused with 400.
One invocation may also embed at most 160 task agents in total (by default), counted across the agent and all of its experts, every use of a shared task agent counted separately. For example, an agent whose 5 task agents each use 5 more, which each use 5 more, embeds 5 + 25 + 125 = 155. Their configurations may total at most 8 MiB (a provisional default). Exceeding any of these limits is refused with 400 before anything runs. All three are deployment settings, so your platform operator may have set different values. These limits apply whatever the passport mode.
References to other agents are pinned to a specific version when the agent is saved. To choose the version a task-agent tool runs, send its agentVersionId. If you omit it, the version in the deprecated agentVersion is used, or the current version when that is latest or absent; either way the saved agent returns the resolved agentVersionId. Sending agentVersionId and an agentVersion UUID that name different versions is rejected with 400.
An agent saved before pinning existed may still reference another agent by latest. Under REQUIRED_FOR_NEW or REQUIRED_FOR_ALL, such an agent is refused with PASSPORT_REFERENCE_UNPINNED. Save a new version of it to pin its references.
Refusals
A refused invocation returns 403 with a machine-readable errorCode:
{
"status": 403,
"error": "Forbidden",
"message": "This environment requires an Agent Passport for every agent, and this agent has none. Create a new version to request one.",
"errorCode": "PASSPORT_REQUIRED"
}
errorCode | Meaning | What to do |
|---|---|---|
PASSPORT_REQUIRED | REQUIRED_FOR_ALL, and the agent has never had a passport. | Create a new version, then have it approved. |
PASSPORT_NOT_PROVISIONED | This version has no passport, but the agent has one on another version. | Create a new version, then have it approved. |
PASSPORT_PENDING_APPROVAL | The passport is waiting for approval. | Ask a Governance Officer to approve it. |
PASSPORT_ISSUANCE_FAILED | The version was approved, but its passport could not be issued. | Retry the approval. |
PASSPORT_REJECTED | The passport was rejected. | Address the reason for the rejection, then create a new version. |
PASSPORT_REVOKED | The passport was revoked. | Create a new version, then have it approved. |
PASSPORT_SUSPENDED | The passport is suspended. | Ask a Governance Officer to unsuspend it. |
PASSPORT_EXPIRED | The passport's expiry date has passed. | Have it approved again. |
PASSPORT_REFERENCE_UNPINNED | The agent references another agent by latest. | Save a new version of the agent. |
Treat any 403 from an invocation endpoint as a refusal, even if it has an errorCode you don't recognize. New codes may be added. A 403 because the caller lacks a permission has a different body, {"detail": "..."}, with no errorCode.
Previewing a change
Before changing the mode, check what it would do:
GET /v1/environment-settings/passport/impact
Example response:
{
"observedAt": "2026-10-02T14:10:00Z",
"settingsRevision": 4,
"settingsEtag": "\"passport-v2-4\"",
"configuredMode": "REQUIRED_FOR_NEW",
"effective": true,
"effectiveMode": "REQUIRED_FOR_NEW",
"tenantAgentCount": 42,
"breakdown": {
"PASSPORT_REQUIRED": 30,
"PASSPORT_PENDING_APPROVAL": 2
},
"refusedUnder": {
"DISABLED": 0,
"REQUIRED_FOR_NEW": 2,
"REQUIRED_FOR_ALL": 32
},
"currentlyRefusedCount": 2,
"transitions": {
"DISABLED": { "newlyRefused": 0, "readmitted": 2 },
"REQUIRED_FOR_NEW": { "newlyRefused": 0, "readmitted": 0 },
"REQUIRED_FOR_ALL": { "newlyRefused": 30, "readmitted": 0 }
}
}
(breakdown lists every refusal code; the zero counts are left out above.)
| Field | Meaning |
|---|---|
tenantAgentCount | Your tenant's agents. Global agents are not counted, because they are exempt. |
breakdown | How many agents would be refused, by refusal code. |
refusedUnder | How many agents each mode would refuse. |
transitions | For each mode: how many agents switching to it would newly refuse or newly allow, compared with today. |
effective | false when Agent Passport isn't enabled in this deployment. The mode is stored but not enforced, and effectiveMode is DISABLED. |
settingsEtag | Send this as If-Match on the PUT. The write then fails with 412 if the section changed after the preview. |
The preview is a snapshot. Agents can change between the preview and your PUT. It counts each agent on its own: a manager whose expert is refused shows as allowed, but its invocations are refused.
Recommended way to change the passport mode
GET /v1/environment-settings/passport/impactand reviewtransitionsfor the target mode.PUT /v1/environment-settings/passportwith the new mode andIf-Matchset tosettingsEtagfrom step 1.- On
412, someone else changed the section: start again from step 1.
Moving from REQUIRED_FOR_NEW to REQUIRED_FOR_ALL immediately refuses every tenant agent that has never had a passport (PASSPORT_REQUIRED). Plan that change with the agents' owners.