Skip to main content
Infrastructure is judged on its failure modes, not its definitions, so each entry below is a property followed by the failure it removes, and the limits get the same treatment as the guarantees.

Decisions fail closed

An agent with no active policy denies everything, with the rule no_policy. The three intrinsic rules do not count as a policy. An agent also arrives with an active starter policy unless you ask for it not to, so the default path never passes through no_policy at all. What this removes: the window between creating an agent and writing its rules, during which a misconfigured agent would otherwise have unlimited authority. The common failure in policy-engine deployments is a default-allow gap at setup time. There is none here, in either direction: an agent with no rules refuses, and an agent you have not got to yet already has some.

The first denial wins, and cannot be overridden

Rules are evaluated in a fixed order: intrinsic rules, then each active policy oldest first, with imported modules ahead of a policy’s own rules. The first denial short-circuits the entire evaluation. What this removes: a permissive rule silently re-enabling something a stricter rule refused. An allow never overrides a deny, and a require_approval never converts a denial into a question for a person. Rule order cannot produce a weaker outcome than the strictest rule that matched.

Scopes are checked before policy

An agent key carries an action-type allowlist enforced by an intrinsic rule, so a request outside it is refused as runtime_scope before any policy is consulted. What this removes: a policy misconfiguration granting an agent authority over action types it was never issued for. Scope is a property of the credential, not of the rules attached to it.

Reservations are released, not stranded

Budget is reserved when an action is authorized or held, and released when it fails, is denied, or its approval is refused. What this removes: budget stranded by an action that was refused, failed, or turned down by a person. What it does not remove: an intent left pending because nobody called complete or fail holds its reservation for good. A budget has no expiry and no close endpoint, so nothing sweeps that up later. Reporting the outcome is part of the contract.

Replay returns the original decision, not a new one

Each (agent, idempotency_key) maps to exactly one intent forever. A replay returns the stored intent and the stored decision, at the original HTTP status. What this removes: a retry under network failure double-reserving budget, and a retry after a policy change silently getting a different answer than the one already acted on. The decision is the record, not a recomputation. The key is matched on its own, though. Reuse one with a different amount and you get the first decision back, not an error, so the key has to be as specific as the action it stands for.

Concurrent spend contends without queueing

A budget is claimed with a single conditional update rather than a lock. What this removes: both the race where parallel sub-agents each read sufficient budget and both succeed, and the serialization bottleneck that a lock would impose on a fan-out. Exactly one claimant wins each contested update. The same applies to spend tokens: if two payments cite one token at once, exactly one consumes it, and the loser releases its reservation and fails with spend_token_unusable.

Every decision is recorded, including refusals

A denied action still writes an intent, in state denied, alongside an audit event. The audit log is append-only and rejects deletion at the model layer. What this removes: “we don’t know what it tried to do.” A refusal that leaves no trace is a refusal you cannot audit, and the interesting question after an incident is usually what the agent attempted, not what it completed. Every role can read the audit trail, including member.

The ledger is never in the authorization path

Where a workspace has the ledger enabled, reservations are mirrored into it asynchronously. What this removes: a slow, unavailable, or absent ledger delaying or changing a decision. A projection can lag; it can never gate. Authorization behaves identically on a workspace with no ledger at all. The gap is observable as unprojected_cents on the workspace funds endpoint.

Revocation is not retroactive

Suspending or revoking an agent stops new authorizations. It does not rewrite decisions already made, and it does not invalidate a cosignature already issued. What this removes: nothing. This is a limit, stated so you can size it. A cosignature’s default lifetime is five minutes, so revoking a compromised agent leaves at most that window in which an already-issued signature still verifies offline. If that window matters to you, verify through POST /control/v1/cosign/verify rather than locally: it re-checks the intent’s state and will report already_settled for anything spent.

Test and live never mix

Every credential is bound to one mode. Keys are prefixed krt_test_ or krt_live_, and a test key cannot reach live data. What this removes: a load test or a demo consuming real budget or producing real payments.

What Kordio does not guarantee

A control layer that overclaims is worse than one that does not exist, so here is what this one will not do for you.

It cannot govern a path that does not ask

Kordio holds no funds, no accounts, and none of your credentials. An executor that never calls us and never verifies a cosignature is not governed by us, no matter what your policy says. The control layer binds the paths you route through it, and the completeness of that routing is your responsibility, not ours.

It has no opinion on what you do when we are unreachable

If the authorize call times out, nothing on our side decides what happens next. Your code does. Fail closed: treat a transport failure as a refusal and do not execute. That is the only choice consistent with having a control layer at all. An agent that spends whenever Kordio is unreachable has a control layer exactly as long as the network is up. Retry with the same idempotency key, which is safe by construction: if the original request did land, you get the original decision back rather than a second reservation.

A cosignature proves authority was granted, not that it is unused

Offline verification checks the signature, the claims, and the expiry. It cannot see settlement state. If double-execution is a risk in your architecture, verify through the endpoint, which re-loads the intent and refuses anything already settled.

Simulation is not free of side effects

POST /control/v1/agent/actions/simulate creates no intent and reserves no budget, but it does write an action.simulated audit event. Policy previews on the dashboard side write nothing at all, so use those if you need a genuinely silent evaluation.

Next steps

How a decision is reached

The evaluation order these properties come from.

Where the ledger fits

What the projection promises, and what it does not.