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.

cd my-project && gnomon launch

Working, pre-1.0 · 400+ tests · CI green

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.

Performance — measured, preliminary

Uses far fewer tokens per finished task
Counted on completed work, not abandoned runs
13–43× less than OpenCode
Tiny system prompt leaves room for your code
Less overhead on every turn
~1.1k tokens vs 7–16k elsewhere
Keeps up with Goose, clearly beats OpenCode
Same model · same 8 hard Terminal-Bench tasks
≈ Goose · ~2× OpenCode pass rate
The harness itself adds almost nothing
Interactive sessions pay startup once
~33ms logic · ~200ms boot
Full audit trail with no speed penalty
Hash-chained log on every turn
338ms vs 354ms — within noise
MIT licensed — free to build on
Contribute, extend benchmarks, fork without asking
Open source · MIT

Preliminary · terminal-bench-core==0.1.1 · small n · not a leaderboard · full measurements §7

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.

The model varies. The conversation wanders. The tools differ each run. .gnomon/ does not.

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.

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
Team lead · config review

Review agent behaviour in PRs.

bash_allow changes in diff. Hash updates on merge.

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

What was permitted? Who approved?

Hash-chained JSONL + surface_hash. audit verify.

audit on → turn → verify chain
Harness author · embed

Pipeline via gnomon task --json.

Published exit codes. Bucket from exit value.

task --dir repo --yes --json
Brownfield adoption

Survey before writes.

Verifier first. Skills proposed. Implementor last.

init → verifier → skill accept → implementor
Specify → verify

Roles separated by capability.

Coordinator can't edit. Verifier can't write.

/spec → coordinator → implementor → verifier
RoleCannot
coordinatoredit; outside write_allow
implementor— (sandbox reach)
verifierwrite, edit
  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. Methodology and raw data published. Several arms include harness comparators (goose, opencode, pi, omp). Small samples on external tasks — not a leaderboard rank.

I — Capability · Terminal-Bench (Aug 2026)

External benchmark · terminal-bench-core==0.1.1 · 8 hard P0 tasks · same container and verifier · valid-pass % = passes ÷ (trials − apparatus failures).

Modelgnomongnomon +P0gooseopencode
DeepSeek V4 Flash39%36%43%19%
GLM 5.3 Flash38%55%57%27%

Parity with goose (not significant at this n). ~2× pass rate vs opencode. Wins the one discordant task (configure-git-webserver 6/6 vs goose 0/1). Solo run on 30-task subset (gpt-5.3-codex): 15/30 (50%), ±18pp — no comparator on that arm.

II — Token efficiency · internal 5-task suite

Five harnesses, four model tiers, deterministic scoring. Author conflict stated; still useful for context cost. ~1.1k-token system prompt vs 7–16k for opencode.

Tiergnomonopencodepiomp
qwen3.6-35b · tok / task4.3k55k7.2k74k
gpt-5.3-codex · tok / task4.6k76k2.3k30k
vs opencode (completed tasks)13–43× leaner · drift-confirmed Aug 2026

III — Quality · internal suite + external gap

Criteria met (% of scored checks). Frontier tiers saturate — three of five harnesses hit 100% — so external tasks discriminate where the smoke test cannot.

Tiergnomonopencodepiomp
qwen2.5-7b89%31%62%76%
qwen3.6-35b100%71%89%96%
gpt-5.3-codex100%57%100%100%
Same model: internal → TB30100% → 50% — saturation demonstrated

Benchmark found a real bug: "Ask before writing" in system.md caused frontier models to propose edits instead of calling tools (86% → 100% after fix).

IV — Integrity · measurement apparatus

Three-bucket model (result / refusal / apparatus_failure) applied to benchmark scoring. Six apparatus defects found and fixed across the Aug campaign.

Fix / propertyEffect
settle() (commit 0087d00)Apparatus-failure rate on +P0 arms: 38.5% → 14%
Valid-trial scoringCrashes excluded from denominator; crash count printed per cell
Identical adapter clocksPrior 600s cap had penalised gnomon’s slow successes
Conformance fixtures4 golden manifests · 400+ tests · README tested against code

V — Latency & local inference

Speed axes only — harness overhead and local generation. Distinct from token efficiency (II) and capability pass rates (I).

MeasurementResult
Audit trail on vs off338ms vs 354ms — within noise
Startup (tsx boot vs gnomon logic)~197ms vs ~33ms
grep vs bash (same task)1 call / 4.5s vs 11 calls / 25.1s
Local inference · DFlash speculative decoding~1.3–1.5× wall-clock · output-exact

Local inference: DFlash speculative decoding is a free ~1.3–1.5× wall-clock speedup on generation-heavy work; output-exact so quality is unchanged (36/36 tasks pass identically on and off). Does not move token counts (II) or Terminal-Bench numbers (I — those ran on cloud models). Timeout headroom on long local tasks is plausible (p90 at 77% of the cap) but not shown here — this run’s tasks were all <26s. Not run against SWE-bench Verified. Prior Aug 27 hosted sweeps (goose / forge / gnomon / opencode) are directional only — apparatus defects depressed some arms.

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. It doesn't run itself as a background job on someone else's server: no queue, no worktree pool. One unattended path: cron-scheduled loops — ticks on the scheduler.
  • No enforced role chain. Order is yours.
  • Terminal only. No IDE.
  • Path sandbox, not process isolation. Enforced for webfetch (SSRF guards). bash still reaches the network.
  • Summary compaction not reproducible.

Primarily tested on bash · available on Windows through WSL2 · WSL may still have bugs.