Skip to main content

gonogo

❖ Communityv0.2.0★ 0

Turn a pilot-scale eval score into a deployment decision — Wilson intervals, a confidence threshold that routes uncertain cases to a human, and an honest INSUFFICIENT EVIDENCE verdict when the sample cannot support the claim.

Open in Hermes Desktop
hermes plugins install gonogo

What it adds

Tools 3

gonogo_decidegonogo_reportgonogo_compare

README

From the reviewed commit 3f9945d ↗; it updates when the author re-pins.

gonogo — a Hermes plugin

47 out of 50 is not 94%. It lands somewhere between 84% and 98%, so if you were aiming at 95%, you cannot yet say you got there.

This plugin gives a Hermes agent a decision instead of a number. Ask it whether something is good enough to ship and it answers with one of five verdicts, the interval behind it, the confidence threshold that routes uncertain cases to a human, and — when the sample is simply too small to say — that it is too small to say.

hermes plugins install keppy/hermes-plugin-gonogo
hermes plugins enable gonogo

Requires gonogo-eval>=0.3,<0.4, which Hermes installs for you from the plugin's pyproject.toml. The 0.2 line is not compatible: the grouped pairing and paired-interval behaviour this plugin reports arrived in 0.3.

The ecosystem this belongs to

This plugin is the in-session half of a small ecosystem that takes a task from which model? to ship it or not:

your task ──► evalroute ─ choose a (model, effort) arm;
                │         measured where available, priors marked
                ▼
your cases ──► thomas ── train on labels (encoder) or score_text (RL);
                │         evaluate on untouched cases with gonogo
                ▼
              gonogo ── ship it, test a threshold on fresh cases, or walk away
  • gonogo — the library behind this plugin, and the root of the map. Any agent, your real cases, a target; the verdict comes with the interval behind it.
  • thomas — the training harness. RL shares score_text across training and held-out evaluation; encoder SFT instead learns labels and needs a separate held-out evaluation.
  • evalroute — the routing layer: classify the task, hand back the arm with measured costs where available and priors otherwise; collect ratings to prioritize the next controlled batch.
  • The Hermes plugins — the same three, inside your agent's session: this one for decisions, thomas with a human approval hook on its training tool, and evalroute's /route before the first turn.

What it adds

Tool The question it answers
gonogo_decide "Is this good enough to ship?" — from a pass count or a results file
gonogo_report "Give me the report artifact" — for a doc, a PR, a pilot review
gonogo_compare "Is B actually better than A?" — McNemar on paired cases

Plus a bundled skill, gonogo-verdict, that loads the reporting discipline with it: quote the interval and not the point estimate, read the verdict off the lower bound, keep the calibration caveat, keep the self-implicating detail in.

Why a plugin and not a library

The library already exists — pip install gonogo-eval. What a plugin changes is who asks. Any Hermes session can now end a measurement with a defensible call instead of a plausible-looking percentage, in the same conversation where the measurement happened, without anyone remembering to go run a script.

A worked exchange

You: The invoice router got 47 of 50 right. Ship it?

Agent: (calls gonogo_decide with passed=47, total=50, target=0.95)

**ASSIST ONLY** — pass rate 94.0% [83.8%, 97.9%] is below the 95% target
and no confident subset reaches it; useful as a draft-generator, not as an
unattended step

Pass rate 94.0% [83.8%, 97.9%] over 50 cases (47 passed), target 95%
Note: Every case reported the same confidence, so no abstention threshold can be
derived. Emit a real per-case confidence to unlock selective automation.

Two things that matter there. The interval reaches down to 83.8%, so 94% is not the number the decision gets made on. And the tool noticed the results carried no per-case confidence — which is what a review threshold would have been built from, so it says so rather than silently reporting an overall rate.

Give it a results file with confidence on it instead and the same call finds the operating point:

**AUTOMATE WITH REVIEW** — overall pass rate 85.0% [73.9%, 91.9%] misses the 90%
target; a candidate threshold at confidence 0.86 reaches 100.0% precision on 85% of cases on this selection set, but needs a fresh holdout before deployment

Candidate operating point (fresh holdout required): abstain below 0.86 → 85% cases selected at 100.0% precision 100.0% [93.0%, 100.0%], 9 cases to review
Calibration error 0.10
Note: The 0.86 threshold was chosen by searching this same case set, so its
precision is optimistically biased. Re-measure it on fresh cases before relying on it.

That last note is the plugin's own caveat, not a user's: a threshold found by searching the case set it is scored on is biased upward. can_automate remains false for this candidate; holdout signoff is a separate step.

The results file

One JSON object per line. passed alone is enough for a one-run verdict. For gonogo_compare, every row in both runs needs the same stable, explicit id (and matching group membership if grouped); generated row positions are not paired evidence. The file is plain enough to build in a spreadsheet.

{"id": "inv-001", "passed": true,  "confidence": 0.97, "expected": "Acme Supply", "output": "Acme Supply"}
{"id": "inv-006", "passed": false, "confidence": 0.42, "expected": "Acme Supply", "output": "Cinder Works", "detail": "normalized the trading name to its parent entity"}
{"id": "inv-007", "passed": false, "error": "TimeoutError: 30s"}
{"id": "inv-008", "passed": false, "abstained": true}
  • confidence (0–1) is optional for an entire file, but mixed missing and present values are rejected; it is what unlocks a candidate review threshold.
  • error is a crashed case — a failure, not an aborted run. abstained lands at zero confidence, so a threshold defers it first.
  • group on every case folds correlated checks into one trial per group.
  • examples/invoice_routing.jsonl is a 60-case synthetic set to try it on.

gonogo_report with save_report writes the report JSON, and gonogo_compare pairs two of those by case id (or by group id with matching case membership) — so a run measured today can be checked against one measured last week.

What it can touch

Three tools, and nothing else: no hooks, no middleware, no environment variables, no credentials, no network. Count-only calls need no file; results calls read the path you give them and optionally write report JSON or HTML when requested. The whole blast radius is the one dependency and those opt-in files.

Development

uv venv .venv && uv pip install --python .venv/Scripts/python.exe gonogo-eval pytest pyyaml
.venv/Scripts/python.exe -m pytest tests -q

hermes plugins validate .     # the catalog admission gate, including the security scan
hermes plugins doctor . --ci  # discovery, manifest, import, registration

The tests assert the verdicts themselves — that 47/50 at a 95% target is ASSIST ONLY, that the same 47/50 at 90% is INSUFFICIENT EVIDENCE needing about 204 cases, and that a 3-point gap on 60 cases is not an improvement.

MIT. The statistics are gonogo's; this plugin is the surface that lets an agent ask for them.

evalroute❖ Community★ 1

Route a task to the right (model, reasoning effort) arm before you start. Classifies the task into a lane, prints a provenance-carrying route card, and installs per-model reasoning-effort defaults. Strong rules run locally; weak-signal classification calls the host LLM and consumes tokens. The separate harness and shim can make paid provider calls when explicitly run; no plugin-owned credentials. Disclosure — weak-signal task classification sends the task text to your active Hermes model via the host LLM facade (token cost). The model-callable tool, /route, /rate and observed /model and /reasoning commands append task text and command args to a local ledger at <HERMES_HOME>/evalroute/labels.jsonl. "hermes evalroute install-routes" rewrites agent.reasoning_overrides in config.yaml when you run it. The bundled harness and Hermes shim are never run by the plugin. When run by hand they make paid provider calls, execute model-generated code on the host via shell checkers, and run hermes -z with approvals bypassed. Disclosure — "hermes evalroute sync" (run by hand) downloads the route table from the Hugging Face dataset keppy/evalroute-flywheel into HERMES_HOME and route cards then show that dataset's text; "hermes evalroute dispatch" (run by hand) spawns a single-query hermes chat on the routed model (Nous provider by default) — or, with --runner claude-code, a `claude -p` (Claude Code) process under the user's own Claude account, whose per-run cost is recorded in the local sidecar — with the brief as its query, inheriting the current environment except HERMES_YOLO_MODE (the worker never inherits --yolo; its approvals follow approvals.single_query_mode, default deny), and writes its report and a .dispatch.json sidecar beside the brief. Disclosure — "hermes evalroute contribute" (run by hand only) refuses to run unless evalroute.contribute: true is set in config.yaml, and then uploads redacted outcome rows only — lane, routed arm, confirmed arm, verdict, method, facet counts, ISO week and an HMAC-SHA256 task hash; never task text, notes, paths or the salt — to the user's own path (contributed/<hf-username>/) in the Hugging Face dataset keppy/evalroute-flywheel using the user's existing huggingface_hub login; "--dry-run" prints the exact rows and sends nothing; the per-install salt stays local in <HERMES_HOME>/evalroute/contribute.salt. Since evalroute 0.9.1 (schema 2) the same upload also carries lane-correction rows as lane pairs (from_lane, to_lane, method, week) with no task text, plus the max_turns value and harness name the arm ran under. Disclosure — "hermes evalroute install-encoder <dir|owner/name>" (run by hand only) downloads a small text-classification model (the default id keppy/evalroute-lane-encoder is a 146 MB ModernBERT fine-tune on the Hugging Face Hub) into <HERMES_HOME>/evalroute/encoder/ and from then on "hermes evalroute route" runs it locally, offline, to classify the task when the keyword rules are weak, instead of the LLM call; it needs torch and transformers in the plugin environment (pip extra evalroute[encoder]), which the plugin does not install; "install-encoder --remove" deletes it. "hermes evalroute export-cases" (run by hand only) writes your --lane-pinned route rows, task text included, to a local file you name, for training your own encoder; stdout carries counts only and nothing is uploaded. As of 0.6.2 the plugin is a thin adapter: all behaviour lives in the PyPI package evalroute (>=0.9.2,<0.10), declared as a Python dependency that Hermes installs on your confirmation.

Tools
thomas❖ Community★ 0

Fine-tune a small calibrated encoder classifier on Modal and rate it with gonogo. Every GPU launch goes through the human approval gate with the exact config shown; data checks and evaluation run locally for free. Disclosure — thomas_encoder_train spends the user's Modal GPU credits and uploads the chosen training JSONL rows to Modal after the human approval gate; the base model is downloaded from Hugging Face on the Modal side. Training and inference run in a separate Python interpreter the user configures via THOMAS_PYTHON (with the author's thomas package, torch and modal installed); the Hermes venv only gets gonogo-eval. Runs and artifacts are written under HERMES_HOME/thomas/runs; the eval tool writes report files to the path the model supplies.

Tools

← Back to the catalog · catalog built Oct 8, 2026