harn adapter
harn adapter list [--json]harn adapter show <id> [--json]harn adapter bench [adapters...] [--require-installed] [--json]harn adapter attest [adapters...] --yes [--subscription-only] [--timeout <ms>] [--projection] [--json]harn adapter attestations [--json]harn adapter is the executable source of truth for Harnery’s workflow
adapters. The built-in registry intentionally contains three adapters:
claude-code, codex, and cursor.
The registry describes the Harnery adapter boundary, not every feature in the
vendor product. For example, Cursor Agent can stream JSON, but Harnery’s
workflow adapter currently returns only a normalized final result, so
streaming is declared unsupported for that adapter.
Capability catalog
Section titled “Capability catalog”harn adapter list prints the high-signal claims. harn adapter show <id>
prints every dimension, its support level, and its qualification.
Claims use four states:
| State | Meaning |
|---|---|
supported |
The adapter implements the capability. |
partial |
A narrower form works; read the qualification. |
unsupported |
The adapter does not expose the capability. |
unknown |
Harnery does not have enough evidence to claim either way. |
The current dimensions cover invocation, model and effort selection, turn ceilings, final results, session ids, cost, tool evidence, policy mapping, interruption, streaming, steering, resume, images, and compaction. Context continuity is split into four claims: context telemetry, a pre-compaction signal, a post-compaction signal, and the ability to initiate native compaction.
Conformance bench
Section titled “Conformance bench”harn adapter bench runs without credentials and makes no model calls. It
uses the same invocation planners and result normalizers as production
workflow runs, then reconciles their observed behavior with the registry
claims. A disagreement is drift and exits non-zero.
The full verdict vocabulary is:
| Verdict | Meaning |
|---|---|
supported / unsupported / partial |
Observation agrees with the declaration. |
unknown |
No offline probe exists for that behavior yet. |
skipped |
The vendor binary is unavailable in this environment. |
not_applicable |
The dimension does not apply to the adapter. |
drift |
Executable behavior disagrees with the declared profile. |
A missing binary is a neutral skip by default because the registry can be
tested on machines that do not install every vendor CLI. Pass
--require-installed when the current machine is expected to host every
registered adapter. --json emits the complete report for CI or dashboards.
Basis: how a result was established
Section titled “Basis: how a result was established”Every row also carries a basis, which answers “how do we know” rather than
“what is true”. Verdict and basis are independent
(ADR 0037).
| Basis | Meaning |
|---|---|
adapter |
Checked against Harnery’s own planner, normalizer, or fixture. Proves the adapter contract and says nothing about the installed vendor CLI. |
attested |
Checked by observing the installed vendor CLI on this host. |
declared |
Not checked. The value is the declaration, repeated. |
Most of the bench is an adapter check. A supported session-id row proves that
Harnery’s normalizer can read a session id out of the committed fixture. It does
not prove the vendor still emits that shape. Without a basis column, a clean
report reads as “no disagreement found” when the accurate reading is usually “no
vendor behavior was observed”.
The report includes a basisSummary count per basis so a caller can tell a
measured run from an unmeasured one without walking every row.
The contract dimension
Section titled “The contract dimension”Each adapter profile can record the vendor CLI contract its declaration was
last validated against. The contract dimension compares that recorded version
with the version the installed binary reports:
supportedwhen they match;driftwhen they differ, because the declaration is no longer backed by an observation;unknownwhen nothing is recorded, or the recorded value is not a version;skippedwhen the binary is absent.
A newer vendor CLI is not automatically broken, so a mismatch is drift rather
than failure. Harnery never infers that a dimension is probably still supported
on an unverified version: an undeterminable fact stays unknown.
contract is the only dimension attested without a model turn, because a
version string costs nothing to read.
Live attestation
Section titled “Live attestation”harn adapter attest --yes records what the installed vendor CLIs actually do
(ADR 0038). It runs one bounded
turn per adapter through the same spawn the workflow engine uses, so what gets
attested is the path production takes.
harn adapter attest --yes # every registered adapterharn adapter attest --yes claude-code # one adapterharn adapter attest --yes --subscription-only # match a subscription-only runharn adapter attest --yes --timeout 180000 # per-adapter probe timeoutharn adapter attest --yes --projection # also prove the sandbox is enforcedharn adapter attestations # show records, no model calls--yes is required because this spends real vendor tokens. Nothing else in the
adapter command group makes a model call, and bench never does.
One turn can honestly establish four dimensions: invocation, finalResult,
sessionId, and cost. Dimensions that would need a staged scenario are left
out of the record entirely. If the probe turn does not complete, nothing is
recorded at all, because an unreachable subject evidences nothing.
Proving a sandbox is enforced
Section titled “Proving a sandbox is enforced”--projection adds a fifth dimension, filesystemPolicyProjection, and needs a
staged scenario to mean anything
(ADR 0041). A sandbox that
is declared but never enforced looks exactly like an enforced one at the CLI
boundary: both accept the flag and exit zero. So the probe gives a child a file
to write and checks the filesystem.
It runs a control first, under a mode that permits the write. Without it, a child that simply ignored the instruction would be indistinguishable from a sandbox doing its job. If the control completes without writing, the probe reports inconclusive, skips the treatment turn, and records nothing.
This costs two extra turns per capable adapter, which is why it is opt-in. An adapter that declares no sandbox projection spends no extra turn at all.
Records live under .harnery/adapters/attestations/. They are structural
throughout: version strings, dimension names, timestamps, and digests. The probe
prompt is a fixed constant, so no prompt text, completion text, or host path can
reach the file.
An observation is recorded against the billing mode it ran under.
--subscription-only scrubs API-key variables so the child can only use its
stored login, matching workflow run --subscription-only (and the repo default
in config.jsonc). A child that may fall back to an API key can succeed where
one restricted to its login fails, so a record made in one mode is not cited for
the other.
A record stops counting when the installed binary reports a different version,
when the capability declaration is edited, when it was made under a different
billing mode, or when it fails its own digest.
Stale and tampered records are ignored rather than trusted, and the affected
bench rows fall back to adapter basis.
bench reads attestations but never writes one and never runs a turn. A live
observation that disagrees with the declaration becomes drift, exactly as a
fixture disagreement does.
What the offline bench covers
Section titled “What the offline bench covers”The offline bench proves registration, binary availability, the installed
vendor contract, invocation planning, model and effort mapping, turn-ceiling
mapping, final result normalization, session-id extraction, cost extraction,
and the absence of normalized tool evidence. It also checks pre/post-compaction
claims against the hook wiring that harn init installs. Context telemetry
stays unknown because no static probe can prove a runtime measurement.
Policy, active interruption, streaming, steering, resume, image input, and
native compaction control remain unknown until a safe behavioral probe
exists.
Workflow effort selection
Section titled “Workflow effort selection”Workflow agent() calls accept effort alongside model:
await agent("Review this patch", { adapter: "codex", model: "gpt-5.6-sol", effort: "high",});Claude Code maps effort to --effort. Codex maps it to
-c model_reasoning_effort="…". Cursor’s parameterized model ids can carry
effort for some models, but Harnery deliberately does not rewrite model ids;
separate Cursor effort requests fail before launch.