What a runner does
A runner takes a task, gives an agent a machine, and hands back a diff.
OpenHands is that, open source. Its README today leads with Agent Canvas, described in its own words as "the self-hosted developer control center for coding agents and automations" — a thing that "turns your coding agents into a self-hosted, always-on engineering team," running locally by default but able to connect to multiple agent backends in Docker, on VMs, or inside your own infrastructure. It is explicitly not single-agent and not single-vendor: it runs "OpenHands, Claude Code, Codex, Gemini, or any ACP-compatible agent across local, remote, and cloud backends" (OpenHands/OpenHands, README, retrieved 2026-08-04).
GitHub's Copilot cloud agent is that, hosted inside GitHub. Per GitHub's own documentation, it "works autonomously in a GitHub Actions-powered environment to complete development tasks assigned through GitHub issues or GitHub Copilot Chat prompts," and while working it "has access to its own ephemeral development environment, powered by GitHub Actions, where it can explore your code, make changes, execute automated tests and linters and more." It can "research a repository, create a plan, make code changes on a branch, and optionally open a pull request" (About GitHub Copilot cloud agent, retrieved 2026-08-04).
Neither product claims to be the thing that decides whether the diff is correct, and GitHub's documentation is unusually explicit about the boundary. On its own page of risks and mitigations: draft pull requests created by the agent "must be reviewed and merged by a human"; the agent "cannot mark its pull requests as 'Ready for review' and cannot approve or merge a pull request"; by default Actions workflows "are not triggered until Copilot cloud agent's code is reviewed and a user with write access to the repository clicks the Approve and run workflows button"; and the agent "is also subject to any branch protections and required checks for the working repository" (Risks and mitigations, retrieved 2026-08-04).
The platform hands the decision back to a human on purpose. That is the correct design. It also tells you exactly where the load lands.
The load lands on a person
A reviewer reading an agent's pull request has one piece of evidence in front of them: the test suite that came with it. That suite was written by the thing under test. It is a claim, not a check.
So the reviewer reads the diff. That works, and it keeps working, right up until the number of diffs per week stops being set by how fast people write code and starts being set by how many agents you are willing to leave running overnight. Review capacity is fixed. Agent throughput is not. Every improvement in the runner category widens that gap.
What scales is not a diff a human reads. It is a check a machine runs, that the author of the diff never saw, that has been proven able to fail.
What a gate does
A gate is external, and it is falsifiable before it is trusted.
External means the implementing agent never sees it. Falsifiable means someone has already injected real defects and watched the gate catch every one of them, before the gate was allowed to certify anything.
Heimdall's version of that is one command: bin/falsify <domain> --assert-score 1.0 runs the domain's mutant suite and reports PASS only when every mutant is killed — not most of them. Two flagship gates hold at 1.0: exchange-lob at 6 of 6 mutants caught, emulator-gb at 3 of 3 (evals/flagship/STATUS.md). A regression corpus replays every failure the gates have ever caught: 13 cases, 13 caught, 100% at version 0.1 (evals/corpus/CORPUS-STATUS.md).
The row worth more than either of those is a failure. On 2026-06-12 a golden Game Boy trace was corrected — a flag byte read F:10 where the truth is F:20, because the half-carry bit is 0x20 and the carry bit is 0x10 and the reference had them inverted. The corpus immediately dropped from 9/9 to 7/9 and exited non-zero. It recovered to 9/9 only after every expectation was re-pinned by replaying the inputs and capturing the emitted divergence.
That is the difference between a gate and a green build: one of them has a recorded incident where it went red on its own author.
Where the two compose
The runner opens the pull request; the gate decides whether it can be pushed. Concretely today: hmd guard install wires a PreToolUse hook onto Claude Code's Bash tool, matching on git push itself, and runs secret-scan, a full-history self-scan, bin/falsify and bin/corpus before the push ever leaves the tool call. A non-zero exit from any of them is a hard block with the real reason attached.
That is a Claude Code mechanism. It does not run inside OpenHands' runtime, and it does not run inside GitHub's Actions sandbox. Saying so plainly is the point of this post — the composition that exists today is "gate the tree the runner produced, on a machine you control," not "gate inside their environment."
The coordination ledger is already cross-tool. bin/heimdall-ledger-mcp is a shipped MCP server over stdio JSON-RPC exposing six tools — read_claims, make_claim, release_claim, read_capsules, append_decision, raise_conflict_pr — so any MCP-capable client joins the same claim surface with HAID attribution, declared at initialize via clientInfo.name (PROTOCOL.md §"MCP Interop Contract"). Two agents from two different tools editing the same repo can avoid each other today. The verification gates themselves are Claude Code hooks.json mechanisms and do not run outside a Claude Code session yet; that work is roadmap, marked COMING, not shipped. The same boundary is written out on the FAQ.
Heimdall runs agents too, and gates itself with the same oracle. rr is a hosted maintainer: it clones your repo with your own Claude subscription and your own GitHub App installation, runs the issue-resolution loop until the fix passes the gates, and opens a heimdall/* pull request that a human merges. Its multi-tenant isolation is not a promise — bin/falsify rr-multitenant-isolation --assert-score 1.0 treats every cross-tenant attack as a mutant and fails the run unless all of them are killed. Bringing that loop up on real Cloud Run took a 29-bug ladder, all 29 named and published in Local green is not evidence.
The category is not the enemy. The unverified merge is.
What Heimdall does not do
- It does not run your agents. If your agents live in OpenHands or in Copilot's Actions sandbox, they stay there.
- The gate suite is Claude Code hooks today. Cross-tool gating is not shipped; only the ledger is.
- The generalization number is modest and published as-is: 0.50 median reuse across 8 cold repos, with the full sorted per-repo table committed at
ae88a55. The companion "8/10 working output" figure is adjudicated, not raw — the raw machine count in that run is 6/10, and the four adjudication layers are written down. Quote it with the word adjudicated or do not quote it. - The corpus is 13 cases at v0.1. That is small, and it is published as a time series with a dip log rather than as an adjective, so you can watch it move instead of trusting it.
/dreamworks the codebase overnight and leaves a morning report. It never auto-pushes. Triage is captured and shared across the team; promoting a case into a standing rule is a manual, human-reviewed weekly decision, not a synthesis step.- The gates run locally, and what leaves the machine is enumerated rather than sloganed. Three things leave, each opt-out or opt-in-by-use, and none of them are your source code: a presence heartbeat, your explicit
rrtraffic, and an unauthenticated version check. The exact fields, endpoints and per-item kill switches are listed on the FAQ and inDATA.md.
The decision rule
One agent, one reviewer, every diff read line by line — a gate buys you very little. You are the gate, and you are still fast enough.
Leave agents running unattended and the arithmetic inverts. The reviewer becomes the constraint, the agent's own suite becomes the only evidence anyone actually has time to look at, and the failure mode is not a bad diff. It is a green one nobody could check.
Run agents with whatever runs them best. Do not let the thing that wrote the code be the thing that certifies it.
Nothing ships unproven.
Sources, checked
This post describes other people's products, so every line about them was re-read against that product's own live documentation on 2026-08-04 before it shipped. Two claims in the draft did not survive that read. They were cut rather than softened, and the cut is recorded here instead of being quietly repaired.
| Claim as drafted | Checked against | Outcome |
|---|---|---|
| OpenHands agents "can do anything a human developer can: modify code, run commands, browse the web, call APIs" | OpenHands/OpenHands README | CUT — that sentence is not in the README. The README has been rewritten around Agent Canvas, and All-Hands-AI/OpenHands now redirects to OpenHands/OpenHands. The quote was replaced with the live wording. |
| Agent Canvas — what it is | OpenHands/OpenHands README | SOURCED — quoted verbatim from the README's own description. |
| "Copilot coding agent": assign an issue, ephemeral Actions environment, pushes to a draft PR, requests your review | About GitHub Copilot cloud agent | CORRECTED — the product is documented as Copilot cloud agent; the old coding-agent URL now redirects to cloud-agent. The ephemeral GitHub Actions environment is confirmed verbatim. "Requests your review" is not the live wording and was replaced with it. |
| Actions workflows need approval from a user with write access; the agent cannot approve its own PR; branch protections and required checks still apply | Risks and mitigations | CONFIRMED — all three, verbatim. |
The Heimdall-side numbers in this post are traceable in-repo and need no external check: the falsify semantics and the flagship scores in evals/flagship/STATUS.md — exchange-lob 6/6 and emulator-gb 3/3; the 13/13 corpus and the 2026-06-12 F:10 → F:20 dip in evals/corpus/CORPUS-STATUS.md; the six MCP tools in PROTOCOL.md; and the 0.50 median reuse with its adjudicated 8/10 versus raw 6/10 at commit ae88a55.
The gates that can actually go red.
The isolation oracle, the regression corpus, and the numbers behind them — listed, not hidden.