Action Fabric

Let agents take real action — without taking real risk.

Every action an agent can take is a first-class governed object: a named action with a risk tier and approval policy, plus an immutable invocation ledger that records dry-run → propose → approve/deny → execute → compensate with an evidence pack on every step.

dry-run → propose → approve/deny → execute → compensate · fail-closed

Action Fabric
Dry-run
Refund $240
risk: low · evidence
Proposed
Close case #4471
risk: med · evidence
Pending approval
Payout $5,000
risk: high · evidence
Executed
Email customer
risk: low · evidence
actions ▸ dry-run → propose → approve → execute → compensate
Actions as governed objects

A tool call is a wish. A governed action is accountable.

Ungoverned agents call tools directly — no risk tier, no approval, no record of what ran or how to undo it. In Cortex, every action is registered with a risk level and approval policy, and every invocation lands in an append-only ledger. High-risk and approval-required actions never execute until an admin approves them; denied actions never execute at all.

Named & registered

Each action — refund.issue, payout.send, close.case — is a registry entry with a key, an input schema (required keys), a riskLevel, and a requiresApproval flag.

Risk-tiered

riskLevel: high or requiresApproval routes the invocation to pending_approval; low-risk actions execute immediately. Risk is a property of the action, not a hope.

Immutably logged

Every dry-run, proposal, approval, denial, execution and compensation appends to cortex_action_invocations — an evidence trail you can hand an auditor.

Reversible

Declare a rollbackKey and any executed action can be compensated — the runtime runs the compensating action and marks the original compensated.

The problem it solves

The moment an agent can write, your exposure changes.

Read-only agents are easy. The risk arrives when an agent issues a refund, closes a case, or sends a payout. Without a fabric between intent and effect, you are trusting a model with side effects — no approval gate for the $5,000 payout, no record of what executed, and no way to roll it back. Action Fabric puts a deny-by-default governance layer between the proposal and the side effect.

High-risk actions land in pending_approval — never auto-executedeny → recorded as denied, the executor is never calledcompensate → declared rollbackKey reverses an executed action
The lifecycle

From proposal to provable effect — and back.

Every invocation walks the same five-state lifecycle. Each transition appends to the ledger with its evidence pack, so the full story of any side effect is reconstructable after the fact.

  1. 01

    Dry-run

    Validate the input against the action's required-keys schema. No side effect runs — it is a safe rehearsal that proves the call is well-formed before anything happens.

  2. 02

    Propose

    Submit the action for real. riskLevel: high or requiresApproval actions land pending_approval; everything else executes immediately under policy.

  3. 03

    Approve / Deny

    Admin-only, AdminGuard-gated. Approve runs the governed executor; deny records denied with a reason and the executor is never called.

  4. 04

    Execute

    The governed executor emits ActionExecuted or ActionFailed (P4 events). The P7 adapter rule keeps mocks out of production unless explicitly allowed.

  5. 05

    Compensate

    Admin-only. If the action declares a rollbackKey, the runtime runs the compensating action and marks the original compensated — a clean, audited undo.

Provenance

Every action links back to who asked.

01 · Humanrisk-ops@nw02 · AgentFraud Triage03 · Skilltriage.v404 · Promptsha 0x3a…05 · Policyapprove≥5k06 · Modelclaude-opus07 · ToollookupCase08 · Artifactmemo #447109 · Outcomeapproved10 · Approvalj.lee
What's in the fabric

Registry, ledger, executor, and the gates between them.

Action registry
  • Named action keys
  • Input schema (required keys)
  • riskLevel: low / med / high
  • requiresApproval flag
  • Optional rollbackKey
Invocation ledger
  • Append-only invocations
  • Per-step evidence pack
  • dry-run → … → compensate states
  • Tenant-scoped reads
  • Hand-an-auditor trail
Approval inbox
  • pending_approval queue
  • Admin-only approve / deny
  • Deny reason captured
  • AdminGuard enforced
  • Tenant from principal
Governed executor
  • Deterministic by default
  • ActionExecuted / ActionFailed (P4)
  • P7 adapter rule
  • live driver behind ACTION_EXECUTOR_MODE
  • No live systems unless enabled
Ontology-scoped
  • Optional objectId on propose
  • Resolves the object's type
  • permitted-actions enforcement
  • 403 ACTION_NOT_PERMITTED_FOR_OBJECT
  • Object + type recorded in evidence
Compensation
  • rollbackKey declaration
  • Compensating action run
  • Original marked compensated
  • Audited, admin-gated undo
  • Reversible side effects
Prove it — don't just claim it

Deny is the default. The ledger is the receipt.

Watch the same fabric handle six honest outcomes — a clean execution, a high-risk hold, an admin denial that never runs, a compensated rollback, and an ontology-scoped action blocked outright. Each row is an append-only ledger entry with its own evidence pack.

  • High-risk action → pending_approval until an admin approves
  • Denied action → recorded denied, the executor is never called
  • Wrong object type → 403 ACTION_NOT_PERMITTED_FOR_OBJECT
  • Executed action with a rollbackKey → cleanly compensated
Invocation Ledger
#1041dry-run
refund.issue · input { amount: 240 } · schema ok
valid
#1042propose
payout.send · riskLevel: high → pending_approval
pending_approval
#1043approve
payout.send · admin: risk-ops@northwind → executed
executed
#1044deny
close.case · reason: needs adjuster review
denied · never ran
#1045execute
email.customer · riskLevel: low → ActionExecuted (P4)
executed
#1046compensate
refund.issue · rollbackKey → refund.void → compensated
compensated
#1047propose
delete.record · objectId: Claim/4471
403 ACTION_NOT_PERMITTED_FOR_OBJECT
actions ▸ append-only · evidence pack on every step · admin-gated approve / deny / compensate
5Lifecycle states on every invocation
100%Of invocations recorded in the ledger
403ACTION_NOT_PERMITTED_FOR_OBJECT on wrong type
0Denied actions that ever reach the executor
Action Fabric
Dry-run
Refund $240
risk: low · evidence
Proposed
Close case #4471
risk: med · evidence
Pending approval
Payout $5,000
risk: high · evidence
Executed
Email customer
risk: low · evidence
actions ▸ dry-run → propose → approve → execute → compensate
Ontology-scoped actions

An action is only permitted on the objects it's allowed to touch.

Pass an objectId on propose and the runtime resolves the ontology object's type and enforces actionPermittedForObject(allowedActions, key). An empty allow-list on the type permits any action; a non-empty list must include the action key — otherwise the proposal is blocked. The object and its type are written into the invocation's evidence, and the check fails open (logged) if ontology-service is unreachable so governance never becomes an outage.

  • Empty allowedActions on a type → any action permitted
  • Non-empty list must include the action key, or it is denied
  • Block code: 403 ACTION_NOT_PERMITTED_FOR_OBJECT
  • Recorded in evidence.ontologyObject for the audit trail
Security & compliance

Built for the enterprise security review.

Admin-gated approvals, deny-by-default execution, append-only evidence, and the P7 adapter rule that keeps mocks out of production — mapped to the frameworks your auditors already use.

SOC 2ISO 27001ISO 42001HIPAAGDPREU AI ActNIST AI RMFFINRA

Give your agents hands — and a leash.

Put every agent action under a governed lifecycle: dry-run, approval, execution, rollback, and full evidence on every step.