npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@geonosis/verify

v3.0.0

Published

One gate runner — tiers of shell steps, run serially, recorded as a JSON gate report.

Readme

@geonosis/verify

Through the front door: geonosis verify — the metapackage pins this and every other kit tool at ONE version, and passes the exit code through unchanged.

One gate runner. Tiers of shell steps, run serially, recorded as a JSON gate report a hook can read.

A repo's gate is already a list of commands — it lives in a verify script, a CI job, and an engineer's muscle memory, and the three drift. This runs the list from one place and writes down what happened, so the Stop hook, CI and the ledger are all reading the same run rather than each re-deciding what "green" meant.

Install

pnpm add -D @geonosis/verify        # bun add -d, npm i -D

--prove is the first thing to run after installing

geonosis-verify --prove

It writes a temp config with one passing step and one that exits 3, runs the real binary over it in a throwaway directory, and checks that the failure reached the report, that the right step is named with the right exit code, and that the process exited 1:

PROVEN — a planted "exit 3" step reached the report and exited 1

A runner that reports green is worth nothing until it has been watched going red on purpose. It touches nothing in the repo it is run from, so it is safe at any time.

Config

geonosis.json in the directory you run it from:

{
  "verify": {
    "fast": ["pnpm typecheck", "pnpm lint", "pnpm test:unit", "pnpm ratchet --tier fast"],
    "full": ["fast", "pnpm build", "pnpm test:integration", "pnpm format:check"]
  }
}

A step whose text is another tier's NAME is that tier, inlined in place, however deep it goes. A cycle is refused by the path it went round rather than discovered as a stack overflow.

proves: how a step can be made to fail

A step may declare its own falsification beside its command:

{
  "verify": {
    "fast": [
      "pnpm typecheck",
      {
        "command": "pnpm lint",
        "proves": {
          "plant": "printf 'debugger\\n' > src/planted.ts",
          "expect": "no-debugger"
        }
      }
    ]
  }
}
geonosis-verify prove fast
  PASS (unproven)  fast/1  pnpm typecheck — no proves declared — nobody has watched this step fail
  PROVEN           fast/2  pnpm lint — the plant made it exit 1 and its output carried "no-debugger"
prove fast: 1 proven, 1 unproven, 0 not proven

Each plant runs in a copy of the tree in a temp directory — one copy per step, so a plant left behind never becomes the next step's finding, and the tree you ran it in is not touched. The step must exit non-zero AND its output must contain expect; a red without that evidence is a red for any reason at all, including the plant having broken the shell.

Half a proves is refused at load: a plant with no expect, or an expect that is blank, would pass on any failure. A proves on a step that names another tier is refused too — a plant belongs to one command.

A step with no proves is PASS (unproven), and that fails nothing. Unproven is not failure; it is the absence of evidence, said out loud on every run — in prove, on the line an ordinary run prints, in the report's "unproven": true, and in the Stop hook's green message. Exit 1 is for a plant that did not produce the red it promised.

There is no default tier and there never will be one. A default that happened to match one repo's script names would run the wrong commands everywhere else and still report green. No geonosis.json, no verify object, or an unknown tier is refused by name.

Running it

geonosis-verify fast
geonosis-verify full --report .geonosis/full.json
geonosis-verify full --exclusive --exclusive-timeout 900
  ok    fast/1  pnpm typecheck (2140 ms) (unproven)
  FAIL  fast/2  pnpm lint (1830 ms)
  skip  fast/3  pnpm test:unit (0 ms)
verify FAIL — fast — /repo/.geonosis/gate-report.json

| Exit | What it means | | --- | --- | | 0 | every step passed AND the report was written | | 1 | a step failed | | 2 | refused — no config, no verify, an unknown tier, an option we do not implement — or the report could not be written |

The last one is the one worth arguing about: a gate that cannot record has not passed. Exit 0 on a green run whose report never landed would hand the caller a pass they cannot go back and read.

The report

.geonosis/gate-report.json, unless --report says otherwise:

{
  "tier": "full",
  "startedAt": "2026-08-30T10:00:00.000Z",
  "finishedAt": "2026-08-30T10:00:04.500Z",
  "ok": false,
  "steps": [
    { "id": "fast/1", "command": "pnpm typecheck", "ok": true, "exitCode": 0, "ms": 2140, "tail": "…", "unproven": true },
    { "id": "fast/2", "command": "pnpm lint", "ok": false, "exitCode": 1, "ms": 1830, "tail": "…" },
    { "id": "full/1", "command": "pnpm build", "ok": false, "exitCode": -1, "ms": 0, "tail": "", "skipped": true }
  ]
}
  • id is <tier>/<n>, numbered within the tier that DECLARED the step — not within the run. An inlined step keeps its own tier, so fast/2 is the same command whether the operator ran fast or ran full. Numbering per run would renumber every fast step the moment full grew one in front of it, and an id that moves is an id nothing can compare against yesterday's report.
  • The run stops at the first red, and the rest are still written down, as skipped with exitCode: -1. A report that silently lost the tail of the tier reads as a shorter, greener tier.
  • tail is the last 40 lines of stdout and stderr, interleaved, with the colour codes taken out. The shell folds the two streams, so they stay in the order they were written; concatenating two captured buffers would not.
  • Each step runs in a subshell. <step> 2>&1 binds the redirect to the last command of the step only, so echo boom >&2; exit 3 would lose "boom" entirely — and a gate whose report is missing the error line is a gate nobody can act on.
  • unproven: true is a step that declared no proves — a gate nobody has ever watched fail. It is recorded on every run and blocks nothing.

The budget a tier declares, and the CI job's own timeout (#161, D-042)

{
  "verify": { "fast": ["pnpm typecheck", "pnpm lint", "pnpm test"], "full": ["fast", "pnpm ratchet"] },
  "budgets": { "fast": 150000 }
}

Milliseconds per tier, optional, and a budget naming a tier nothing declares is refused — a ceiling nothing can be measured against is a ceiling that cannot fire. Over budget prints one WARN line naming D-042 and the tier's verdict is unchanged: a budget is a ceiling a repo chose, never a definition of done. A budget that could fail a tier is a number people raise instead of read. The report carries budgetMs beside the per-step ms, so a CI step reads the timings against the ceiling without re-reading the config.

A budget is not a timeout. It is measured after the run, so it says nothing at all about a job that never finishes — one consumer's CI browser job ran three hours before failing, and every minute of it was billed to a gate nobody could see. Every job that runs a tier declares its own ceiling:

jobs:
  verify:
    runs-on: ubuntu-latest
    timeout-minutes: 30     # the runner's ceiling; the budget is the repo's
    steps:
      - run: npx geonosis-verify full

A scoped fast tier needs a total full tier (#136)

Changed-files linting is what makes a fast tier fast — and it is exactly how a hard cap goes unwatched: two max-lines caps were breached in a Medusa storefront with nothing noticing, because the cap was a finding only a tool the full tier never ran could see, and a file over a cap sits there until someone happens to edit it. The pairing rule: every hard cap needs a FULL-TIER counter, or it is a cap in prose. The fast tier is scoped, therefore the full tier must be total.

What a cached runner can hide

A step like pnpm test that a build runner (turbo, nx) satisfies from cache is green by REPLAY: 50 cached tasks answered a Medusa storefront's full tier while a live, race-caused failure sat in the tree, and only --force surfaced it. The cache is sound for deterministic tests — but a verify step satisfiable from cache means a flaky test's red can be permanently masked by its own earlier green. If a tier exists to catch non-determinism, its step must bust the runner's cache (pnpm test -- --force, or the runner's equivalent) and pay the time; a cached gate proves the tree compiled once, not that it passes now (#128).

stats — the first-try pass rate

Not a gate; the KPI a law diet is judged by. The Stop hook records every turn-end it gated in .geonosis/stop-turns.json, one bucket per day, and this reads it back:

geonosis-verify stats
geonosis-verify stats --since 2026-09-07     # that window, and everything before it
geonosis-verify stats --json
first-try pass rate — the share of turn-ends whose fast tier was green
  before          61 turns ·     18 blocked · 70.5 % first try
  2026-09-07+     58 turns ·      6 blocked · 89.7 % first try

A turn whose fast tier was green on the first run is a turn where the code was written the way the gates accept without being told twice. A blocked turn is a correction loop. --since gives the two windows a before/after needs, from one command and one instrument — the procedure is docs/law-diet.md.

Three refusals, all of them the same refusal: an empty record is not a perfect score. A repo where the hook has never run says "no turns recorded" and gives no rate; a record that will not parse is an error, not zero turns; and a turn the hook never gated (stop_hook_active, where the gate does not run at all) is not counted, because there was no first try to have.

The sibling stop-blocks.json cannot answer this and is not asked to. It is the block cap's working memory, and a green turn deletes its own row from it.

--exclusive

Takes the machine-wide lock @geonosis/ratchet owns, through that package's published entry, so a verify and a ratchet on one laptop serialise against each other rather than each against itself. Three sessions each starting a full gate is how a 25-minute run becomes two hours and produces failures that are about the load and not the code.

The lock is taken only AFTER every refusal has been decided: a run that waits half an hour for the machine and then finds the tier was misspelled has held it against two other sessions for nothing. --exclusive-timeout <seconds> bounds the wait (default 1800) and says who it is waiting for.

Programmatic use

import { loadVerifyConfig, resolveTier, runSteps, shellRun, writeReport } from '@geonosis/verify'

const steps = resolveTier(loadVerifyConfig(cwd), 'fast')
const report = runSteps({ run: shellRun(cwd), steps, tier: 'fast' })
writeReport(cwd, '.geonosis/gate-report.json', report)

What this cannot see about itself

  • It does not know whether your steps measure anything. verify reports what your commands exited with; whether pnpm lint was pointed at the right directory is between you and the ratchet's --prove.
  • .geonosis/ is runner-owned. The geonosis Claude Code plugin refuses agent writes there (D-007) — the scored agent never writes the scoreboard. Nothing in this package enforces that.