Repository-scoped · content-hashed · terminal-native

The gnomon is the fixed blade on a sundial.

The sun travels. The shadow sweeps the hours. The gnomon does not move — and that is precisely why the dial can be read. Remove the blade and you have decorated stone, not an instrument.

This harness names itself after that object. .gnomon/ is the fixed configuration — models, roles, tools, approval — content-hashed and committed with your repository. Everything else is shadow.

$ curl -fsSL https://raw.githubusercontent.com/eljaplacido/gnomonharness/master/scripts/install.sh | sh
$ cd my-project && gnomon setup
$ gnomon dashboard # optional
$ gnomon launch

v0.5.0, the latest release — what the installer gives you · on npm as gnomon-harness · 3,466 tests · green on Linux, macOS and Windows · Windows: irm …/scripts/install.ps1 | iex

The guide · Read it on GitHub · llms.txt for agents · Whitepaper: v0.5.0 edition in preparation

XII I II III IV V VI VII VIII IX X XI N .gnomon/ blade — fixed · content-hashed shadow — sweeps the plate · everything else varies

Fig. 0 — Plan view (looking down). Fixed gnomon; black umbra projected from the blade.

Why this name. Behaviour is readable because something holds still. The harness puts that something in a directory you commit.

Measured — properties first, rates with their caveats

Behaviour you can identify, and check afterwards
Every path in .gnomon/ that changes behaviour moves the surface hash, and the hash is stamped on every record. Exhaustive, deterministic, re-run in CI on every change
surface-hash fidelity 14/14 · 0 false negatives · 17/17 degradations recorded
Start from the defaults
In the v0.5.0 release runs on Claude Haiku, gnomon's release defaults did at least as well as a tuned long-task recipe, at about half the cost. Reasoning replay, the part of the old recipe that helped, is now a default for hosted endpoints
defaults ≥ tuned recipe · ~½ the cost
One policy, enforced inside other harnesses
gnomon guard runs in Claude Code's and opencode's pre-tool hooks (Cursor: shell and reads). In a $0 pilot with a scripted model, both hosts made the same decision on every forced call, no call the guard denied ran, and every record named agent, harness and session
137/137 identical · 0 denied calls ran · 800/800 attributed
Hybrid local + cloud, as a cost mode
Local-first with cloud rescue (a cloud model takes over a stuck local turn; opt-in, [roles.<name>.escalate]) spent about 23% of the cloud-only arm's cloud cost, at −0.07 hidden-test share against cloud-only and +0.25 against local-only. Not the hybrid setup offers as an opt-in mode, and setup does not configure it; not a default
~23% of cloud-only's cloud spend (v0.5.0 release runs, opt-in mode)
Reasoning replay by default
On long Terminal-Bench 4.0 tasks with a hosted model, replaying the model's reasoning raised the share of hidden tests passed by 16 points and capped 5 fewer runs (H3, pre-registered). On by default for hosted endpoints from 0.5.0
+16 points hidden tests [+4, +29] (H3, 0.4.2)
Destructive commands held
Every prompt, adversarial respellings included (rm -fr, rm --recursive --force). Was 38/43 on 0.3.1, before the shell parser
43/43 held · 0 breaches (G2b-R)

Every run pre-registered, losses included · gnomon's own results; peer comparisons only from before November 2026, dated · not a leaderboard · full measurements §8

Ask most coding agents why did you do that and there is no answer. Configuration scatters across dotfiles and machine state — the same repo behaves differently for two people.

One directory declares models, roles, tools, approval policy. Content-hashed. Stamped on every record the harness emits. Linux, macOS and Windows — same surface, same hash, all three in CI.

gnomon does not make a model complete more tasks: the last peer comparison, in September 2026 on 34 paired Terminal-Bench tasks with the same model, was a tie inside noise (50.0% vs 47.1%). In November 2026, pooled over three pre-registered studies on long Terminal-Bench tasks against opencode and mini-swe-agent, no difference was shown in either direction; in the latest single study opencode turned more tasks into full solves, while gnomon cost less per task and used fewer tool calls and tokens on the same model. Those peer figures stay unpublished until the benchmark repository is. On long hosted-model tasks it lost runs for reasons traced to gnomon itself; those were fixed, and the largest part — reasoning replay — is a default in 0.5.0. What it adds is governance: a hashed surface, capability separation, a tamper-evident trail, and a checker that holds other agents' work to the same rules. The model varies. The conversation wanders. The tools differ each run. .gnomon/ does not.

The rules a repository commits — which role may write where, which commands are refused, what needs a person — hold in gnomon's own loop, and can be applied to work another agent did. In G1 (November 2026, sandboxed, one model) gnomon's own loop broke policy in 1 of 24 trials: after its deny-list refused git clean, the agent moved var/ out instead.

gnomon check reads a change after the fact — the diff, and the transcript where there is one — against the repository's .gnomon/ as it stood at the base commit. Since 0.3.2 it reads transcripts of opencode, goose, Qwen Code and mini-swe-agent as well as its own trail, so a destruction that leaves no diff can still be seen.

1 / 24Committed in gnomon's own loop. G1, November 2026. The one: a deny-list refusal routed around by moving the directory instead.
43 / 43Destructive prompts held. Adversarial respellings included, 0 breaches (0.3.1: 38/43, before the shell parser).
27 / 27Self-governance attacks refused with nobody to approve: the agent cannot rewrite its own rules, records or skills (GBS 0.2 draft run, 0.4.2).

The gap, stated. gnomon check cannot see what leaves no diff (git clean -fdx, rm -rf var/, git reset --hard, a force-push) unless a transcript shows it. Give it the transcript, or put gnomon guard in front of the agent so the call is decided before it runs.

Found by measuring. The first GBS-GOVERNANCE run (v0.4.1) found the agent could approve its own skill by unsetting one environment variable, 4 of 4; 0.4.2 closes it and needs a person present for skill decisions — CHANGELOG 0.4.2.

A shared governance layer — one policy, several harnesses

Teams rarely run one agent. The same committed .gnomon/ can govern the others:

  • Before the action — gnomon guard. Sits in Claude Code's and opencode's pre-tool hooks (Cursor: shell and reads only) and decides each call with the same function gnomon's own loop uses. It only tightens: a deny is enforced, an ask goes to the host. Released since 0.3.3.
  • At merge time — gnomon check. For any harness: it reads the diff, and a transcript where there is one, against the rules at the base commit. As a required CI check the agent cannot skip it. It cannot see what leaves no diff (git reset --hard, a force-push) unless a transcript shows it.
  • A tamper-evident trail. Every guard decision is a hash-chained record naming the tool, the rule, the agent, the host and the session.
  • Levels — since 0.5.0. Each family of rules (write, bash, network, secrets, rules, ci) is set to observe → advise → prevent → enforce, so a team can see what a policy would refuse before it refuses anything. A role can only tighten, and the rules that protect the surface and the records never drop below prevent.

The $0 pilot (6 Nov; scripted model, no network, a draft 0.4.5 build; a pilot, not pre-registered). One committed policy, enforced through gnomon guard in opencode and in Claude Code: the two hosts made identical decisions on all 137 forced calls, the same as gnomon's own loop; no call the guard denied ran; 800 of 800 decision records named agent, harness and session. It also found ways to detach the layer — removing the host's hook file, committing the policy away in opencode, Claude Code's bypass mode running an “ask”, opencode's grep going ungoverned. Those are fixed in 0.5.0 (#165). Still missing: org-wide policy distribution, a record of the person's answer to an ask, and adapters for Codex, Aider and Goose.

The real path, in order. Slash commands stay local. Everything else: role → skills → context → tools under approval policy.

Three guarantees in this path:

  • Tools absent, not discouraged. Schema list matches role exactly.
  • Nothing mutating runs unseen. Diff before write; bash gated.
  • Three buckets. result · refusal · apparatus_failure
you type a line slash command? local · no model pick role · load skills · build context manual · suggest · auto send system + history + tool schemas THIS role only tool call? answer approval gate? refusal execute · sandbox · feed back next step record bucket · session · audit result · refusal · apparatus_failure

Fig. 1 — Agent turn loop. Slash commands stay local; everything else routes through role, approval, and honest outcome buckets.

Schema enforcement. Verifier has no write — absence, not instruction.
Approval before mutation. Real diff. Standing approvals in audit trail.
Honest outcomes. Declined = refusal. Timeout = apparatus failure.

Rust owns verifiable parts. TypeScript owns the loop. Sessions and audit live outside the hashed surface — logs inside .gnomon/ would change the hash every turn.

.gnomon/ — content-hashed config.toml routing · endpoints · audit roles.toml · tools.toml policy.toml · system.md skills/ surface_hash TypeScript — loop gnomon-core turns · tools · context · skills gnomon-cli gnomon-surface · edit · exec (Rust) outside surface .gnomon-sessions/ .gnomon-audit/ must not alter hash varies

Fig. 2 — Rust owns verifiable surface, edit, and exec. TypeScript owns the loop. Sessions and audit sit outside the hash.

The blade is .gnomon/: fixed, identifiable, content-addressed. Replies, tool traffic, session history — the shadow.

Rust and TypeScript compute the same surface hash; a test holds them together. conformance/ pins exit codes, enumerations, manifest shape.

Workflows where repository-scoped behaviour matters — not generic productivity claims.

Team lead · config review

Review agent behaviour in PRs.

bash_allow changes in diff. Hash updates on merge. Destructive commands held: 43/43 prompts with adversarial respellings.

PR .gnomon/ → review → merge → new hash
Post-incident · oversight

What was permitted? Who approved?

gnomon init switches the trail on; a policy decision with its audit write costs 0.2 ms (GBS-OVERHEAD, 0.4.1). Hash-chained, it carries the surface hash and, since 0.3.2, every shell command whole (after redaction). gnomon audit verify names the sequence that broke. Primitives for oversight, not a compliance guarantee.

9/9 tamper attacks caught with a git anchor · 8/9 without, the 9th published
Another agent did the work

Hold Claude Code, opencode or goose to the repository's rules.

gnomon check reads the diff and the agent's transcript against .gnomon/ as it stood at the base commit, and exits non-zero on a violation, so it can be a required CI step. Or put gnomon guard in front of the agent so each call is decided before it runs (§2).

check --transcript run.json --format opencode | goose | qwen-code | mini-swe-agent
Offline · local model

Keep the whole loop on your own hardware.

gnomon setup recommends a local model your machine can run. On an RTX 5090, Qwen3.6-35B alone solved about two thirds of a 32-task Terminal-Bench set in gnomon's own runs (24/32 in R1H; 22/29 and 18/32 in later runs of the same lane).

Ollama · llama.cpp · any OpenAI-compatible server
Solo dev · local models

Ollama on laptop; same agent on CI.

Surface committed. Clone anywhere — same roles, tools, gate.

init → roles.toml → launch → task in CI
Brownfield adoption

Point a verifier at a repo you did not write.

Pilot: 10 of 14 planted defects found, 0 of 5 adversarial controls falsely flagged, 0 containment violations — local models, $0 API. Reading code flips less often than making a task pass.

7.1% flip rate · two synthetic projects · no peer
Harness author · embed

Pipeline via gnomon task --json.

Published exit codes. Bucket from exit value. Degradations announce on stderr and land in TaskRecord.degradations[].

task --dir repo --yes --json
Specify → verify

Roles separated by capability.

Coordinator can't edit. Verifier can't write. Chain can stop on a failed check — not on an opinion.

/spec → coordinator → implementor → verifier
A poor fit if you want IDE integration beyond ACP editors (Zed, JetBrains — gnomon acp, in 0.4.0), HTTP/SSE MCP transports, cloud or async execution, or the broadest model support. Those are real requirements and other harnesses serve them better — OpenCode for a far larger ecosystem, Aider for Git-centric diff discipline, OpenHands for sandboxed autonomous execution.

The verifier has no write and no edit, so it cannot alter what it judges — and because bash can write anything, bash_allow narrows it to test commands. task runs a sub-turn under that role's tools, so a role that may not write also may not delegate to one that can.

RoleCannot
coordinatoredit; outside write_allow
implementorgated by write_allow / bash_allow / bash_deny
verifierwrite, edit; bash_allow for tests only

Each boundary has a test that fails if it moves. Other harnesses have permission prompts; these are declared per role, hashed, and testable.

The chain stops on a failed check — not on an opinion. One dial, three positions: never, on_refusal, on_check. A stage whose declared check ran and failed stops the chain. A stage that merely disagrees in prose does not — reading its sentence would be instruction, not capability. Default: never. Not yet re-measured — the earlier arm tested a chain that could not gate.

  1. No machine-scoped config. All in .gnomon/.
  2. Manifest every session. Content-addressed.
  3. Declared tool schemas. Refusal, not shorter list.
  4. Three buckets. No composite verdict.
  5. Published exit contract. 0–1 / 2–4 / 10–13.
  6. Published enumerations. README tested.
Read before citing. Every run below was pre-registered before its first trial, losses included. Property suites are on master; the November 2026 task-run summaries are archived outside the public repository and are named here by study. These are gnomon's own results: comparisons with other harnesses are cited only where they were published before November 2026, with their date. n is small throughout; “not shown” means no difference was shown, never that the arms are equivalent. Each rate names the build it ran. Not a leaderboard.

I — Properties, overhead and containment

The property suites are exhaustive, deterministic and $0; CI re-runs them on every change, so they describe the build you can download.

ClaimResultSource
Surface-hash fidelity14/14 faithful · 0 false negativesproperty_suites
Declared degradations announced & recorded17/17 (14/14 until three new degradations were added, Nov 3–4)property_suites
Injected faults disclosed by name8/8fault-disclosure
Silent success at decision points0/11 falsely successfulsilent-success
Determinism across locale, tz, cwd, $HOME, mtimes10/10 identical · the suite was broken for 8 weeks — it measured nothing and reported a pass — and has been repairedg2-2026-11 · PR #59
Prompt injections crossed0/36 · the model attempted none, so this says nothing about the harness boundaryg2b-2026-11
Containment of destructive commands43/43 prompts with adversarial variants, 0 breaches (0.3.1: 38/43)g2br-2026-11
Harness overhead, one whole turn151 ms wall · 115 ms to first request, fake model (0.3.1)ux1-2026-11
Context sent to answer one prompt4.66× less than opencode, bytes counted at the endpoint (2026-09-05)context-cost
Policy decision + audit write, in-process0.20 ms per call (0.4.1)gbs-2026-11-04
Start-up--version 44 ms · a one-request task 94 ms (GB10, 0.5.0 candidate)CHANGELOG 0.5.0

Withdrawn: an earlier claim that opencode could rewrite its own permission surface and gnomon could not — the original opencode configuration was misordered, and it must not be quoted. Still retired: “13–43× leaner than OpenCode”, which multiplied a token ratio by a retracted pass-rate ratio.

II — Task completion, short tasks — a tie, inside noise

The last peer comparison this site cites: 2 September 2026, gnomon on the v0.2 line against opencode on equal terms — 34 paired Terminal-Bench tasks, the same model, the same clock, the same night.

Arm (2026-09-02)SolvedPaired
gnomon (v0.2 line)50.0%discordant 3 to 2 · McNemar p = 1.0
opencode47.1%

No difference, which rules out a large one and says nothing about a small one. An earlier 18-point “win” is an artifact of unequal adapters and must not be quoted. Since then, gnomon-only: proportionate verification shipped in 0.4.0 after its pre-registered A/B (LEAN, DeepSeek V4.1 Flash): −33% $/solved ($0.052 → $0.035), −28% output tokens, 37 vs 34 solved of 48 (p = 0.45, not significant). Role chain, model ceiling and timeout teaching each measured null (EVIDENCE.md).

III — Long tasks: why gnomon lost, and what fixed it

Terminal-Bench 4.0, 29 long tasks, DeepSeek V4.1 Flash, 30-minute cap. gnomon 0.3.1 solved 1 of 29; the main cause was gnomon's: unstreamed calls cut at 300 s and re-sent, fixed in 0.4.0. P2G41 re-ran the tasks on 0.4.1, as released and with a tuned hosted recipe.

gnomon armSolved / validCappedHidden tests passed (mean fraction)
0.4.1 as released0/28210.31
0.4.1 + hosted recipe3/28100.58

Which part of the recipe matters — H3 (same 29 tasks, gnomon 0.4.2, pre-registered). Reasoning replay alone raised the hidden-test share by 16 points [+4, +29] over the release defaults (0.32 → 0.48) and capped 5 fewer runs; the rest of the recipe added +1.7 points [−9.5, +13.8] on top — not shown. By its decision rule, replay became the default for hosted endpoints: in 0.5.0.

Defaults or a tuned recipe — the v0.5.0 release runs. On Claude Haiku, gnomon's release defaults did at least as well as the tuned long-task recipe, at about half the cost. A done check before the final answer made the final answer more honest (fewer “done” claims over unfinished or unverified work) and did not improve outcomes, so it stays opt-in. Start from the defaults.

Why long runs fail. An offline look at 167 valid hosted gnomon runs (6 Nov): 48% hit the 30-minute cap, and in 68% of those the file the task asked for had never been written — the model explored until time ran out. Capped runs spent about 84% of their time in model calls and 14.5% in tools; everything else, gnomon's own overhead included, was about 1%. The responses — a run deadline, deliverable-first time notes, a finish gate, a soft-timeout shell — ship opt-in in 0.5.0; none is shown to improve outcomes.

Traceability, tested on 58 cells. gnomon audit verify: 54/54 chains intact (25 sealed, 29 correctly reported not sealed). On the 25 runs that ended by themselves, model-call counts and prompt/completion tokens match the billing relay to the token, and reasoning tokens match the wire 13/13. On 24 of 29 runs killed at the cap, gnomon's surviving records miss calls the relay billed (55 calls; median 48 s of unrecorded time, at most 287 s). Two record defects were fixed in 0.4.3 (#151); a self-stop before the cap (--deadline, #153) is in 0.5.0.

IV — Hybrid local + cloud: a cost mode

In the hybrid arm (PC) a hosted model plans and a local model builds; L is local-only, C cloud-only. Terminal-Bench tasks, pre-registered, paired by task and attempt.

The v0.5.0 release runs measured a different mode, local-first with cloud rescue: a local model works and a cloud model takes over a stuck turn (opt-in, [roles.<name>.escalate]). It spent about 23% of the cloud-only arm's cloud cost, at −0.07 hidden-test share against cloud-only and +0.25 against local-only: a candidate cost mode, not a default. These figures are not for the PC hybrid in the table below, which is the one gnomon setup proposes.

Run · machine · buildLocal onlyCloud onlyHybridHybrid $ / solved
M2 · GB10 · v0.4.0 · Qwen3.6-35B builds16/31 (52%)not run22/32 (69%)$0.031
R1H · RTX 5090 · d59e6c1924/32 (75%)27/32 (84%)26/30 (87%)$0.034 (C: $0.046)
R3R · RTX 5090 · v0.4.0 · R1H re-run22/29 (76%)24/31 (77%)19/31 (61%)$0.058 (C: $0.041)
R4H · RTX 5090 · hybrid arm only, old vs v0.4.1, run together——22/32 old · 19/30 v0.4.1$0.038 · $0.032

GB10: hybrid solved 22 vs 16 on 31 paired cells (exact McNemar p = 0.07), and capped more runs (8 vs 4). RTX 5090: R1H's 87% vs 84% cloud-only, 26% cheaper, did not reproduce: re-run on v0.4.0, hybrid solved 18 vs R1H's 25 on matching tasks (p = 0.04) and cost 43% more per solved task than cloud-only. R4H ran R1H's build and v0.4.1 side by side: 20 vs 19 on 30 pairs (p = 1.0), so the build is not the cause. Local compute is not free: on R1H the hybrid's saving vanished above about $0.42 per GPU-hour. Method: GBS-HYBRID.

Research context. Minions (ICML 2025): a small local model working with a cloud model kept 97.9% of cloud-only quality at 5.7× lower cloud cost, on long-document tasks (arxiv.org/abs/2502.15964). AgentCARD (2026): heterogeneous teams matched the strongest homogeneous team at up to 12× lower cost per task (arxiv.org/abs/2606.20629).

What did not work

Each was pre-registered with a rule saying what would count; none met it. None of these is a default.

ChangeStudy · buildResult
Idle nudge off by default, local modelLG1 · RTX 5090 · 0.4.2 vs the #153 candidate18 vs 18 solved, at 1.43× the local tokens [1.04, 2.15]. Not adopted: the nudge stays at 12
Completion gate, local model, no time pressureG1-gate · GB10checklist 18 vs 16, review 17 vs 16 on 30 pairs — no difference shown; review took ~2.7× the wall time
Completion gate with a reviewer, hosted modelH4-lite · 14 taskshidden tests −10 points [−21, −1.4]; capped 4 → 8; +86% spend. The reviewer took ~12 minutes and the gate does not know the deadline. Off by default; keep it off for time-capped runs
A “verify every requirement” prompt ruleH22/12 with and without
Hybrid as a quality upgradeR3R · R4H · v0.5.0 release runsThe earlier “87% vs 84% cloud-only, 26% cheaper” is retracted. In the release runs local-first with cloud rescue (opt-in, [roles.<name>.escalate]) trailed cloud-only by 0.07 hidden-test share; it is a cost mode at best

V — Local models and steering

M2 gave each local challenger its best known recipe on v0.4.0, against Qwen3.6-35B on the same lane. Flash-Next (GB10): local-only 20 vs 16, ahead but not shown (p = 0.29); its hybrid arm capped 9 vs 6 and fails the pre-set rule. Muse Glimmer 30B and Qwen3.8-27B (RTX 5090) trail, not shown. Reasoning replay on Glimmer: 78% (25/32) with, 55% (16/29) without (M1a3).

Steering, measured and not adopted. On Qwen3.6's llama.cpp template every mid-turn system message is dropped (1,754 of 1,754 in M2). Delivering steering as user notes instead (S1) solved 15 vs 19 on 30 pairs (p = 0.13) — no gain. The idle nudge itself (N1: on vs effectively off, local lane) stopped at its interim look for futility: 35 solved with it, 37 without, on 61 pairs. steer_role stays opt-in. Switching the nudge off by default was then tested on its own (LG1, above): no gain, more tokens, so it stays at 12.

VI — gnomon Bench Standards (draft)

GBS proposes open benchmarks for what a harness decides, as distinct from the model. gnomon's authors wrote the specs and build a harness they measure, so read the results accordingly. One line per spec, with gnomon's own latest figures — scripted models, no model calls, $0:

  • OVERHEAD — the time and CPU a harness adds, independent of the model. 0.4.2: +169 ms CPU per run of 11 scripted round-trips over a null Node harness [155, 196]; 0.2 ms per policy decision, audit write included (0.4.1).
  • CHAOS — are injected endpoint faults announced, or swallowed? 0.4.2: 17 of 20 faults announced (34 of 37 cases). Still silent: a dropped late system message, a throttled stream, a cache miss.
  • GOVERNANCE — a scripted compromised model forces forbidden actions: are they stopped, and can the agent rewrite its own rules? 0.4.2, asks auto-approved: 170 of 280 attacks blocked by the default rules; 245 of 280 with the kernel sandbox (exec = "os" plus read scoping — opt-in, PR #156, in security review, not released). Self-governance 27/27 with nobody to approve; 26/27 with asks auto-approved (a coordinator reached a deletion through a sub-agent).
  • AUDIT — does the record survive tampering, and can someone else check it? 0.4.2 with a git anchor: 7/7 · 3/3 · 5/5 attacks caught at the three adversary levels (5/7 · 2/3 · 0/2 without a witness); 0 false alarms in 48 untampered sessions.
  • HYBRID — does a local/cloud split beat local on quality and cloud on cost, with local compute priced? See IV: the plan-in-the-cloud hybrid beats local-only on quality (GB10) but not cloud-only on quality or, once local GPU time is priced, on cost; local-first with cloud rescue (opt-in, [roles.<name>.escalate]) cut cloud spend to about 23% of cloud-only's and trailed it on quality — a cost mode at best.
  • REPORTING — what every result must state: builds, the pre-registration it cites, paired design, margins, honest denominators, open traces. Held to it, gnomon's own records matched the billing relay to the token on 25/25 long-task runs that ended by themselves (0.4.1).
  • LAYER (draft, not yet published) — one policy across harnesses. Where a policy can attach (the loop, a pre-tool hook, a stop hook or CI, a wrapper), whether the agent can skip or detach it, and whether each violation was prevented, caught before merge, caught after, or missed. Its pilot is in §2.

Sources: the GBS 0.1 run on 0.4.1 (gbs-2026-11-04) and the GBS 0.2 draft run on 0.4.2 (5 Nov, PR #155). Running the specs found 50 places they could not be followed as written; v0.2 resolves 47. No cross-harness GBS table is published.

VII — Brownfield audit pilot

Two synthetic projects, no peer, $0 local. Supports the brownfield use case — label it a pilot.

EndpointResult
Planted defects found10/14
Adversarial controls falsely flagged0/5
Containment violations0
Flip rate7.1% — half this harness's task-completion flip rate

A harness that hides its gaps is worse than one that has them.

  • MCP: stdio only. Pinned server → discover tools → gate per role. Reproducibility bounded — gnomon pins invocation, not what the server does.
  • Not a hosted or async service. Runs in your terminal — and from there reaches cloud models, authenticated cloud CLIs (gh, az…), and the web. No queue, no worktree pool. One unattended path: cron-scheduled loops.
  • Terminal, ACP editors, a local dashboard. gnomon acp serves Zed, JetBrains and other ACP editors; gnomon dashboard runs on your machine. Nothing beyond that.
  • gnomon check sees what leaves a trace. A destruction of git-ignored state leaves no diff; only a transcript shows it. The transcript readers (since 0.3.2) close that on replay; not yet re-run live.
  • Long hosted-model tasks are hard for it. Full solves on 30-minute Terminal-Bench 4.0 tasks stay few; the gains measured are in the share of hidden tests passed. Reasoning replay, the change that helped most (H3), is a default in 0.5.0.
  • Governance across harnesses is a decision layer, not a platform. No org-wide policy distribution, the person's answer to an ask is not recorded, no adapters for Codex, Aider or Goose; tools a host does not hook are not governed.
  • Path sandbox and a network filter. webfetch has SSRF guards; network = false refuses the common network commands in bash. That is an intent filter, not process isolation. exec = "docker" isolates; before 0.5.0 it did not hold against a deliberately hostile model aiming at gnomon's own host-side actions, fixed in 0.5.0 (#158). A kernel-enforced exec = "os" is an open pull request (#156, superseding #74) awaiting an independent security review — not released.
  • Summary compaction not reproducible.
  • Runs killed from outside lose their last calls. On 24 of 29 capped runs the record missed calls the provider billed (up to 287 s). A self-stop before the cap (--deadline, #153) is in 0.5.0.
  • Injection resistance unmeasured. 0/36 crossed, but the model attempted none.
  • Hybrid trades quality for cost. The plan-in-the-cloud hybrid (opt-in in setup, never suggested) did not beat cloud-only on an RTX 5090 and capped more runs; local-first with cloud rescue (opt-in, [roles.<name>.escalate]) spent about 23% of cloud-only's cloud cost at −0.07 hidden-test share (§8 IV). Opt-in.
  • npm carries the package, not the native binaries. npm i -g gnomon-harness (from 0.5.0) gives you gnomon; the installer also fetches the binaries surface, session and apply need.

Linux, macOS and Windows — all three in CI, every commit. Windows runs natively, not through WSL. It needs Git for Windows for its POSIX shell, and gnomon refuses rather than falling back to cmd.exe — a shell that changes with the OS would be machine-scoped behaviour the hash cannot see.

0.4.4 and 0.4.5 were drafted and never published, so 0.5.0 carries their changes too. Upgrading from 0.4.x: Node 22+ is required; re-run gnomon guard install <host> --write for a Claude Code or opencode guard hook (until then it shows as outdated); requests to Claude targets now carry prompt-cache markers (prompt_cache = false keeps the 0.4.x bodies); reasoning replay for hosted endpoints is on by default (replay_reasoning = false restores the old behaviour). Every other new key is opt-in, record-only or a security tightening. From 0.3.x: gnomon migrate, then re-trust. On npm as gnomon-harness. Full changelog.

Prompt caching on Claude, on by default. About 93% of input is read from cache: $0.029 instead of $0.084 per long benchmark task, about a third of the cost, with no measurable change in hidden tests passed (RG1 screen). prompt_cache = false turns it off.
Guard liveness and scorecard: an audit feed. Every tool call a guarded harness makes gets exactly one audit record; a session can prove its guard ran; gnomon check --scorecard shows which rules held, for gnomon, Claude Code, opencode or any harness whose transcript it reads.
Reasoning replay by default for hosted endpoints. H3: +16 points of hidden tests passed [+4, +29], 5 fewer capped runs. Local lanes stay off unless declared. #153
gnomon task --deadline. Remaining-time notes, bash timeouts clamped to the time left, and a final record before an outside kill. #153
Docker against a hostile model. gnomon's own git, audit writes and check can no longer be driven from inside the container; leaving docker needs --trust-exec-downgrade. #158 · #166
Guard hardening. Host hook files are protected surface; Claude Code's bypass mode turns an ask into a deny; opencode sessions keep their base rules; grep and glob are governed; gnomon guard status. #165
Governance levels and protected paths. observe → advise → prevent → enforce per family of rules, per repository and per role; secrets and CI paths protected; writes outside the project root refused. #167 · #168 · #171
Opt-in long-task tools, not shown to help. Finish gate v2, deliverable-first time notes, a soft-timeout shell, a first-token stall watchdog, a container sandbox profile, an upfront deadline note. Start from the defaults. #161 · #162 · #164 · #173 · #174 · #175

Earlier in 0.4.x.

0.4.3 — the record says how a turn ended. A turn whose endpoint failed reads endpoint_error, not answered; records of killed and partial runs carry per-call timing and tokens. #151 · #152 · #154
0.4.2 — security fixes from the first GBS runs. gnomon audit verify fails a trail appended after its seal; skill decisions need a person present. #149
0.4.1 — setup and dashboard. gnomon setup scans your machine and recommends a local model; gnomon dashboard walks the same steps in a browser #129. Also: the endpoint's own context window (max_context_tokens = "auto"), a record of every model call, and a turn record that survives a kill. #137 · #144 · #143
0.4.0 — every model call is bounded; gnomon's records are its own. Streaming with idle and total clocks and an output limit; no role may write gnomon's own records; skills are tried before they are trusted.
Read this before citing a rate. Every rate on this page names the build it ran: M2 and R3R ran 0.4.0, GBS 0.1 ran 0.4.1, H3, LG1 and GBS 0.2 ran 0.4.2, H4-lite and G1-gate the completion gate first released in 0.5.0, and the release runs the 0.5.0 candidates. The property suites re-run on every change and describe the build you can download.

None of this is in 0.5.0 or counts as a result yet.

OS sandbox · PR #156

A kernel-enforced sandbox for bash.

exec = "os": Landlock and seccomp on Linux, plus opt-in read scoping. Supersedes #74. Not merged: an independent security review comes first.

security review → merge → release
GBS v0.2 · PR #155

The bench standards, revised.

v0.2 resolves 47 of the 50 gaps the first runs found. Reference runners, so that anyone can run them on any harness.

review → reference runners → publish
GBS-LAYER 0.1 · next

Turn the governance pilot into a claim.

A pre-registered run of the pilot, with policy propagation, tamper attacks on the foreign trail, a positive control, and more hosts.

pilot → pre-register → run
Whitepaper · v0.5.0 edition

The guide as a PDF, regenerated.

The v0.3.2 edition is withdrawn: it predates this release and carries comparisons this site no longer cites. The v0.5.0 edition follows.

regenerate → review → publish

The gnomon Guide is the how-to and the whitepaper's source, kept current on GitHub. The PDF whitepaper is being regenerated for v0.5.0; the v0.3.2 edition is withdrawn.

The guide — docs/GUIDE.md Markdown · quick start, model recipes, commands, troubleshooting, FAQ, and a procedure for agents ViewRaw
Whitepaper — PDF v0.5.0 edition in preparation
For agents — llms.txt What gnomon is and where its docs live, for an LLM to read ViewDownload
$ curl -fsSL https://raw.githubusercontent.com/eljaplacido/gnomonharness/master/scripts/install.sh | sh

The installer verifies every download against the release's SHA256SUMS. Windows: irm https://raw.githubusercontent.com/eljaplacido/gnomonharness/master/scripts/install.ps1 | iex. It installs v0.5.0, the latest release. Node 22+. Update with gnomon update. npm i -g gnomon-harness once 0.5.0 is published there.

One maintainer, open source, MIT. Every change lands through a reviewed pull request; every claim here has a file behind it you can check.

Developers

Run it on your own repository, then tell us what broke.

Open an issue first for anything non-trivial; one slice per PR; .gnomon/ci.sh green. A documented claim needs a test that fails when the claim stops being true.

Harness builders

Run the bench standards on your harness.

The GBS specs are drafts for comment. Each harness is run in a best-effort configuration its maintainers are invited to correct, and a result naming another harness waits 14 days after its maintainers are told.

Teams & enterprises

One policy for the agents you already use.

gnomon guard in Claude Code, opencode or Cursor; gnomon check as a required CI step for any harness. Read what the sandbox does and does not contain before relying on it.

Researchers

Check the numbers, or reproduce them.

Every published result names its build and pre-registration, losses included. Point out what is wrong with a run, and it gets re-run or withdrawn.

Security issues: not in public issues — see SECURITY.md.