A small harness for the ongoing verification of a complex system — the thing that keeps asking "is this still healthy?" long after the tests pass and the launch ships.
It is a script, not a project. The harness is ~6 tiny modules that stay small and stable; you'll edit them rarely. All the real, ever-growing work lives in checks/, which belong to your project, not to this repo.
Writing or wiring up checks? The full how-to is
skills/using-verifier/SKILL.md— read it before you add or edit a check. This README is the map of the harness itself.
Everything is a check: a command that prints one Result JSON object to stdout and exits. The harness never knows what a check does — only what it needs to run (its inputs), how to run it, and how to route its result.
{ "status": "pass" | "fail" | "uncertain" | "error", "summary": "...", "findings": ... }- pass — healthy. Ignored.
- fail — the system is wrong. Pages you.
- uncertain — ran fine, but judgment is ambiguous; wants a smarter look. Queued.
- error — the check couldn't run. A blind spot. Queued; escalates if it persists.
Exit non-zero, time out, or print garbage and the harness records an error for you — a check cannot hide by crashing.
Two consequences make this more than a cron runner:
- There is no separate "supervisor" type. A supervisor is just a check whose inputs include other checks' latest results. The whole hierarchy — which manager summarizes which workers — emerges from those inputs. It's a DAG, so one worker can feed several supervisors. A graph of stateless evaluations, not an agent society.
- A run picks its own next run. Alongside its status a check may emit
nextRun: { inMinutes: 60 }, making adaptive backoff (inMinutes: healthy ? 240 : 5) trivial and letting an LLM check decide when to look again. Thetriggerin the definition is only the seed and the fallback.
The skill covers how to actually write all of this; the rest of this README is what's behind the curtain.
types.ts the Result/Input/Definition contract — read this first
config.ts resolves the per-project verification workspace
inputs.ts resolves a check's declared inputs; check-side readInputs()
loader.ts reads checks/*.def.json, validates the input graph (no cycles, all ids exist)
runner.ts resolves inputs, spawns one check, enforces timeout, manufactures `error`
store.ts directory-as-index JSON storage + run state
router.ts pass=ignore fail=alert uncertain=queue error=queue→alert-if-stale
scheduler.ts the only long-running process: due? → run → store → route
run.ts one-shot CLI: `verifier-run --workspace <dir> <checkId>`
heartbeat-check.sh dead-man's-switch — runs from REAL OS cron, outside all of this
The harness is generic; each project that uses it has a verification workspace — the directory where that project's checks, history, and mutable state live. It is not this repo, and not necessarily the project root.
checks/ YOUR checks (grows forever): *.mjs logic + *.def.json definitions
supervisor.mjs one reusable generic supervisor (folds inputs by a rule)
prune.mjs retention enforcement — itself a check
meta/liveness.mjs the silent/overdue watchdog — itself a check
results/ results/<checkId>/<runId>.json (rolling, pruned)
artifacts/ artifacts/<checkId>/<runId>/... (bulky per-run evidence)
state/ state/<checkId>.json + heartbeat (mutable)
Checks are independent programs that import nothing from the harness — they read env vars and print one Result. So a check can be written in any language; the .mjs examples just run with plain node (no build step). See the skill for the authoring details.
From this repo during development:
npm run build
node dist/scheduler.js --workspace /path/to/workspace
node dist/run.js --workspace /path/to/workspace root # runs the root supervisor; this IS your dashboard
Install the harness on your PATH:
npm run build
npm run install:global
Then:
verifier-scheduler --workspace /path/to/workspace
verifier-run --workspace /path/to/workspace <checkId>
verifier-summarize --workspace /path/to/workspace # markdown summary of the check definitions
verifier-heartbeat /path/to/workspace # put this in real OS cron
The workspace can also come from VERIFIER_WORKSPACE; individual dirs override with VERIFIER_CHECKS, VERIFIER_RESULTS, VERIFIER_ARTIFACTS, VERIFIER_STATE, VERIFIER_HEARTBEAT.
- No database. Readable JSON on disk; recent history doesn't need queryability.
- No web dashboard.
run.ts rootIS the dashboard — a one-shot rollup report. - No plugin/agent framework. The subprocess-emits-JSON contract is the whole API.
If a fresh reader can't understand the harness top-to-bottom in an afternoon, it's drifting toward a project — stop and cut.