Mac · trust root
The second machine that keeps nothing.
Your Mac drives a spare machine as real compute. Every key stays on the Mac. The node runs the work, hands back the result, and is torn down with nothing durable left on it.
Collection and retrieval proved against a real Docker 28.5.1 container — the workload writes, Errand copies it back, bytes compared. Not covered: nothing has crossed a network socket; the node and daemon talk in-process in these runs.
Controller holds the key. Node holds nothing.
The controller can be a Mac, iPad or iPhone; the authority is always the Mac daemon, so a phone driving a Windows node is still the Mac deciding and signing. The work runs inside a container, walled off from the node's own operating system — and the data it works on is sealed before it leaves your Mac, so the node stores blobs it cannot read. Amber is work in flight — never a key.
RunThe container is the boundary. A Linux or Windows container node is the default precisely because it is isolated and disposable.
Stated, not impliedA job on your own Mac is NOT a container. One kernel, one machine, yours. It runs as a sandbox-exec-confined process under a per-job root, with the home folder, the keychain and the network denied by profile — and the root and the profile are deleted when it ends.
Honest limitThe workload itself — its image and its argv — is visible to the node, because the node has to run it. What is sealed is the data, and what never travels at all is a credential.
Not coveredThe carriage is a Unix socket, not a tailnet. A simulator shares the host's filesystem and a physical iPhone does not, so the relay transport ships refusing by name. No phone has driven anything over a network.
Not coveredMac↔Mac needs a second real Mac and is lab-gated. Linux is a real kernel under emulation on Apple silicon — real syscalls and real uid-0, but no claim about x86-64. Windows preflight ran on real Windows 11.
01 — the shape of it
Two machines. One of them is trusted.
Most distributed compute makes both ends equal and then spends its life defending that decision. Errand does not. The Mac decides, holds the keys, and signs. The node executes and forgets. A credential that reaches a machine is compromised even if it is deleted afterwards — so one never leaves.
A job declaring a credential-shaped variable name is refused before egress — before the queue branch, before submission. Classified by name, never by inspecting a value. There is deliberately no bypass flag.
CeilingSubscription CLI routes authenticate against this Mac's logged-in sessions. There is no credential to carry even in principle, so those cannot be offloaded at all — whatever Errand does.
01
Declared
You name the work. The Mac parses it at the boundary — never casts, never assumes.
parsed02
Sealed
A capability is minted for this job, this caller, this moment. Scoped, signed, expiring.
signed03
Crossed
Work goes over. Secrets do not. What the node receives cannot be turned back into a key.
no key04
Emptied
The result comes home. The working root, the profile and the container go with it.
torn down02 — the surface
It lives in the menu bar, not a browser tab.
A native macOS app, a Rust systems core, and thin helpers on the node. No web console, no control plane you have to trust, no raw engine socket anywhere. The daemon on your Mac is the only thing that decides anything.
Docker → podman → Apple container, in that order, pinned by a test. An engine named explicitly that does not answer is refused naming what did, never silently downgraded — a node told to use podman that quietly used Docker resolves images from the wrong store.
Not coveredVerified on one arm64 Mac. podman is 6.0.2 on a running machine; a stopped machine is a loud NOT COVERED, never a pass.
“Interrupted · outcome unknown” is a real state, not a rounding of “failed”. A job that ended where the exit status could not be read is never reported as success — an absent code is never zero.
Optional at every hop and in both languages, so “ended, and Errand could not read its status” stays distinguishable from success end to end. A defect that recorded an unknown outcome as exit 0 was found and fixed by this rule.
And once by the inverse: create-before-ack recovery matched exited containers by a deterministic label, so a workload that never started was reported Done · exit 0 · Completed. Found by an end-to-end test, not by reading.
03 — the interesting part
The refusals are the product.
Anything can say yes. What a system is worth is what it says no to, and whether it tells you why. Every refusal here states a cause and a next step — never a code, never a shrug.
This job declares AWS_SECRET_ACCESS_KEY. Nothing was sent and no key was burned.
Run it on this Mac, or use a route that authenticates without a credential to carry.
An AI agent asked to start work natively on your Mac. Every other thing an agent can start lands in a container on another machine.
Start it yourself, or send it to a node.
This work needs Apple frameworks and there is no Mac available to place it on. It was not quietly put on Linux.
Pair a Mac, or drop the requires = "macos" declaration.
This caller has spent its daily allowance. Nothing was done.
Wait for the window, or raise the ceiling for this caller.
Some of them are about you, and some are about us. A credential the node never sees is the easy case. The harder one is that GPU sharing is a performance mode, not an isolation boundary — one VRAM pool, one fault domain — so the planner refuses to co-schedule anything marked as needing isolation, and says so every time.
The reading path is written to be suspicious — it samples twice, requires the driver's stamp to have advanced, anchors card identity on first sight and never re-anchors, and re-probes MPS after starting because an acknowledgement is not evidence. A reading it cannot confirm renders as “GPU status unknown”, which is deliberately not the same sentence as “no GPU here”.
The catalogue of ways a GPU can lie is a hypothesis awaiting real hardware.
04 — the pipe
Compressed on the way, verified on arrival.
Framing, threaded compression by payload class, and a negotiated dictionary. A segment that expands past its declared length is refused as a bomb at a single ceiling — two ceilings is how one of them rots.
2308–2460 MB/s serial → 17053–17155 MB/s across 8 workers. Mac16,5, 16 cores, arm64, load average 5.92. Peak memory bounded at 64 MiB by wave width — the only sender-controlled term saturates, so 128 segments cost the same peak as 16.
True ofThis Mac, arm64, only. Never measured on x86-64. An emulated Linux on Apple silicon supports no claim about x86-64 codegen or timing, so it was not run and not claimed.
05 — with conditions attached
Numbers, and what they are true of.
A figure without its conditions is not a measurement. Each of these carries the machine, the load and the boundary it was taken at.
06 — permanent furniture
What isn’t proven, kept where you can see it.
This does not belong in a footnote. A gap you can read is worth more than a claim you can’t check, and the list moves as the work does.
0600 file, not a Secure-Enclave key. Documented at its call site rather than implied away.