Skip to main content
Your app’s users can bring an agent they run themselves — on a laptop, an always-on Mac mini, or a VM in their own cloud. Location is not a kind. Every one of those is the same connected posture with the same pairing flow; they differ only in how often the machine is expected to be online. The choice your UI offers stays exactly two-valued — managed by Checkfu or connected (yours) — never a menu of hosting geographies. The copyable client’s protected pairing-recovery store currently supports macOS and Linux. Windows is not supported: the client returns a typed failure before filesystem access because POSIX mode bits cannot prove a Windows ACL, owner SID, or reparse-point boundary. Windows support requires those native checks and a real Windows proof lane; a simulated platform test is not that evidence. The runtime dials out to Checkfu, so there is no inbound port, tunnel, or public URL to configure, and your app never sees the runtime’s credential: the one-shot pairing code is the only secret that crosses your product, and the user’s machine redeems it directly against the platform. CHECKFU_API_KEY and CHECKFU_WORKSPACE_ID come from Get access. The examples use the TypeScript SDK.

1. Mint a pairing code in your app

A pairing binds an end-user Principal to an AgentDefinition and produces a single-use code. The code is returned exactly once, by this authenticated create; the public pairing read exposes state, never the secret.
Show the user the code and the copyable client command. The ConnectLocalAgent component in @checkfu/ui renders this state (code display, presence badge, offboard control) from injected data, holding no credential and making no network call itself.

2. Run the client on the user’s machine

Any supported macOS or Linux machine, same command:
The CLI prompts for the code on stdin — it never rides argv, a URL, or shell history — then redeems it, keeps a durable mode-0600 redeem_id so a crashed redemption recovers instead of double-pairing, announces outbound presence under a fresh generation, and supervises the local agent behind the ACP boundary. Redemption is exactly-once: an idempotent retry recovers the same runtime, a second redeemer conflicts. The <your-acp-agent> argument is any command speaking ACP on stdio — the same contract every harness in the catalog uses.

3. Watch the pairing complete

Presence is disposable liveness only — never execution or capability evidence. Render an absent presence as offline, not as an error.

4. Drive the Session — online or offline

Address a turn to the runtime by naming it in the user.message. Everything else is the ordinary public Session surface:
Because the log is the agent, an offline runtime loses nothing: the Run is created and durably parked, the Session honestly reads provisioning (with run.created in the log and no run.started), and the turn executes when the runtime next announces. Tell the user exactly that — “queued; it runs when your machine reconnects” — rather than surfacing a failure. Under standard retention an Automation targeting an offline runtime queues the same way; under ZDR it fails closed instead of retaining execution content.

5. Offboard

Revocation is platform truth: the connector token stops authenticating immediately. Removing the owning Principal also ends its runtimes’ authority, but lazily — the runtime is revoked when it next presents its token, not at the moment of deletion. The credential is dead either way (the next claim, announce, or ToolInvocation is refused), but a runtime listing can still show state: "active" in the window before that next call. If you need the row to read revoked at a definite moment, revoke it explicitly rather than relying on the cascade.

What connected execution is — and is not

A connected runtime shares the durable Session log, governance, and audit path, but makes no Runner, sandbox, conformance, or model-control claim; its narration is attested against its registered key and honestly classed as narration, never as platform-witnessed evidence. See what a connected runtime realizes for the capability ceiling, and note that a ConnectedRuntime is not a customer-VPC Runner — that is a separate customer_runner topology. Connecting an existing third-party gateway (for example an operator-owned OpenClaw Gateway) is the sibling story — a control-plane federation rather than an end-user pairing. It rides the same connected-ACP boundary; see managed OpenClaw versus an existing Gateway.

A worked example

examples/personal-assistant wires this whole journey into a chat assistant: /connect local-agent mints the pairing and relays the code, /local <message> drives the paired runtime and relays the reply when it is online — or answers honestly that the turn queued durably when it is not — and /disconnect local-agent revokes it.