Writing a harness adapter
An adapter lives in internal/harness/<name>/ and does two things: render a Profile into the harness’s native config (returning files and warnings), and declare capabilities (Capabilities()), which halo harnesses prints and the docs matrix mirrors. Existing adapters: claudecode, codex, gemini, copilot, cursor, opencode (see ADR-0019 for what a partial adapter renders and warns).
- Research and cite. For every matrix row, find the vendor doc or run the CLI and record the evidence in
internal/harness/FACTS.md(with the source URL). Rows you cannot verify are listed under “Still UNVERIFIED”, never guessed. - Declare capabilities you actually render: version pin, model lock, MCP allowlist, hooks lock, permissions, gateway, headers, telemetry, instructions. Emit a warning for every profile field you cannot render (
hutil.WarnUnsupported); never drop one silently. If the CLI cannot pin its own version, warn thathalodenforces. - Implement render:
Profile(plusGatewayand release info) to files, at the documented managed paths for each OS. MergeHarnessSpec.Overrideslast, and list the override keys you accept inallowedOverridesininternal/policy/guardrails.go(a harness with no entry accepts no overrides). PublishMeta()(internal/harness/harness.go:116:Binary,Installer,ManagedDirs,ManagedFiles) and register the package ininternal/harness/all;halodderives its path allowlist and binaries from it, or it will refuse to apply the files. - Golden tests and release check: rendered output matches fixtures under
testdata/; add a case tointernal/release/check.goso the parsed output is verified forbypassPermissions,danger-full-accessand the profile’s lock settings. - Smoke test in a container: install the pinned CLI, apply the output, confirm the CLI loads it (
--version, a doctor-style command) and that an out-of-range version refuses to start (if the CLI supports it). - Eval driver: headless invocation for
halo evaland event parsing for telemetry normalization. - Docs: update the harness matrix and metrics mapping.
Rollout
Section titled “Rollout”New harness: canary starting at ring0 with the matrix complete, golden tests green and evals passing. Rollback: disable the harness in the profile.
- Never emit a permissive mode (
bypassPermissions,danger-full-accessor equivalents), including via overrides (AGENTS.md invariant 1). - Fail closed when a required key is uncertain.
- Cross-check the adapter’s claims in the docs: a docs/code disagreement is a bug.