FAQ
No FAQs match that search.
FAQ-001PlatformWhat problem does Caracal solve?
Caracal gives agents and automated workflows short-lived, policy-approved authority instead of long-lived credentials. The agent asks for scoped authority at the moment it acts, STS evaluates policy, Gateway or a connector enforces the mandate, and Audit records the decision and result.
See Authority and Enforcement and the Caracal Mental Model.
FAQ-002PlatformIs Caracal an identity provider, secrets manager, or API gateway?
No. Caracal is an authority broker for agent and workload actions. It can sit in front of HTTP resources like a protected Gateway, and it can broker provider credentials, but it does not replace your IdP, your static config store, or your general API management layer.
Use an IdP for human login, a secret manager for static application configuration, and Caracal when an agent or service needs scoped, auditable authority for a resource.
FAQ-003ArchitectureWhat should a zone represent?
A zone should represent a trust boundary: the set of resources, sessions, policies, signing keys, and audit records that are allowed to share authority state. Use a separate zone when two workloads need independent signing keys, policy activation, or audit trails. Use one zone with separate resources when the same trust boundary protects multiple upstreams.
For examples, see Model Your Application in Caracal.
FAQ-004ArchitectureDoes the open-source edition include managed multi-tenancy?
No. The open-source Community Edition gives you zones as a manual isolation primitive. You can model customers, environments, or trust tiers with zones and automate them through the Admin API, but managed tenant, team, SSO, and hosted lifecycle features are Enterprise Edition features.
To serve many of your own customers from one deployment without per-customer zones, see Serve Your Own Customers.
See Compare Editions for the commercial feature boundary.
FAQ-005IdentityWhat is the difference between an application, principal, and agent session?
An application is registered software that authenticates to Caracal. A principal is the acting identity, such as a user, service, or agent. An agent session is a time-bounded execution context spawned from a subject session or application context.
Policy decisions consider all of them: which application is asking, which principal is acting, which session anchors the request, and which resource scopes are requested.
FAQ-006IdentityShould I create one application per agent?
No. This is the most common modeling mistake, and it does not match how Caracal scales. An application and an agent are different layers:
- An application is the credentialed security boundary. It is operator-provisioned (managed) or dynamically registered (DCR), holds a server-owned secret, and is the identity Caracal authenticates. Creating one is a deliberate, secret-bearing act.
- An agent session is the scalable runtime unit. The workload that already holds the application credential creates agent sessions at runtime — no secret, no registration, no Console step. One application backs many concurrent agent sessions (up to 200 per application by default).
The default model is one managed application per durable workload, with many agent sessions under it. When that workload fans out — spawning sub-agents, delegating a narrower slice of authority, or building an agent hierarchy for a single request — each of those is a new agent session under the same application, not a new application. Policy and audit still tell them apart by agent session, lifecycle, labels, and delegation chain (see FAQ-008).
One application per agent breaks this. Managed applications are operator-provisioned, so a workload cannot mint one per spawned agent at runtime. DCR can register at runtime, but a DCR application is meant to expire and bind exactly one session, so per-request fan-out would register and tear down an application for every sub-agent — adding registration latency, credential sprawl, and registry churn for no policy or audit benefit. Reach for an application per agent only when a spawned agent genuinely needs its own isolated, expiring credential and a registry-visible identity; then use a DCR application with one session, as described in FAQ-007.
See Identities and Applications and the Caracal Mental Model.
FAQ-007IdentityWhen should I use a managed application versus DCR?
Use a managed application for durable software you intentionally operate: a backend service, Gateway application, orchestrator, or agent runtime — including the runtime that spawns and fans out child agents. Ordinary spawn fan-out does not need DCR: every spawned child is an agent session under the runtime’s own managed application. Reach for DCR only when an identity needs its own isolated, auto-expiring credential boundary — for example a per-tenant or per-integration identity. DCR applications are registered through the zone DCR endpoint as a control-plane action (the SDK spawn() primitive never registers applications), always expire, and bind exactly one session, so a DCR application is not reused across agents and is not a spawn parent for further sessions.
FAQ-008IdentityIf many agents share one managed application, can policy and audit still tell them apart?
Yes, with one important distinction between attribution and credential isolation.
The agent’s identity in a decision is the agent session, not the application. You do not pre-register agents in the Console; the workload that holds the application credential creates each agent session at runtime and declares its labels then, while the coordinator records the session’s lifecycle (task for an ordinary session, service for a heartbeat-leased one). The token exchange carries the acting agent_session_id, lifecycle, and labels, plus the delegation edge and chain, alongside the application_id. Policy reads these as input.principal.agent_session_id, input.principal.lifecycle, and input.principal.labels, and audit records the same fields with the parent and delegation context. The Console agent list shows the lifecycle and labels of every session, so you can see which agent is which under a shared application. So two agents under one managed application present different sessions, labels, and delegation paths, and both policy and audit can tell them apart without referencing the application.
What is actually enforced is the authority, not the label. Spawning is gated by application ownership, the asserted agent_session_id is bound to the owning application at exchange, and requested scopes must stay within the delegation chain, which is itself bounded by the parent’s authority. The labels, by contrast, are asserted by the credentialed workload and are not delegation-constrained. They are a sound basis for policy and audit when you control and trust the spawner, but they are not a defense against a compromised workload mislabeling its own sub-agents. For that, the boundary is scopes, delegation, and policy.
A single managed application is therefore the right fit for one durable workload that spawns many agents: per-agent attribution comes from the agent session, lifecycle, and labels, not from one application per agent. To investigate a specific agent, the zone audit endpoint filters directly by agent_session_id (one exact session) or by label (a role across a fleet). Reach for a DCR application per agent only when a spawned agent needs its own isolated, expiring credential and a registry-visible identity. What that buys you is credential isolation, not additional policy or audit distinguishability.
See Identities and Applications and Model Your Application in Caracal.
FAQ-009ResourcesWhat is the difference between a resource and a provider?
A resource is the protected target and policy audience: the thing a mandate authorizes access to. A provider describes how Gateway authenticates upstream: no credential, Caracal mandate, OAuth, API key, or bearer token.
Keep target identity, scopes, upstream URL, and Gateway binding on the resource. Keep secrets, token endpoints, OAuth settings, API keys, and bearer tokens on the provider.
FAQ-010ResourcesWhy must the resource identifier stay stable if the upstream URL can change?
Policies, grants, mandates, and audit records refer to the resource identifier. If you use a mutable deployment hostname as the identifier, changing infrastructure also changes your authority boundary and breaks audit continuity. Use a stable audience URI such as resource://billing, then change the upstream URL when routing changes.
FAQ-011ResourcesHow should I design scopes?
Use small action-oriented scopes such as payments:read, tickets:comment, or mcp:tool:call. Do not encode environment, tenant, user, or hostname into scope names when that data belongs in the zone, principal, resource, or policy input.
Scopes answer “what action is allowed?” Resource identifiers answer “what target is protected?”
FAQ-012ResourcesDo I manage grants directly?
In the current Console flow, you usually define resources, scopes, applications, subjects, and policies rather than managing grants as a separate daily object. Grants are an authorization input that policy can read; the active policy set still makes the final allow, deny, or step-up decision.
If access is denied, inspect the active policy, subject, application, resource, and scopes through request trace.
FAQ-013SecurityIs an application secret the same as a provider credential?
No. An application secret authenticates the application to Caracal. A provider credential authenticates Gateway or STS to an upstream provider such as Google, Slack, OpenAI, or an internal API. Agents should authenticate to Caracal and receive short-lived mandates; they should not receive long-lived provider credentials.
FAQ-014SecurityWhen should I use per-user OAuth instead of a shared provider credential?
Use per-user OAuth (oauth2_authorization_code) when the upstream call must act as a specific user and that user must consent. Use a shared service credential (oauth2_client_credentials, api_key, or bearer_token) when the agent acts as the application or service, not as an individual user.
The concrete setup fields are in Provider Recipes.
FAQ-015RuntimeWhy are zone and policy commands in the Console instead of the caracal CLI?
caracal CLI?The top-level caracal CLI is intentionally limited to local runtime lifecycle and process execution: up, down, status, purge, run, and console. Product-management workflows such as zones, applications, providers, resources, policies, audit, diagnostics, agents, and delegation live in the Console, Admin API, and SDKs so they use one management surface and do not drift into duplicated CLI commands.
FAQ-016OperationsWhat is the difference between a 403 from STS and a 403 from Gateway?
A 403 from STS means the exchange was authenticated but policy did not allow the requested resource scopes, or a step-up/grant/session condition blocked issuance. A 403 from Gateway or a verifier means the request reached a protected boundary but the mandate, resource binding, scope check, revocation state, or route safety check failed.
Use request trace with the request ID to identify the surface before changing policy or resource configuration.
FAQ-017OperationsWhere is the diagnostic bundle or doctor command?
The diagnostic bundle is exposed through existing surfaces instead of a separate top-level command. Use caracal status —json for runtime status, Console diagnostics for Doctor checks (health, readiness, zones, preflight), audit for recent decisions, and request trace for a known request ID.
FAQ-018OperationsWhy is an audit event missing?
First confirm the request reached a Caracal-protected boundary. If it did, check the selected zone, time window, request ID, Audit service readiness, Redis stream health, replay backlog, and DLQ. If the request failed before STS, Gateway, Coordinator, or a connector emitted evidence, there may be no action-result event for that boundary.
Start with Inspect Diagnostics and Audit and Debug Infrastructure Issues.
FAQ-019EditionsWhich features are Enterprise Edition only?
Managed multi-tenancy, hosted management UI, managed Gateway and service operation, SSO, SCIM provisioning, teams, organization-level RBAC, commercial support, and enterprise lifecycle features are Enterprise Edition features. The Community Edition remains self-hosted and uses zones, Admin API automation, Console workflows, SDKs, and connectors.
FAQ-020IdentityTwo agents share the same application and labels — how do I tell which one acted?
Every agent has exactly one canonical identity: the server-minted agent_session_id. It is unique, returned to the caller the moment spawn() or service() creates the session, and stamped onto every token exchange and audit event that session produces. That id — not the application, lifecycle, or labels — is the answer to “which agent did this?”. Even two sessions that share the same application, labels, and metadata are still separated by their agent_session_id in audit.
Identical sessions are interchangeable on purpose. A hundred [“pricing-worker”] sessions fanned out under one application are meant to be fungible — that is how fan-out works, and it is why labels are a descriptor rather than a unique name. When you need to tell sessions apart by meaning rather than by raw id, give them distinguishing labels, attach business correlation in metadata, or propagate a trace_id through the work.
To investigate, the zone audit endpoint filters directly on these fields: query agent_session_id to follow one exact session end to end, or label to scope to a role across a whole fleet of sessions. The Console audit view exposes both filters.
To see the sessions themselves — including ones that have ended — the management API exposes GET /v1/zones/{zone}/agent-sessions, filterable by status (active, suspended, terminated, expired), lifecycle, label, parent_id, and application_id. Rows are never deleted on termination — a session keeps its row and its status flips to terminated or suspended — so this is the authoritative place to review past agents. Add format=csv to the same endpoint to export the filtered set for offline analysis.
FAQ-021SecurityA spawned agent inherits its application’s policy and also carries a grant — which wins?
Both apply, and they compose as a strict intersection — a logical AND — so the narrower of the two always wins. They are two independent layers with different jobs: a grant (the delegation edge a narrowing spawn(grant=…) creates) caps which scopes the token may carry at all, while policy decides whether the action is allowed. Neither layer can ever add authority; each one can only subtract.
At token exchange a resource is released only if it passes every gate: the requested scopes must be within the resource’s own scopes, within the grant edge’s scopes (which is itself re-validated to be within the parent’s authority), the resource must fall inside the delegation, and policy must return allow. The effective authority is therefore policy ∩ grant ∩ resource ∩ delegation. This holds in both directions: if policy is the narrower of the two, policy wins and the grant cannot widen past it; if the grant is the narrower, the grant wins, because the token cannot request scopes outside the grant and resources outside the delegation are rejected even when policy would have allowed them.
This means there is no “clash” to resolve when a spawned agent runs under its parent’s application. A plain spawn() carries no grant edge, so the child runs at the application’s full, policy-bounded authority — deliberately identical to the parent, which is what inheriting means. Reach for spawn(grant=Grant.narrow([…])) when the child should hold strictly less; the grant then sub-bounds the authority further while policy continues to apply on top. Because every layer is subtractive, inheriting an application’s policy and carrying a grant can only ever narrow access, never expand it.
See Delegation and Policy.
FAQ-022IdentityIf spawned children inherit the parent’s application, when is a DCR application actually used?
A DCR application is used by authenticating as it, not by spawning under it. Because spawn() always runs under the caller’s own application, a DCR application — bound to exactly one session — cannot be a spawn parent. Its single root session is created by a workload that already holds the DCR credentials.
The credential boundary between durable managed identities and short-lived DCR identities is named by registration_method (managed vs DCR), not by an agent’s lifecycle. A session’s lifecycle is either task (the default) or service (heartbeat-leased), and a DCR application cannot host a service session, so its one session is always a task session. A short-lived worker is therefore not a separate lifecycle — it is an ordinary task session with a TTL (see FAQ-023).
That root session is created by a workload that holds the DCR application’s credentials. The control plane registers the DCR application through the Admin API DCR endpoint, which returns a one-time client secret and a short expiry; the SDK never registers applications. An orchestrator injects those credentials into an independently launched workload — for example a per-tenant container — and that workload, configured with the DCR application_id and secret, authenticates with the client_credentials grant and creates its one root session. The application then expires (one hour or less) and is archived by DCR cleanup.
The credential split is deliberate: minting a new credentialed identity is a privileged control-plane action, so a runtime cannot register applications for itself. The SDK consumes a DCR application by being configured with its credentials; only an operator or orchestrator with Admin API access mints one.
Because a DCR root has no parent and no delegation edge, its authority is decided entirely by policy, not by inheritance — and policy is default-deny, so a DCR identity opens no tools until a policy grants it scopes. Policies receive input.principal.registration_method, so you write one policy class targeting registration_method == “dcr” (optionally narrowed by labels, resource, or zone) that covers every DCR application; you do not author a policy per DCR app. Pair that with per-tenant or per-job resources to keep each DCR identity scoped to its own data.
So DCR has a real, distinct purpose that managed applications do not serve: a per-tenant, per-job, or per-integration identity that is credential-isolated, independently revocable, auto-expiring, and registry-visible. What it does not add is extra policy or audit distinguishability — the agent session already provides that. Reach for DCR when you need an isolated, short-lived credential boundary for an independently launched unit of work; use one managed application with many agent sessions for ordinary spawn fan-out.
See Identities and Applications and FAQ-007.
FAQ-023IdentityHow do I model an orchestrator that spawns managers and short-lived workers, and where does a spawned agent’s authority come from?
This is the mainstream multi-agent shape, and it is modelled under one managed application. Every node is an agent session under that app. A short-lived worker is not a separate lifecycle: a spawned agent is task-scoped — it dies when its block exits — and “least-privilege” is expressed by a narrowed grant. An optional ttl_seconds adds a hard upper bound for the case where the agent should also expire on a clock (see FAQ-025):
- The orchestrator is the durable root session — or a
service()handle when it needs a heartbeat lease. - Each manager is a plain
spawn()that inherits the application’s authority. - Each task worker is
spawn(grant=Grant.narrow([…]))— bounded to a subset of authority and auto-terminated when its block exits — withttl_seconds=…added only when you also want a wall-clock cap.
On where authority comes from: a spawned agent’s authority comes from its application, not from its parent. The SDK authenticates with the client_credentials grant using the configured application_id and secret, so every session under that application already acts under the application’s own authority — which is why spawn() needs no parent and a parentless (root) spawn is well-defined. A parent matters only when you narrow authority: grant=Grant.narrow([…]) creates a delegation edge that the server re-validates as a subset of the parent’s effective authority, and a cross-application grant goes through delegate(to=peer) with receiver consent. With the default grant=inherit and no edge, the child simply shares the application’s authority, bounded by policy.
See Identities and Applications, Delegation, and FAQ-022.
FAQ-024SecurityIf A narrows a grant to B, and B spawns C without narrowing, does C stay bounded by B’s restriction?
Yes — by default. inherit carries the parent’s effective authority forward, so least-privilege is transitive down a same-application spawn tree. Take A spawns B with grant=narrow([tickets:read]), then B spawns C:
- If B spawns C with inherit (the default), the coordinator mirrors B’s delegation edge onto C in the same transaction: a
B → Cedge is recorded holding B’s exact scopes, resource, constraints, and expiry. C is therefore bounded by B’stickets:readslice — it does not regain the application’s full authority. A narrowed intermediary contains its descendants without you having to re-narrow at every hop. - If B spawns C with a narrowing grant, a
B → Cedge is recorded and the coordinator rejects it unlessC ⊆ B(scopes, TTL, hop count, budget, and resource are all checked). So B can never pass on authority it does not hold. - If B is a root session (no inbound edge — it already holds the application’s full authority), an inherit child of B creates no edge and runs under the application’s authority bounded by policy. There is nothing narrower to carry forward, so this is correct, not an escalation.
Transitive inheritance is enforced for same-application spawns, where the mirrored edge is escalation-proof by construction (the child copies the parent edge and can never broaden it). It is not auto-created across applications: a cross-application grant must go through delegate(to=peer) with receiver consent. The hard, server-enforced boundary that contains every session is still the application plus policy (default-deny); to place a subtree behind a real cross-trust boundary, give it a different application via delegate(to=peer).
See Delegation and FAQ-023.
FAQ-025IdentityWhat is the difference between a task and a service lifecycle — and how do I model a task-and-die worker versus a time-limited one?
Every runtime actor is an agent session; lifecycle only describes how it runs. There are two lifecycles, and they map directly onto the two SDK primitives:
- Task — created with
spawn(), recorded aslifecycle = “task”. It lives for the duration of its task: when its block exits it is terminated automatically. This single behavior covers both of the cases you are distinguishing. A “do one task and die” worker (for example a search sub-agent) is justspawn()whose block returns when the task is done. A “live up to N seconds then expire” worker is the samespawn()withttl_seconds=N, which adds a hard wall-clock cap enforced by the TTL sweeper. The difference between “task-and-die” and “time-limited” is whether you set a TTL, not a different lifecycle. - Service — created with
service(), recorded aslifecycle = “service”. It is the genuinely different lifecycle: it outlives any single task and is kept alive by a heartbeat lease, so the runtime can detect and reap it if it stops reporting. Aserviceis governed only by that lease — it is not subject to the wall-clock TTL sweeper that retires tasks, so a faithfully heartbeated service is never terminated on a timer. Eachheartbeat()renews the lease (extends the deadline); it does not just check status. The SDKs offer an opt-in background auto-heartbeat (heartbeat_interval/heartbeatIntervalMs) so the lease stays current even while your code is blocked awaiting a long provider stream.
The stored lifecycle column carries exactly these two values, and only service changes runtime behavior (the heartbeat lease). The default is task — named for the lifecycle, not the actor, so it never collides with the “agent” umbrella that every session already belongs to. So how long a worker lives is expressed by task scope and an optional TTL, not by a separate lifecycle. Reach for service() when you need a durable, heartbeat-leased agent; otherwise use spawn() and let task scope (optionally plus a TTL) express how long the worker should live.
See Identities and Applications and FAQ-023.
FAQ-026IdentityCan two DCR applications have different policies, and can a DCR agent spawn children?
Different policies per DCR app: yes. Policy evaluation receives the full principal, including the specific input.principal.id (the application id), input.principal.labels, and input.principal.registration_method. Matching on registration_method == “dcr” is just the convenient way to write one rule that covers every DCR app; when two DCR apps need different authority, target their distinct application ids or labels, or scope them to different resources. There is no requirement that all DCR apps share a policy.
Can a DCR-application agent spawn children: no, in practice. A DCR application binds exactly one agent session (a second spawn under the same DCR app is rejected with dcr_application_already_bound), so a DCR session cannot create further sessions under its own application — it is a leaf. Spawning a child under a different application would require cross-application spawn authority that a DCR workload is not granted. So a DCR identity is a single, isolated, non-parent session by design.
Which sessions can be parents: any session under a managed application can spawn children via spawn(), with one lifecycle rule — a task parent cannot spawn a service child (task_agent_cannot_spawn_service). A task is bounded by its work or its TTL, so it must not mint a durable, lease-renewable session that could outlive it; a service parent may spawn either lifecycle. The only structural non-parent is the DCR session described above — it can be neither a parent (dcr_application_cannot_spawn) nor a spawned child (dcr_application_cannot_be_child). So the practical answer is that managed sessions spawn (task parents to task children, service parents to either) and DCR sessions are isolated leaves.
See Identities and Applications and FAQ-022.
Next Step
Section titled “Next Step”Use Glossary when you need canonical terms for concepts, API names, Console labels, and examples.

