Trust tiers
Continuum’s trust model spans the host that runs your agents, the clients that drive it, the relay and push paths between them, the cloud backend that holds account state, the inference gateway, the provider CLIs it spawns, and the release channels.Cryptographic primitives
These cover the relay and push path that lets a paired device reach your host when the two are not on the same network.- Key exchange. X25519 ECDH between host and client (CryptoKit
Curve25519.KeyAgreement). Fresh ephemeral keypairs per pairing; the relay sees only the 32-byte public keys, never the shared secret. - Key derivation. HKDF-SHA256 with
salt = sessionIdand separateinfostrings for the relay channel and the push payload channel. Differentinfostrings derive sibling keys, so a compromise in one channel does not affect the other. - Authenticated encryption. XChaCha20-Poly1305 AEAD with random 24-byte nonces from the platform CSPRNG. The 192-bit nonce never collides in practice, so there is no birthday-bound message ceiling. The envelope header (version, sender role, type) is bound into the AEAD associated data, so a captured host→client frame cannot be reflected back as client→host — a flipped role changes the AAD and verification fails.
- Replay protection. Per-direction sequence numbers carried inside the encrypted plaintext, validated against a per-direction window that persists across reconnects. The protocol version byte is bound into the HKDF
infostring, so a downgrade derives a different key and AEAD fails closed.
Per-peer bearer auth
Every daemon endpoint — HTTP and WebSocket, loopback included — requiresAuthorization: Bearer <token>. The daemon accepts one of two tokens:
- A pairing token presented by paired clients.
- A per-launch loopback token generated fresh on each app launch for the host’s own in-process client. It is never persisted and never crosses the wire.
Token and code lifetimes
There is no single pairing TTL — the artifacts have deliberately different lifetimes, and the short one is the one you handle by hand.
The Mac shows the enrollment code’s countdown inline: “Code expires in 10 min.”
QR-code pairing has been removed from the shipping surfaces. Devices join through email sign-in, and hosts are added with a one-line enroll command or through the Advanced options (Tailscale, SSH, cloud). See Pairing.
Network peer filter
The daemon listener accepts connections only from loopback (127.0.0.0/8, ::1) and the Tailscale CGNAT range (100.64.0.0/10 and the fd7a:115c:a1e0::/48 IPv6 prefix). Any other peer is dropped on accept, before auth runs. Bearer auth is still required afterward, so the peer filter is defense-in-depth, not the sole gate.
The daemon does not terminate TLS itself; transport confidentiality on the remote path comes from the sealed relay envelopes and, on a tailnet, from WireGuard.
Tailnet identity verification
Non-loopback connections from a Tailscale network are additionally verified via Tailscale Whois (60-second cache). This is fail-closed: a peer that cannot be resolved to a tailnet identity is rejected with a401. It applies uniformly to the local daemon and to remote execution hosts.
Multi-account isolation
Continuum supports multiple accounts per provider on one machine (Settings → Providers → Add account…). Isolation is enforced at spawn time:- Config-dir isolation, not a HOME swap. Each secondary account gets a deterministic config root, and at spawn the daemon points that provider’s own config variable at it —
CLAUDE_CONFIG_DIRfor Claude,CODEX_HOMEfor Codex,XDG_DATA_HOMEfor the OpenCode-family providers,GROK_HOMEfor Grok, and a scopedHOMEfor Antigravity’sagy, which honors nothing narrower.HOMEis deliberately not overridden in the general case: a full HOME swap brokegit,ssh,gh, andnoderesolution inside worktrees. Cursor authenticates with an API key and has no config root to isolate. - Env scrubbing on child spawn. Before launching a per-instance child, the daemon strips every inherited
CLAUDE_*,ANTHROPIC_*,CODEX_*,OPENAI_*,GEMINI_*,GOOGLE_APPLICATION_CREDENTIALS,OPENCODE_*,OPENROUTER_*, andCURSOR_*variable, so a stray key in the parent environment cannot leak into another account’s spawn. Per-instance credentials are injected after the scrub. Non-Anthropic agents always get the Claude credential scrub even on the primary account, so a subscription token can never leak into a third-party agent. - Per-instance keychain partitioning. Each non-primary instance reads its token from a distinct keychain partition — a per-instance access group plus a per-instance service-name suffix. Because the access group is part of the lookup key, a query scoped to account A cannot read account B’s entry, and the double bind means even a misconfigured entitlement can’t cross partitions.
- Fail-closed spawn resolution. A session’s pinned account is resolved before every spawn. A pin to an account the registry no longer carries, a non-isolatable instance, or an account with no stored token all refuse to spawn with a re-authenticate error — never a silent fallback to your default subscription. The defended failure mode is wrong-account billing.
/, \, NUL, whitespace, or leading .), which rejects the .. path escape that could otherwise let account removal delete a sibling account’s data.
Execution hosts
Another Mac, a Linux box, a VPS, your own cloud account, or a Continuum-managed runner can run agent sessions on behalf of a hub.- How the host is provisioned. On Linux, a bundled Go
continuum-agentplus a service unit; the agent generates its own bearer token, which the hub captures. On macOS, Continuum itself runs in headless-agent mode under a per-user launch agent with a provisioned token. Token files are staged into a0700directory and written0600, so no secret lands in a world-readable file. - What the hub trusts about the host. The hub reaches the remote daemon with a provisioned bearer. The remote daemon applies the same gates as the local one: peer filter, per-peer bearer, and fail-closed tailnet identity on every non-loopback request. A remote host trusts the hub only insofar as it presents a valid bearer from a verified peer; it is not an open relay.
- Credentials on the host. When the hub needs a provider subscription there, it pushes that credential explicitly and refreshes it as it rotates. Hosts are compute, not credential custodians — they hold only what the hub deliberately pushes.
- Repo-controlled hooks do not run. Worktrees the Mac provisions are created with
core.hooksPathpointed at/dev/null, so cloning or checking out a repository cannot execute a hook script that repository controls. - GitHub access for managed cloud runs is short-lived and single-repo. Access is re-checked immediately before create or wake — a suspended installation, a revoked grant, an archived repo, or missing push permission fails closed. The token is scoped to one repository, refreshed before expiry, and delivered through a credential helper over an owner-only socket, so it never lands in git config, a command line, or shell history.
Content sealing and erasure
Once you sign in, transcript pages mirrored to the cloud are sealed at rest with AES-256-GCM under a per-member key. Removing a member destroys that key, and every page encrypted under it becomes permanently unrecoverable — erasure that holds across replicas and backups without hunting down individual rows. Tenant tables have Postgres row-level security enabled and forced, with policies keyed on the requesting organization. Forced RLS means the policy applies even to the table owner, so an application bug that forgets a predicate still cannot read across tenants.Hosted inference: gateway-side enforcement
Organization policy for hosted inference is enforced by the gateway, not by the client UI. One code path serves every hosted entry point, and it checks, in order: the global model allowlist, model pricing, subscription entitlement, the organization’s model allowlist for that member or team, and an atomic budget reservation. A blocked model returns403 with the reason — “…is not permitted for your team by your organization admin.” An exhausted allocation returns 429, distinguishing a free-tier allowance, an organization-set member cap, and a spent weekly budget. Because the checks live behind the API rather than in front of it, an older or modified client cannot route around them.
Upstream provider credentials are server-side only, sealed with AES-256-GCM under a key held outside the database and bound to their purpose by the AEAD associated data. Clients never receive more than a four-character key hint.
Share links
Publishing a transcript tocontinuumcode.ai/share/<id> runs the redactor server-side, before storage — no client, and not the host proxy, can widen what a link exposes.
The redactor is an allowlist walker: each message is rebuilt from a known key set and anything unrecognized is dropped, so a transcript field added tomorrow cannot leak by default. Raw tool-input JSON — whole file contents, full shell commands, credentials passed as flags — is never stored at all, because the share page does not render it. On top of that, known secret shapes are masked: private key blocks, Anthropic, OpenAI, GitHub, Slack, AWS, and Google keys, JWTs, database connection strings, KEY=value dotenv lines, and api_key:-style assignments, plus home directory paths, email addresses, and private IP ranges. Terminal control characters are stripped so captured output cannot smuggle escape sequences into the page.
Links can carry an expiry, can be revoked, and record a view count. Unlisted-ness rests on the id’s entropy, not on obscurity of the route.
Environment variables
Environment values never leave the machine, and the wire type enforces it: the record Continuum publishes for an environment variable has no value field at all — only the key name, a fingerprint, whether a value exists, and its rotation state. Reveal is a local action against your own keychain, with no endpoint that returns a value. Agents are briefed with the key names only. Keys that could hijack a process — loader, hook, and routing variables such asLD_PRELOAD, DYLD_INSERT_LIBRARIES, NODE_OPTIONS, PATH, BASH_ENV, GIT_SSH_COMMAND, GIT_ASKPASS, and the proxy variables — are refused on import, reported rather than silently dropped, and stripped again at spawn, swap, and revive time so a legacy stored key cannot reactivate.
Audit logs
The daemon writes append-only JSONL audit entries under~/.clawdmeter/audit/. The directory is created 0700 and re-tightened on every launch, so peer IPs and repo paths stay private on a multi-user machine; files are created 0600.
Current streams: sends.jsonl, swaps.jsonl, autopilot.jsonl, auto-router.jsonl, mobile-commands.jsonl, cowork.jsonl, creds.jsonl, and sidecar-ask.jsonl. Entries record metadata — timestamps, session ids, operation type, hashed prompt fingerprints, byte counts — not content. Files rotate at 1 MB or 7 days, whichever comes first.
Prompt text is hashed by default, and there is no UI that turns that off. Recording plaintext is a deliberate defaults-key opt-in (clawdmeter.audit.includePlaintext, default false) intended for debugging your own machine; the same key gates whether the wire inspector retains request and response bodies.
The push gateway’s log records attempt outcomes, hashed device tokens, and byte sizes — never the notification body. The relay’s records sender role, envelope type, and byte count — never body bytes. Retention there is 90 days by default.
Kill-switch and rate limits
The push gateway has anAPNS_DISABLED kill-switch that short-circuits the request handler before schema validation, auth, or rate-limit checks — toggling it stops all push delivery within about 30 seconds. A per-sender hourly cap (default 60 pushes per hour, bound to the verified pairing identity rather than the supplied device token) limits damage from a compromised signing key.
The daemon enforces 1 send per second and 1 swap per 5 seconds per session; model, effort, and mode swaps share the swap budget. Exceeding either returns a 429.
ACP file-system trust boundary
When Continuum drives Codex, Cursor, Grok, or Gemini over the ACP harness, the agent can request file reads and writes. Every request is validated through a repo trust gate: the path is canonicalized, symlinks resolved and.. collapsed, and the canonical result must sit at or under the repo root — defeating traversal, absolute-path escape, and symlink escape. The gate is TOCTOU-aware: it returns the resolved canonical path and the caller opens that exact path, never re-resolving the attacker-supplied string. Terminal and read output returned to the agent is capped as an anti-DoS measure.
Release channels
Two release gates worth naming, because they fail the build rather than shipping something weaker:
- A tagged Windows release cannot publish unsigned. The pipeline refuses to proceed without a signing certificate, and after packaging it runs Authenticode verification on every executable, failing the release if any file does not verify. (Untagged development artifacts are explicitly built unsigned and say so.)
- Dependencies cannot resolve without a lockfile. A missing lockfile aborts the build rather than silently resolving fresh versions.
Unsigned Windows binaries can still be blocked by Smart App Control or WDAC, and a newly signed binary needs SmartScreen reputation to accumulate. If Windows warns on first launch, see Troubleshooting.