{domain}.{action} event names, typed stop reasons, stream-only deltas, repo mounts, thin at-least-once webhooks, and an outbound-polling worker for self-hosted execution are all kept. The departures are deliberate too, and they cluster in two places: governance (who may do what is a resource you can list, audit, and revoke, never ambient configuration) and portability (the harness and model are choices, not the product’s identity).
This page maps concepts. It is not a compatibility layer: Checkfu does not accept CMA request shapes, and there is no drop-in endpoint. CMA details below were re-checked against its live public documentation on 14 August 2026; since the 2 August check, CMA has split its memory beta headers, published per-component budget pricing (model list cost, web searches, and sandbox wall-clock), added an advisor entry to the multiagent roster spec, and added
injection_location to vault credentials. CMA is a moving target and some of it is labelled beta or research preview; check its docs before relying on a CMA-side detail stated here.The resource map
Every row carries the same one-word answer Checkfu’s own plans and pull requests must give when they depart from CMA, so you can tell a deliberate bet from an accident at a glance:MATCH— CMA’s shape, kept on purpose.CHOSEN (D…)— a different bet, with the decision number that records it.N/A— no CMA counterpart.
One false friend
Checkfu has a resource namedConnectionVault, but it is not the CMA resource
with the similar name.
- A Checkfu SandboxProfile is the reusable base image, packages, network policy, resource limits, and retention configuration that maps to CMA’s Environment. Each published SandboxProfileRevision is immutable. A multiagent Session’s SessionSandbox is the one physical sandbox instance materialized from that configuration, not another reusable resource. Checkfu reserves Environment for deployment isolation.
- A ConnectionVault is a named access bundle over Connections. Editing it
compiles ordinary
use_connectionPermissionAssignments; the bundle stores no provider credential and grants nothing by itself. Use a principal-owned Connection when migrating a CMA Vault credential.
This vocabulary is in motion. Checkfu has decided a final domain language
(D262) that separates the deployment-stage sense of “environment” from the
sandbox-configuration resource described above, and a mechanical rename is
scheduled but has not landed. The names on this page describe the current
wire surface; expect the sandbox-configuration resource’s name to change in a
future dated API version, announced in the changelog.
Creating a session
A CMA session takes anagent and an environment_id. A Checkfu Session takes an agent_deployment_id and a principal — the identity the Session acts as, which has no CMA equivalent and is required. The deployment is the Environment-scoped head whose revisions pin the Agent release plus the exact harness, model-routing, and sandbox coordinates the Environment resolves; “same agent, different sandbox or model route per Session” is multiple deployments of one Agent under distinct keys, not a per-Session override.
The SandboxProfile network shape ports directly. CMA’s allow_package_managers and allow_mcp_servers exist on a Checkfu SandboxProfile under the same names, so a config copies across — with one difference to know about: a Checkfu flag is an abbreviation, not a mode. It compiles into the revision’s explicit allowed_hosts at publication, so the SandboxProfile you read back shows every host the flag granted and enforcement never sees a flag at all. allow_mcp_servers is the case where matching the name does not mean matching the effect: it expands to no workload host, because a Checkfu sandbox never dials an MCP server itself — every MCP call already crosses the CapabilityGateway. Port it and you keep the reach; port it alone, with no other hosts on an allowlist, and publication refuses the SandboxProfile rather than accepting an allowlist that reaches nothing. See Trust and isolation.
Like CMA, a create call can carry the session’s first work inline, and the cardinality now matches: both take up to 50
initial_events, processed in list order, and both accept user.message and user.define_outcome. Two Checkfu rules are worth knowing before you port a list across. A user.define_outcome is accepted only as the first entry, and at most one — an Outcome starts a turn from a settled boundary, which inside a create call is position 0 alone. And more than one entry requires an Idempotency-Key (the header CMA has no documented equivalent for, per the table above), because past the first entry the Run is already admitted and an exact retry is what recovers a list that failed part-way through.
CMA’s third form — agent_with_overrides, which changes model, system prompt, tools, or skills for a single session — maps partially onto Checkfu’s session-variable slots, and how far it maps depends on which field you are overriding.
tools and skills port with one difference in kind. Where CMA replaces the list with whatever you send, Checkfu narrows it: the release declares session_variable.tools.allowed (and .skills.allowed), those entries must be things the definition itself already grants — publication refuses a slot offering anything else — and a create call sends tools or skills naming a subset of the allowed set. So the gesture is the same and the direction is not: a Checkfu selection can take capability away from the reviewed release, never add capability it did not grant.
model and CMA’s environment selection do not port: the deployment revision pins the exact model-routing and sandbox coordinates, so per-Session variance there means multiple deployments of one Agent under distinct keys — a stable and a canary, say — not a per-Session override on the create wire. That is the price of “a Session always runs something a human reviewed.”
system ports as instructions, and it is the one member of agent_with_overrides that needs no declaration on the definition. Instructions are content rather than capability: an override reaches no tool, Skill, IntegrationConnection, PermissionAssignment, sandbox, or egress rule the release did not already grant, and your own first message steers behaviour inside that same envelope already — so there is nothing for an allowed-list to bound. What you get in exchange for that freedom is a record: the prompt is frozen into the Session’s admitted release and pinned by digest in run.created.execution_pins.instructions_sha256, so two sessions of one release that ran different prompts stay distinguishable forever. It is bounded at 64 KiB, and a Session created through an installed surface refuses it — that definition comes from the installation, not from the caller.
mcp_servers has no per-session form at all: a ToolSource’s tools reach a Session by being declared on the definition, and the Connection backing one is pinned there too, so the tools slot can only subtract from that declared set — it cannot add or replace a server for one session.
CMA’s separate idle-session update — a session operation rather than an override — ports as POST /v1/sessions/{id}/selection. The Session must be idle with no live execution, exactly as CMA requires, and the body is a replacement in the same way: send tools to narrow, omit it to restore the release’s full declared set, and one call does both. Every selection is admission-checked again, PermissionAssignments included, so a permission revoked between turns denies the re-selection rather than riding on the first admission. What it cannot do is move a pinned execution coordinate: if the harness release, sandbox image, model routing profile, deployment revision, or an environment policy has changed under the Session, the re-selection is refused and you make a new Session. The boundary lands on the event log as a session.updated entry carrying the release hash either side; what each turn ran is already in that Run’s execution_pins.
A coordinator agent whose roster includes itself narrows like any other release: the selection travels to its native child threads, so a child spawned against the self entry runs the narrowed set rather than the release’s full one.
CMA’s per-session budget ports directly. Where CMA takes budget: { max_list_cost } at session create, a Checkfu create call takes budget: { limit, metric? }, which compiles into a real session-scoped Budget — visible on the budgets list, not a shadow cap. The semantics match CMA’s: the session pauses at the cap (idle with stop_reason: "budget_reached", never terminated), the one in-flight model call completes and is billed, and raising the Budget’s limit strictly above consumed usage re-opens admission — restarting work that was queued behind the pause without a fresh message, exactly like CMA’s auto-resume. An Automation’s agent target accepts the same optional budget field, applied per created session, covering CMA’s per-run deployment budgets. Two differences to know: Checkfu bills its own reviewed price catalog in integer micro-USD (model_spend) or provider tokens (model_tokens) rather than CMA’s list-cost components (web searches and sandbox wall-clock are not yet counted), and CMA’s one-way budget: null removal maps to pausing the Budget — reversible, and unlike CMA you can also attach a budget to an existing session later.
Inference effort works the same way on both platforms and is worth mapping directly. CMA sets effort inside the agent’s model object (the model_config form) and explicitly ignores it inside a per-session override. Checkfu declares effort on the model candidate as a closed, harness-agnostic scale — minimal, low, medium, high, max — which the model gateway translates per provider. CMA’s rungs are low, medium, high, xhigh, max, so low through high and max line up by name; CMA has no minimal and Checkfu has no xhigh. Checkfu never passes a provider’s raw effort parameter through.
Events: the same taxonomy, one catalog
Events you send
CMA’sevents.send takes a batch (events: [...]); Checkfu’s takes one discriminated event with a payload, and attribution is required on every input: authored_by (the Principal speaking) and caused_by (what triggered the turn).
Events you read
Resuming a stream
Both platforms stream over SSE with stream-only deltas for token-by-token rendering. The reconnect story differs: CMA has no resume cursor, so a client that drops must re-list persisted history, seed seen IDs, then tail and deduplicate — and missed stream-only deltas are gone. That replay is timestamp-keyed, and the key recently moved: CMA now orders its event lists by each event’sprocessed_at rather than created_at, and its created_at[gt] / [lt] filters compare against processed_at despite the parameter names. Checkfu events carry a monotonic per-session seq, and the stream honors Last-Event-ID: send the last sequence you fully processed and the stream resumes from there. Ordering and cursoring are the same integer, so there is no timestamp semantics to track. See Resume a stream.
Tool permissions and approvals
CMA’spermission_policy is two-state (always_allow / always_ask) and configured per toolset on the agent. Checkfu’s ActionPolicy is a separate resource with three dispositions — allow / require_approval / deny, resolved as deny > require_approval > allow. A rule names a subject kind from a closed set — principal, group, agent_definition, agent_installation, surface_scope, session, or * — and a resource kind, each with a glob over ids, plus a glob over the permission. Defaults: a read-only, non-destructive tool over a read-only transport is allowed; writes and destructive-hinted tools require approval. An MCP-bound tool is never auto-allowed, because its safety hints are authored by the upstream server and refresh on every sync — it reaches allow only through an explicit ActionPolicy.
When an ActionPolicy says require_approval, the ask is not an inline event exchange but a durable ActionApproval: a queryable resource with frozen resolution context (connection, principal, arguments), a TTL-bound one-time response token, and the responder’s identity on the record. You list pending ActionApprovals, GET one, and POST /v1/action-approvals/{id}/responses — from any surface, not just the client holding the stream. The “stop asking me” gesture maps to a StandingApproval: minted only as a side effect of an approve response, scoped to one exact tuple, TTL-capped, revocable, and audited — never a silent config edit.
One scoping difference to notice: CMA’s permission policies do not apply to custom tools — your application is responsible for deciding whether to execute one. In Checkfu, custom (host-side) tools go through the same ActionPolicy evaluation, so an ActionPolicy can escalate or deny them before your app ever sees the call.
The defaults you arrive with
Where CMA sets a preset, Checkfu resolves the same two answers and now names them in CMA’s own spelling (D216), so nothing about the switch is a surprise:
The subsetting posture is the one to set deliberately when you port a CMA config: it is fixed at ToolSource creation, and a later sync preserves each tool’s explicit review rather than re-deciding it. See Tool sources.
Tool results and session output files
Two CMA behaviors around large content have direct Checkfu counterparts worth knowing before you port a data-heavy workload:- Oversized tool results. Both platforms bound one tool result at 100,000
characters. CMA spills the remainder to a sandbox file and hands the model a
preview plus the path. Checkfu’s Docker Runner now matches that recovery
shape: its self-describing
result_truncatedenvelope keeps a bounded preview and names alive_onlypath in the active sandbox. Read it during the Run; it is never captured into Session outputs and dies with the sandbox. An execution plane without the Runner spill sink, including the Worker-hosted Runner, returns the same bounded envelope without a path and states the loss honestly rather than promising unavailable recovery (D202/D272). - Reading what a session wrote. CMA mounts agent output into the sandbox
and leaves retrieval to you. Checkfu captures files the agent writes under
/mnt/session/outputsat settlement and serves them from the API:GET /v1/sessions/{id}/fileslists captured outputs andGET /v1/sessions/{id}/files/content?path=…returns the bytes (D178). Capture is bounded and streamed into Session-owned staged custody before the terminal event: at most 64 MiB per file and 256 MiB across at most 64 files. A file over the per-file ceiling is recordedtoo_large; a file inside it that cannot enter the settlement’s file-count, aggregate-byte, or Session storage-quota budget is recordedover_capacity. Either way it is recorded with its typed reason rather than silently dropped, so a bounded capture never reads as an empty one. A new Runner talking to an older control plane falls back to the legacy inline transport and its 1 MiB/file and 8 MiB/settlement limits, again reportingover_capacityvisibly. On the read side one response serves at most 8 MiB;offsetandlengthname exact byte windows that can be concatenated to reconstruct a larger captured file. ZDR refuses both the streaming settlement protocol and retained output files.
Multiagent: frozen rosters and one coordinator Session
CMA’s multiagent orchestration runs coordinator threads inside one session: a config-snapshotted roster (at most 20 agents, 25 concurrent threads), one shared sandbox and vault set, and delegation depth 1. Checkfu mirrors the coordinator authoring boundary:multiagent.agents accepts a bare Agent id, an exact versioned Agent, or self, publishing freezes the complete resolved roster, and callers start one pinned coordinator Session. The public runtime is one Session with a primary thread and persistent child threads:
- The published roster defines addressability. Live
use_agentPermissionAssignments and ActionPolicy can revoke a target but cannot add one. - Each member is pinned to an exact AgentVersion when the coordinator is published. Bare ids advance only when the coordinator is republished; exact entries remain pinned;
selfis supported directly. - Each child has a stable
sthr_*identity, complete filtered history, resumable stream, cumulative usage/stats, andrunning | idle | rescheduling | terminatedlifecycle. No backing execution identifier is public. - Spawning queues one initial message and returns immediately; follow-ups address the same persistent thread, child reports/questions wake the primary, and the primary never joins or parks on child completion.
- Sent/received event bodies match CMA’s direction-relative shape. Checkfu’s two private platform-control tools are an implementation boundary, not CMA API names or customer thread-mutation operations.
- The primary is listed first, children follow spawn order, and the Session admits at most 25 non-archived threads including primary. Idle children persist for follow-up until archived.
- Publication rejects nested coordinators and members that cannot share the coordinator runtime. Every active thread runs as an isolated process in one fenced SessionSandbox and sees shared file changes immediately.
- One aggregate-idle winner performs lifecycle writeback and checkpointing. The environment expires no later than day 30 without extending on activity; a later turn gets fresh scratch while thread conversation remains.
- The roster is capped at 20 unique Agents and 500 aggregate Skills.
Memory and Dreams
CMA memory stores attach to sessions (at most 8 per session) and cap out at 2,000 memories per store. A Checkfu MemoryStore is a versioned file tree with an ownership boundary (environment, principal, agent_definition, session, or surface_scope) where access is always PermissionAssignments — there are no fixed store-count or memory-count caps; cost is bounded by Budgets rather than quotas. Shared-owner stores advance through reviewed proposals instead of live sandbox writes, and every read and write lands in the log (memory.accessed, memory.proposal_created, …).
Dreams map almost 1:1. Both are asynchronous jobs (POST /v1/dreams) that take one existing memory store plus a set of past sessions and produce a new output store, copy-on-write, with the inputs never mutated, plus cancel and archive operations. Checkfu adds a deterministic mode (omit the model routing profile: dedupe only, zero usage) and a review flag that lands the result as an open proposal for a human decision. Both Versioned Memory and Dreams are currently rollout_fenced (Dreams additionally preview) — check capability status before planning a memory-dependent migration.
Outcomes
The shape is kept:user.define_outcome with a description, rubric, and bounded max_iterations; a grader in a separate context; a terminal result taxonomy. Two departures:
- The wire. CMA emits grader progress as
span.outcome_evaluation_*telemetry while also driving control flow and billing from it. Checkfu’soutcome.evaluation_started/outcome.evaluation_completedare first-class domain events with ledger-backed cost. - The verdict. CMA’s grader is deliberately opaque (“you see that it’s working, not what it’s thinking”). Checkfu persists the grader’s
explanationand the evaluation-input digest, subject to retention, and an Outcome can declare 1–32 typedreportoutputs — validated primitives with acceptance criteria — when downstream systems need comparable values instead of a verdict. See Outcomes.
Webhooks
The premise is identical — thin envelope with the eventtype and id, never payload content; fetch the object on receipt; at-least-once delivery with retries; an HMAC signature keyed by a whsec_-prefixed secret. The signing shapes differ: CMA sends the three Standard Webhooks headers (webhook-id, webhook-timestamp, webhook-signature), Checkfu sends one Checkfu-Signature header with a timestamped t=…,v1=… scheme.
Retry behaviour differs in a way worth planning for. CMA makes up to three delivery attempts with jittered backoff between 5 and 120 seconds, then drops the event with no further signal. Checkfu makes seven attempts spanning about 17 hours, with backoff widening from 30 seconds to 12 hours. Both are at-least-once and neither is a durable log: deduplicate on the event id and reconcile from the API when you need every transition.
The difference is the catalog. CMA’s webhook event names diverge from its persisted event names (session.status_run_started versus session.status_running, session.status_idled versus session.status_idle). Checkfu normally uses the persisted event name across streams and webhooks; the CMA-shaped child-thread lifecycle intentionally follows CMA’s webhook spelling: session.thread_created, session.thread_idled, and session.thread_terminated. Its signed thin envelope adds data.session_thread_id beside the Session and Environment identities. The rest of the subscribable platform lifecycle includes session.status_*, run.*, action_approval.pending / action_approval.resolved, and outcome.evaluation_*. See Receive webhooks.
CMA additionally publishes resource-lifecycle webhooks — created / archived / deleted across agents, deployments, environments, vaults, vault credentials, and memory stores, plus updated on the first three, paused / unpaused on deployments, and refresh_failed on vault credentials. Checkfu’s equivalent family covers memory stores (memory_store.created / .archived / .deleted — including the platform-created output store a completed dream leaves behind, which no customer call created), agents (agent.created / .updated / .archived; published versions are immutable, so publishing delivers agent.updated), Vault Credentials (the exact vault_credential.refresh_failed event, including the owning vault_id beside the Credential identity), connections (connection.created / .revoked / .refresh_failed for Checkfu’s additional governed Connection aggregate), automations (automation.created / .paused / .resumed / .deleted — the deployment.paused / .unpaused analogs; Automations have no archive state, so deletion is the terminal transition), deployment Environments (workspace.created / .updated; disabling is a versioned update, and Checkfu exposes no Environment delete/archive operation), and reusable sandbox configuration as SandboxProfiles (sandbox_profile.created / .updated; creation publishes revision 1 and later revision publication is the update). D262 requires the extra noun: CMA’s reusable sandbox Environment maps to Checkfu SandboxProfile, while Checkfu Environment is the isolated deployment boundary. A later Checkfu Environment creation delivers through the pre-existing request Environment; bootstrap creates the first Environment and has no possible Environment-scoped subscriber, so it emits no fact rather than race an empty catalog. Every delivery is the signed thin envelope with data.resource_id beside a null session, so one get-by-id completes the read. An Automation subscription trigger observes subscribable platform events, not Checkfu-internal resource mutations (D198).
Self-hosted execution
CMA’sself_hosted environment is a work queue: Anthropic’s runtime drives the agent loop, and your environment worker polls for tool-execution work items and posts results back. Checkfu keeps the outbound-only worker-polling pattern and widens what it hosts: a Runner executes the entire harness — the agent loop, the sandbox, the tools — on your infrastructure, while the control plane keeps the durable log and governance. Pairing is explicit: an admin mints a short-lived code naming the acting Principal (POST /v1/runner-pairings), the Runner redeems it, and revoking the Runner’s credential fences new claims. Provider credentials still never leave custody: the sandbox receives only the same short-lived gateway capability a hosted sandbox would.
The practical consequence of that wider scope shows up in what a self-hosted session can carry. CMA rejects any session that names a resources entry on a self-hosted environment, so files, repositories, and memory stores are hosted-only there. A Checkfu Session keeps the same mounts on a Runner as on a managed sandbox, because the Runner owns the filesystem the harness runs against.
The walked migration
Everything above is a map. This is the territory: the CMA quickstart agent and environment, taken verbatim from Anthropic’s own tutorial, translated, published as an AgentBlueprint, applied, and driven through a real Session. The transcript below is recorded output from an actual run, not an illustration. The input is the CMA quickstart’sagent (quickstart.md:151-156) and
environment (quickstart.md:347-350), plus the two things a real integration
carries beyond a tutorial — a vault attached at session create and a metadata bag:
The transcript is a recording, so it is left exactly as it ran — including a
refusal that has since been closed.
V-API-012 has moved to built since 5
August 2026: resources now carry a customer-owned metadata bag, so a re-run
today would bind external_user_id rather than refuse it. The
vault_reference_unresolved refusal beside it is not a gap and will not close —
it is D107 working as designed, and the paragraph below explains why.vlt_quickstart translated to a
Connection reference, so apply reports it unresolved instead of binding some
credential nobody authorized. You then create the Connection deliberately, which
is the whole point of the Connection model.
Step 3 minted three PermissionAssignments you did not have to write. A CMA agent reaches its
environment because the session named it. A Checkfu AgentDefinition holds an
explicit PermissionAssignment per runtime resource — and because the Blueprint declared them,
apply created them, and you can list and revoke each one.
Step 4 has no CMA counterpart, and that is the difference. The Principal a
Session acts as must hold invoke on the definition. In CMA, a workspace API key
can reference anything in the workspace; here, reach is a row.
One caveat stated plainly: the local stack runs a mock harness that echoes its
input, so the reply text is fixture content. The Session, the publish, the
apply, the PermissionAssignments, the event log, the sequence numbers, and the settlement are
real — what the transcript proves is that the migration path works end to end,
not that a model wrote that sentence.
What you lose today
These are the current customer-visible gaps relative to CMA. Each row comes from Checkfu’s outcome ledger, cites CMA’s mirrored documentation, and disappears when its status is promoted pastpartial, planned, or undecided.
No customer-visible CMA parity gaps are currently recorded.
Availability is separate from parity: a built behavior can still be
rollout_fenced in a particular deployment. Check capability
status before planning a migration.
No equivalent, on purpose
Places CMA has a surface and Checkfu deliberately does not. Each entry says what to use instead.Next steps
Quickstart
Create an Agent, publish a version, and drive a Session end to end.
Events reference
The full event catalog this page’s tables are drawn from.
Handle an approval
Review frozen context, answer through a Session or ActionApproval resource, and serve a Custom-tool result.
Migrate from your own loop
The companion guide for hand-rolled agent loops.