Skip to main content
A custom harness lets you run your own agent implementation through Checkfu’s Agent, Environment, and Session model. Package it as an immutable image, register it, and verify its supported capabilities before starting a Session. If your agent already speaks ACP, use the repository recipe path to install and launch it through the shared adapter. If you need to implement ACP, start with the CLI scaffold below. This guide covers the ACP and one-shot image contracts. The native Cloudflare Agents integration is a separate execution path: its internal package exports do not provide a customer BYOH scaffold or make an ACP image a native Durable Object harness. Native package tests also do not qualify your image or its tools, model formats, continuation, or cancellation. Use the exact release’s admitted capabilities and deployment status for either path. Harness wire extensions describes the contract and its generated capability matrix and slot inventory. The acp-v1 extension schema and golden wire vectors provide machine-readable wire contracts. Use the artifacts matching your release. They describe protocol support; the exact release’s signed conformance report and the deployment’s capability status determine which capabilities you can use. The server.mjs excerpts explain the protocol scaffold; connect it to your own agent’s tools and execution loop. Use the scaffold supplied by the authorized alpha CLI to start your own implementation; no Checkfu source checkout is required. See CLI access for artifact access and authentication.
The Checkfu CLI and TypeScript SDK are private-alpha artifacts with no self-service public installation channel. Part of this flow is behind a rollout fence; a deployment that has not enabled it refuses the request rather than running it. Confirm capability status before making availability part of your application’s contract.

Start from a scaffold

Use this path when your company owns the harness implementation. To use an official harness, select its named profile instead; you do not need to author a custom recipe. A catalog entry marked image_required still needs a qualified image and is not a ready-to-run default. See capability status for availability. checkfu harness init acp writes a minimal ACP starter and image packaging:
The generated starter calls Checkfu’s model plane and implements the ACP floor. It declares loadSession: false and does not declare or connect MCP tools. The protocol examples below come from that maintained CLI template. Implement the tool connection in your agent before declaring MCP delivery or the corresponding capability. Connect the starter to your domain implementation and declare only the capabilities it supports. Pass oneshot for the one-shot image contract. An existing ACP executable can use a recipe that installs and launches it; it does not need a TypeScript rewrite or Vercel dependency in its own implementation.

The wire: JSON-RPC over stdio

A harness is a process. The Runner launches it inside the sandbox, writes newline-delimited JSON-RPC 2.0 to its stdin, and reads the same framing from its stdout. Stderr is yours for logging. The starter uses the official ACP SDK for framing and request dispatch rather than maintaining a separate JSON-RPC server. Its input drain keeps the SDK connection open until an accepted turn has settled:
path=apps/cli/templates/acp/server.mjs
Protocol settlement and stream closure do not prove provider termination, rollback, a durable checkpoint, or physical descendant drain. Checkfu reads accepted settlement from the Session event log.

initialize: declare only what you serve

The first request is initialize. The response names your protocol version and capabilities:
path=apps/cli/templates/acp/server.mjs
This starter does not declare HTTP MCP support. A custom agent that actually connects the supplied HTTP MCP servers may declare mcpCapabilities: { http: true } and the matching recipe delivery. Richer harnesses may implement Checkfu’s namespaced extensions; see the declaration handshake. Qualify each implemented capability on the exact release before relying on it. Declare only what your implementation serves. A declaration is not proof: only server-issued, signed conformance evidence realizes a capability. Inspect the exact report’s checks and admitted capability matrix before configuring a Session. A check marked unsupported, skipped or failed does not realize that capability; some surfaces have no executable qualification case yet. Registration or a passing base protocol check does not make those surfaces available. A Session requesting an unproven capability is refused rather than given a substitute.

Session and turn lifecycle

session/new opens one process-local session. The starter refuses MCP servers and additional directories rather than pretending to connect them:
path=apps/cli/templates/acp/server.mjs
session/prompt streams the model answer through session/update and returns its native stop reason:
path=apps/cli/templates/acp/server.mjs
The starter’s cancellation handler aborts its original fetch and joins the turn. That local behavior still needs qualification with your actual model route and agent implementation. The conformance grammar holds every harness to the same shape — exactly one ready handshake before any output, exactly one terminal observation per turn, unique correlated tool-use ids. The full rule table is in the conformance grammar. The portable text prompt includes a JSON envelope with conversation.event_cursor, conversation.history, and the current input. The starter forwards that text to the model; it does not maintain its own conversation store. On an ordinary subsequent Run, Checkfu rebuilds the envelope from retained Session context. Reloading the console reads that retained history; it does not restore an agent process. A supported native checkpoint is a separate recovery path and must avoid replaying history already present in restored state.

Qualify the complete agent journey

Before adopting a release, exercise your actual agent implementation through the Session path you intend to support:
  • Complete useful work with a real native tool or granted MCP tool, and inspect the recorded tool result as well as the final response.
  • Start a subsequent Run in the same Session and check the context your agent actually retains. A successful first turn does not prove continuation. The scaffold above declares loadSession: false; connect and qualify your own state handling before advertising restoration.
  • Cancel while work is in flight. A cooperative ACP implementation handles session/cancel, stops its pending work, and settles the prompt. Check both the terminal outcome and any tool side effects. A cancellation acknowledgement does not prove that effects were undone or an upstream provider request terminated; a notification alone does not prove that execution stopped.
  • Exercise a known provider refusal, then submit a valid fresh prompt through your release’s supported retry path. Check the failed Run’s recorded outcome, the next Run’s useful result, and the absence of credentials in errors or diagnostics. Pinned BYOK refusal must not switch to paid managed tokens. A successful retry does not establish native checkpoint restoration or reverse effects from the failed attempt. If a request, tool effect, cancellation, or custody callback has an uncertain outcome, retain its original operation and use only the release’s supported reconciliation path. Do not create a new operation or reopen the native owner to repeat an effect whose outcome is unknown; a joined or closed local process does not establish rollback.
  • Exercise recovery only for the mechanisms your release supports. An externally custodied native checkpoint must be exported and imported through the declared Checkfu extensions. Native restore requires nonempty, bounded native state. The wire value same_run_resume also covers completed conversation state carried into a later Run of the same frozen Session; its name does not require the same Checkfu Run ID. Pending approvals require their exact admitted continuation, rather than an unrelated new input. Keep that state outside agent-readable files, and do not put provider credentials in it.
A native conversation identifier does not archive the agent’s private files. If recovery depends on a local transcript, automatic Memory, or other files, qualify how those files reach a fresh sandbox before advertising portable recovery. Check both the original conversation identity and the required file contents; a successful same-sandbox resume does not prove fresh-sandbox recovery. Native automatic Memory is separate from Checkfu’s governed Memory resources. A later Run receives fresh MCP credentials. If your upstream adapter fingerprints the complete MCP configuration in its saved state, that state may reject the new credentials. Preserve that compatibility check and rebuild from retained Session context until your adapter supports and qualifies credential rebinding. Set portable_native_checkpoint: false on a recipe whose state cannot cross this boundary. BYOH recipes omit external checkpoint custody by default. Set portable_native_checkpoint: true only after qualifying native state across fresh processes, replacement sandbox filesystems, and MCP credentials. If the upstream state refers to private files, retain those files through a supported filesystem recovery path or carry and restore their required contents in the checkpoint. A restart against the old filesystem does not prove recovery after sandbox replacement. Same-Run restoration with its original admitted configuration is a separate qualification. Select recovery support from the exact admitted release and its qualified capabilities. A protocol integration or an upstream conversation identifier does not establish checkpoint support. Checkfu’s current Pi coding and generic ACP guest adapters refuse restored transport state; Cursor’s protocol helper does not establish native restoration. Their source integration is not a portable recovery offering. For a custom harness that keeps history in sandbox-local files, qualify a supported file-restoration path before advertising recovery in a replacement sandbox. A retained filename alone does not restore its contents. The shared adapter refuses checkpoint export, checkpoint import, and native approval or question parking when initialize does not declare checkfu.capabilities.native_checkpoint: "external_custody". It returns ACP invalid params (-32602) with data.reason: "native_checkpoint_unsupported". That refusal does not establish a checkpoint or a restored Session. Explicit recipe opt-in supplies the declaration; conformance must still qualify the release before Checkfu admits the capability. Use the capability matrix to record unsupported continuation, interruption or checkpoint behavior explicitly. Source support, passing local protocol cases, a qualified packaged image and hosted availability are separate results. Keep the tested release digest and profile version with your receipts; rebuilding or changing the profile requires qualifying the changed inputs.

The governed model plane arrives in the environment

This scaffold uses Checkfu’s governed model plane. On this path, the harness receives a scoped gateway token; Checkfu keeps the provider credential outside the workload. Routing, budget enforcement, and platform-observed model usage apply to calls through that gateway. The sandbox environment carries CHECKFU_MODEL_BASE_URL and CHECKFU_MODEL_TOKEN — the platform-neutral names, and the ones to prefer in new code — pointing at the governed model gateway. The same values are also exported under the vendor-shaped aliases OPENAI_BASE_URL/OPENAI_API_KEY and ANTHROPIC_BASE_URL/ANTHROPIC_API_KEY for the formats your image declares (both pairs when it declares none), so a harness built against an existing SDK works unmodified; note that ANTHROPIC_BASE_URL is the origin without the /v1 suffix its OpenAI-shaped sibling carries. When every route the Session admitted serves one format your image declared, the environment also carries CHECKFU_MODEL_API — openai-completions, openai-responses, or anthropic-messages — and only that format’s alias pair, so an image that speaks several formats picks the one the gateway will forward. Official and customer harnesses selecting this model plane receive the same projection. The model name you send is rewritten to the admitted route. The protocol scaffold reads the OpenAI alias:
path=apps/cli/templates/acp/server.mjs
The maintained starter uses OpenAI Responses and passes its original turn’s AbortSignal to the fetch. Declare that dialect and select a compatible admitted route; it does not translate other formats automatically. Bake no credentials into the image and fail closed when the gateway refuses. Provider reachability is listed in harness and model-provider reachability. A harness_owned model plane uses the harness’s own credentials and routing. Checkfu has no model wire or token-usage authority on that path, so Session text alone cannot establish platform-observed model usage. An opaque declaration records unknown model control. Declare only the model control and usage authority your integration can demonstrate; admission rejects requested guarantees that the selected path cannot provide.

The platform tool plane: MCP handoff

For an ACP release that implements session_http delivery, granted platform tools arrive as HTTP MCP servers in session/new. Connect those original servers using a maintained MCP client and preserve their current exact-call approval and credential boundaries. The generated starter does not implement this connection and refuses a nonempty server list. Use --mcp-delivery none until your implementation and exact release have qualified the handoff. Emit native tool_call and tool_call_update observations for actual tool work. Narrative output is not a tool-delivery receipt; Checkfu’s served-call record remains authoritative. Declaring MCP support creates no tool grant.

The image contract

Your harness runs under a container posture the sandbox imposes, not one your image chooses: the process runs as user 65532:65532, the root filesystem is read-only, and exactly /workspace, /tmp, and /home/checkfu are writable. Build for it — a harness that expects to write elsewhere, or to be root, fails at runtime rather than at registration. Be precise about what enforces this. The sandbox provider applies the posture at materialization; the values above are the same ones the catalog’s image contract records for first-party entries, and a custom image registered through harness add oci has no catalog entry at all. Conformance does not check container posture — its case set covers the ACP handshake, tool correlation, and the declared control axes, and contains no uid, read-only-root, or writable-path case. The maintained starter does not test or attest that posture. Verify the selected Environment and immutable image through the actual owner-supported checks before claiming isolation. Measurements your harness reports from inside its workload remain self-reports, not platform attestation. Non-secret configuration reaches the harness as visible JSON in CHECKFU_HARNESS_CONFIGURATION, validated against the configuration schema registered with the release. Credentials never belong there — provider access rides the model plane above, and tool authority rides the MCP handoff. A generated Vercel recipe image forwards this variable only when its forward_env explicitly includes CHECKFU_HARNESS_CONFIGURATION. Use that opt-in for an image whose native process understands the JSON, and register the closed configuration schema with the release so profile validation happens before the image starts. An arbitrary customer Dockerfile already receives its declared environment; this recipe forward_env switch is not a requirement for that path. The configuration is not a provider route or credential authority. Official DeepSeek managed rows are not BYOH recipe examples; a BYOH image must document its own accepted schema and native selection.

Register, verify, run

Registration is the same advanced lane arc for every custom harness: build and push an immutable image, register the digest, request server-signed conformance, then create or update an Agent so Checkfu records the next immutable AgentVersion. Low-level registration records do not replace the AgentVersion or Environment admitted by a Session.
This example calls the Responses API, so --model-wire openai_responses records its supported dialect on the release. Declare the dialects your own implementation actually uses; the model route must serve one of them. These registration commands use --mcp-delivery none for the unmodified checkfu harness init acp starter shown above. The starter refuses MCP servers. Use --mcp-delivery session_http only after your implementation connects the HTTP MCP servers supplied in session/new. That flag records the delivery contract on the release; the initialize capability alone does not set it. Only the digest-pinned name@sha256:... form registers; a mutable tag fails before anything persists, and a new image is always a new release. The Custom ACP harness example describes how the resulting profile fits the Agent, Environment, and Session model.

Upgrade and roll back one logical harness

Keep the logical harness lane name stable after initial adoption. Test and publish a new immutable digest, then create the release, advance the profile with optimistic concurrency, and verify the exact resulting version in one CLI workflow:
--expected-version is checked before the CLI creates a release, then the API guards the patch with the same current version. The command prints a recovery command as soon as an OCI release exists, so a failed or interrupted profile patch never strands an undiscoverable artifact. After a successful patch it prints the exact rollback command. Rollback is an ordinary forward version:
The earlier HarnessRelease and every HarnessProfileVersion remain immutable. An in-flight Run keeps its resolved pins; later admission resolves the new profile version. Moving any release, driver, or configuration member invalidates the old conformance tier, which is why --verify targets the returned profile version directly instead of resolving the logical name a second time. Non-secret configuration is retained unless --configuration is supplied, and the CLI validates the resulting configuration against the target release before patching. For an OCI-to-OCI update, omitted process, platform, configuration-schema, model-wire, and MCP options inherit from the current immutable release. This keeps an image-only rebuild exact without silently dropping a declared capability; pass an option only when the new binary intentionally changes that part of the release contract.

Or hand us the repository instead

If you would rather not run a container build at all, POST /v1/organizations/{organization_id}/harness-builds takes a GitHub repository URL, an optional ref, and an explicit platform build pool or Workspace/RunnerPool target. Checkfu builds the image and mints the Organization-owned, digest-pinned release for you. Ownership never implies execution authority. The ref is resolved to an exact commit at submission and only that commit is stored, so the immutability rule above is unchanged rather than relaxed: no branch or tag is ever stored on the result, and re-registering a repository is always a new build. Submission is accepted with 202; poll GET /v1/organizations/{organization_id}/harness-builds/{id} for settlement. Two repository shapes are recognized:
  1. harness-recipe.json at the repository root — the recipe-in-repo path. Commit the recipe plus the context its install command needs. Checkfu prepares a Vercel-shaped adapter image from that recipe. You do not need a Dockerfile for this path. The selected Runner must have a recipe base configured by its operator. Adopt the result as acp-v1 with entrypoint /opt/checkfu/bin/checkfu-vercel-harness and model_wire_dialects from the recipe’s route. The private andyrewlee/checkfu-customer-harness-fixture repository is an additional example for developers who already have access. The recipe below works with your own published ACP package.
  2. A Dockerfile and no recipe file — Checkfu builds that Dockerfile as a stranger image. Direct-OCI registration (checkfu harness add oci) remains the path for images you already built yourself.
For an existing ACP agent published to npm, commit this as harness-recipe.json. Replace the package name, exact version and executable with your agent’s values; the package must be accessible to the build Runner. This example assumes the agent reads OPENAI_BASE_URL and OPENAI_API_KEY and uses OpenAI Chat Completions. Choose the route and environment mapping that your agent actually supports.
The package supplies the native agent loop and ACP server. The empty builtin_tools list declares no native tools; add only tools your agent exposes. Declare session_http MCP delivery only when the agent implements that transport. For a native ACP server that enforces an allow-list supplied in session/new metadata, the recipe can declare that mapping:
This is a recipe fragment, not a complete recipe. Checkfu projects the admitted selection to the listed tools’ native_name values (or tool_name when absent), then Vercel delivers the array under that exact _meta key. The native server must enforce it before executing any built-in. An empty array disables every built-in; an absent selection preserves native defaults. read, glob, and grep are separate grants. Merely hiding a tool from the model is insufficient. Unknown names and ambiguous native aliases are refused. Vercel continues to own bootstrap, transport, Session restoration, turns, and cancellation; the mapping does not introduce another agent loop. Recipes do not inherit Vercel’s generic approval capability by default. Declare "builtin_tool_approvals": "acp-permission-request" only if the native server actually requests ACP permission before the governed operation and obeys the decision. Without that declaration, approval-requiring modes fail before native startup. The declaration alone grants no approval authority: signed conformance must exercise the request and continuation on the exact release and profile. A Session using this capability must enable native continuation capsules in its capture policy; Workspaces with zero-data-retention (ZDR) mode cannot use native approvals. The noncatalog Docker proof runs both decisions through the public API (owned/harness-sandbox/public-customer-native-action-approval). The separate launch-file-arg / dsh-overlay mapping is not a generic file writer. It selects the reviewed DeepSeek plugin adapter and requires pinned @deepseek-ai/dsh@0.1.5-rc.1, dsh --profile acp, and the complete matching native tool inventory and built-in aliases. A recipe cannot relabel DeepSeek’s shell as a read tool. Other harnesses use their own enforceable mapping; declaring DeepSeek’s mapping cannot grant filtering support to another engine. This DeepSeek integration also accepts the maintained adapter’s model configuration. Declare these fields in the release’s configuration schema and set them on the HarnessProfile so the native selector and context/output limits match the model you route through Checkfu:
Use your model’s actual limits. The selected ID must occur in the catalog and its output limit must be below its context window. Keep DSH_HOME in retained Harness state, such as /home/checkfu/.checkfu-harness/deepseek, so the native journal is available to later Runs. This does not establish portable native checkpoint restoration. The following example uses an ACP recipe that consumes HTTP MCP servers and OpenAI-compatible chat completions. Run it from your own checkout of the harness repository, not from a Checkfu source checkout. Commit harness-recipe.json at the repository root and push that commit to GitHub first. With --recipe, the CLI reads the recipe from the local commit that --ref names and derives the entrypoint and wire dialect from it. --ref may be a full commit SHA, a tag, or a branch (tags/v1.0.0, heads/main, or a bare name that is not both). Checkfu resolves the ref once to an exact commit and the build records only that commit, so a tag rebuilds a historical release after the branch has moved on. If your checkout and Checkfu resolve the ref to different commits, the CLI refuses the result, and the Runner refuses a build whose entrypoint or wire dialects differ from the recipe at the frozen commit. A bare SHA is accepted only while it is the tip of a branch in that repository, so name the tag for an older commit, and a commit that exists only in a fork is refused. The command can stop at the ordinary release-profile handoff, or compose adoption and signed verification without introducing a privileged build-only profile path. Set CHECKFU_RUNNER_POOL_ID to the rpool_... ID of a build-capable RunnerPool in your Workspace first:
Add --dry-run to print the exact build request without submitting it. If the waiting process exits, resume without resubmitting the build:
A Dockerfile-only repository omits --recipe and supplies its own entrypoint and model wire dialect. Without --adopt, success prints checkfu harness add release --name ... --release hrel_... --driver checkfu:acp-v1@1. With --adopt, the CLI submits that same public profile-creation payload; --verify additionally waits for signed conformance and prints status. Building an image grants no conformance or admission privilege.

Prepare an Environment from the release

Create your Agent and its dependencies through the ordinary resource operations. No installer prepares them for you. Put the harness reference, model, and instructions in an Agent project and run checkfu agent apply, or call Agent create directly. Then create the Environment that uses the built release’s exact image repository and digest, and grant the Agent use_environment through a PermissionAssignment. The quickstart shows that Environment grant. The Agent also needs a use_harness PermissionAssignment for the adopted Workspace HarnessProfile. Set the subject to kind: "agent_definition" with agent set to the Agent ID, and the resource to kind: "harness" with id set to the HarnessProfile ID. Adopting the profile or creating the Agent does not grant this permission automatically. Use Create a PermissionAssignment. An inline BYOK model configuration pins model_credential_id and does not need an additional use_model grant. If you use a reusable ModelRoutingProfile, select it with an Agent use_model PermissionAssignment whose resource kind is model-binding and whose resource ID is the profile ID. See Create a PermissionAssignment. Keep the harness reference consistent with the adopted profile and the Agent manifest. These are nonsecret configuration files; no Checkfu checkout or manual trust evidence is needed. For this preparation sequence, build with --adopt first, then create the Agent and Environment and verify against that Environment. The combined build command above assumes its named sandbox is already prepared.
Save the Agent ID that agent apply prints and pass it as --agent-id on later applies. The derived sandbox digest can differ from its harness base-image digest. Creating these resources does not establish exact-image execution readiness. That remains the separate check below. Official catalog identity is recorded when a release is adopted. A later catalog refresh does not invalidate an already-admitted Run’s pinned release. Native checkpoint and approval authority come from its verified capability admission, with the same provider, custody, and policy checks for official and customer harnesses. A catalog label alone grants neither capability. For an existing profile, leave --adopt off and pass the resulting release to checkfu harness update <profile> release --release <hrel_...> instead. OCI releases select the canonical protocol driver automatically; a non-OCI release requires the explicit --driver value. The update path then follows the same fresh-verification rule above.
This path is alpha. A build stays pending until a build-capable Runner is available to your Workspace. Recipe builds additionally require an operator-configured recipe base; a Runner without one rejects that build. A private repository needs the Checkfu GitHub App installed and bound to that Workspace and repository. Successful builds record their source commit and provenance. If an existing image digest belongs to an incompatible release contract or different build provenance, the build fails with image_rejected; it does not replace or silently reuse that release.

Check execution readiness

A completed build creates an immutable release. Adoption selects a profile, and verification exercises its declared capabilities. Before an ordinary Session, the execution deployment must also serve that exact image on a qualified runtime and provide placement capacity. A passing conformance report or ready Runner alone does not supply that execution authority. After attaching the profile to an Agent, inspect public support diagnostics:
With these flags, doctor exits nonzero when the Workspace’s broader public Session support is incomplete. That result does not check exact admission for your selected Agent and Environment: a qualified basic custom-harness path may be usable while advanced capabilities such as steering remain unavailable. Doctor exit zero is not a prerequisite for attempting that qualified subset, and a successful basic Session does not prove those advanced capabilities. Ask your alpha operator about the missing public support prerequisites. Session creation separately checks the exact image, qualification and authority; missing or expired execution qualification is still a refusal. If admission reports harness_artifact_mismatch, ask the operator to publish and qualify an execution offering and matching placement for the exact release image. Supply your release ID, profile ID/version, and image digest. These prerequisites apply to new and upgraded releases; do not change the digest to an unrelated image to bypass the refusal. A successful preflight still leaves exact admission to Session creation. Keep your existing profile until the new release is verified and its execution path is available. Existing Sessions and in-flight Runs retain their frozen choices; later Session admissions can select the updated profile.

Where to go next

  • To understand the boundary, use the maintained CLI ACP template — the protocol floor is intentionally minimal, and its omitted capabilities are explicit.
  • To adapt an SDK-authored agent, use the OpenAI Agents SDK over ACP example — it pins the official SDK, routes its fixed model through Checkfu’s gateway, disables the SDK’s separate trace exporter, and declares no MCP handoff.
  • For the contract itself, Harness wire extensions and the schema and vector artifacts remain the normative source.