Nuthatch
A governance harness for AI coding agents working on healthcare software. Every write an agent attempts through its tool channel is evaluated before the bytes exist on disk, and receipted to a hash-chained ledger. It witnesses in every mode. Two modes are built to gate, and both stay observe-only until a host attests the hook graph.
Nobody ships bad code on purpose.
The record just stops at the commit.
Your team reviews. Your CI is good. Your detection is genuinely excellent — scanners, linters, ratchets, a test suite that catches what it was taught to catch. All of it runs after the bytes are already on disk.
Increasingly the code that produces a hospital’s evidence is not typed by a person at all. It is written by an AI coding agent, at machine speed, across files nobody opened. The moment between the agent deciding and the write landing is the moment your record does not cover — and it is the only moment in which a bad write is still cheap to stop.
We audited our own AI governance
and didn’t like the answer.
Nuthatch exists because we audited our own AI governance and found the prevent rung nearly empty. Detection was excellent. Prevention was one deny rule. We built the missing layer, on ourselves, first.
Nuthatch does not make bad code impossible. Nuthatch makes non-compliance immediate, attributed, and provable, and it makes bypass impossible to do silently.
Built and gated — not yet published. The engine, ledger, verifier and starter pack are slated for Apache-2.0 release — roadmap, not shipped.
It hangs off the agent’s own tool call.
Every governed attempt gets a receipt.
Nuthatch evaluates each attempted write with deterministic rules, before the bytes exist on disk — then writes down what happened, in a form somebody else can check.
At the tool-call boundary
Not a scanner reading the repository afterwards. Nuthatch sits on the coding agent’s own tool channel and sees the write as an intention, while refusing it is still free.
Deterministic verdicts
A model never decides a verdict; it only drafts the human-readable explanation. The rules are code, and the same code runs in every mode.
One receipt per governed call
What was attempted, which control matched, who the actor was, what the verdict was — each landing as one entry in a hash-chained ledger.
It asks for very little to do that: a hook in the repository it watches, and — in the engine, asserted by a source scan — no network access of any kind.
Three modes, one readable file —
and the same controls evaluate in all three.
The operating mode is a single word in a single file. Nothing is hidden in a console, and nothing about the measurement changes when the mode does.
The three modes
- shadow — the default. Measures everything, emits nothing, touches no one’s workflow.
- teach — built to turn every finding into an approvable prompt carrying the lesson.
- enforce — built to act, with a citable reason.
Teach and enforce both observe until a host attests the hook graph, and no runtime attests one today — so neither emits a verdict. The default is shadow, and an absent, unreadable, or garbage mode file resolves to shadow.
Twenty-six controls, all of them asking
The starter pack carries 26 controls — identifiers in a logger, a credential written to a file, a store read that swallows its failure into an empty list, a permission check that fails open, a raw outbound call off the reviewed transport, an unwitnessed bypass.
Every one of them starts at “ask.” Not one of them can deny today. A control earns “deny” by demonstrating a low false-positive rate against accumulated evidence — and the tool that reports which controls have earned it refuses to edit the pack, because flipping a control from asking a human to blocking one has to have a human’s name on it.
The pack manifest digests every control module and refuses the whole pack rather than load a tampered one. It supports one coding agent — Claude Code — today; other agent transports are roadmap.
The developer tool is the witness.
The packet is the receipt.
The thing a non-developer holds is not a dashboard. It is an artifact, and it states its own limits on the page.
What the packet contains
The controls that were in force and the signature state of the pack they came from; the receipt totals; whether the chain and its signed tree heads verify; and every break-glass event rendered individually with its named actor and its stated reason.
It closes with a methodology section stating its own limits — including that observations are not blocks, and that this is evidence for conformance, never a compliance certification.
Who can check it
A separate verifier, with no dependencies and no network access, re-checks a packet offline from nothing but a public key and one receipt’s inclusion proof — revealing nothing about any other receipt in the log.
The signed tree head is the half a stranger can verify: it is Ed25519, and the public key verifies without being able to forge. The receipt chain itself is keyed, so it is the operator’s own check and the verifier says so rather than implying otherwise.
The ledger is hash-chained and tamper-evident: a break in the chain is detectable and surfaced. It is designed to be third-party-verifiable, which is a property someone else checks rather than a promise you accept. Both the packet and the verifier are built; publication is roadmap, not shipped.
Some questions are decidable at the tool call.
Nuthatch says out loud which ones are not.
T0 — decidable now
Decidable from the tool call alone: a secret being written, an identifier key in a logger, a bypass flag. A refusal is legitimate here.
T1 — decidable on a budget
Needs cached repository context on a strict time budget — does that data-model delegate exist, did this change raise a baseline, is the cited commit really an ancestor. On timeout it degrades to asking, never to passing.
T2 — not decidable in real time by anything
Nuthatch does not judge the content. It forces provenance, and it starts an obligation clock routed to a named human. The honest version of a hard question is a named owner and a deadline, not a green check.
dose-gate’s epistemic claim is “this constant came from the registry,” not “this constant is correct.”
The boundary between what you believe
you installed and what you installed.
A governance tool that overstates its own guarantees is the precise failure it sells protection against. So this is the whole table, including the rows that are empty.
| Property | On a fresh install |
|---|---|
| mode (default) | shadow — measures, emits nothing |
| modes available | shadow, teach, enforce |
| modes that emit a verdict | none today — teach and enforce are observe-only until a host attests the hook graph; the built ceilings are teach: ask, enforce: deny |
| controls in core-safety | 26 — every one at ask; none denies today |
| pack signature | none yet — the pack is unsigned |
| trust root | unpinned — and every verifier says so instead of implying otherwise |
| verdicts it can emit | ask, deny — a frozen list |
| hard deadline | 1500 ms, on an unref’d timer — a stalled check cannot hold a tool call open |
| break-glass | reason of 40+ characters required · 15 min default, 240 max · 1 use default, 5 max |
| file contents stored | none — writes reduce to a sha256 digest and a byte length |
| third-party packages | zero |
| network access | none in the engine, asserted by a source scan |
Zero, or eight hundred and ninety-six.
Same repository, same authors, same discipline — and the only variable is whether the rule existed before the code did.
Every baselined number is a measurement of what it costs to catch something after it lands. A prevent-rung control has a baseline of zero by construction — which is the entire argument for building the rung.
What Nuthatch does not do.
The list a tool that overstated itself would leave out.
- It does not make errors impossible, and it does not stop a model from being wrong. It governs the output boundary, not the model’s reasoning.
- It does not judge whether a dose, a threshold, or a citation is right. It can refuse a magic constant that came from nowhere; it cannot tell you the number is correct.
- It does not catch what never reaches a tool call. A file pulled in by reference produces no event, and a write that arrives as a shell command rather than an edit is measured, not caught.
- It does not block bypass. It witnesses bypass, and it enumerates every break in the chain.
- It does not deny anything by default. All 26 starter controls ask.
- It supports one coding agent — Claude Code — today. Other agent transports are roadmap.
- It is not a compliance certification and it does not make anyone compliant. It produces evidence a third party can check — and a human being still has to read it.
- Its published evidence run is a 25.5-hour window on our own repository — not fourteen days. The fourteen-day corpus is owed, and no fourteen-day figure gets quoted until a fourteen-day ledger produces one.
The review is short,
because the answers are architectural.
Nothing to audit downstream
Zero third-party packages. No network access in the engine, asserted by a source scan. There is no vendor cloud in the path because there is no path to a vendor cloud.
No file contents leave the machine
Nothing leaves it at all, and nothing is stored either: a write reduces to a sha256 digest and a byte length. The ledger records that a thing happened, not what the thing said.
It cannot hang your agent
A 1500 ms hard deadline on an unref’d timer. A stalled check cannot hold a tool call open, and a timeout degrades to asking — never to passing.
Break-glass demands a written reason of at least forty characters, refuses to arm without a chained receipt of its own, and burns the grant before the bypass applies — one grant at a time, under hard caps on how long it lives and how many times it is used. Bypass is possible and we say so. Every bypass emits a coded event, and every break in the chain is enumerated.
Named. Not dated.
Not promised.
A roadmap read as a product is how software companies lose clinicians. These are the five things that are not here yet.
- Public release of the engine, ledger, verifier and starter pack under Apache-2.0.
- Controls promoted from “ask” to “deny” once each earns it on adjudicated evidence.
- Reconciliation as a coverage claim — every committed change showing its witnesses, and anything unwitnessed flagged on the packet.
- Signing for the starter pack, and a pinned trust root.
- Receipts registering as a Charlie Owl evidence source, so one governance file covers both the algorithms that touch patients and the agents that touch the code.
Owl proves what happened.
Nuthatch is there while it happens.
Charlie Owl keeps a hospital’s designations continuously provable — including the receipts for every algorithm that touches a patient. Nuthatch holds the same shape one floor down, on the development floor, with a hash-chained ledger and refusal codes of its own.
Nuthatch receipts are designed to register as an Owl evidence source. Wiring that into the Owl board is gated on a design partner, and until one exists it stays on the roadmap above rather than in this paragraph.
A nurse wrote the rules
the agents build under.
Nightingale OS was founded by a 20-year ER, Flight, and Trauma Nursing veteran who spent two decades running hospital trauma and accreditation programs. A former Stanford educator, she taught herself to build by directing AI coding agents inside a governance harness she authored — the same discipline the product sells, applied to our own codebase first.
That is why the self-audit in the second section is not a marketing story. The prevent rung was found nearly empty on this repository, by the person accountable for it, and the missing layer was built here before it was offered to anyone else. The full record is on the company page.
Nuthatch is pre-release.
We are looking for repositories to be wrong in.
The ask is small on purpose: run shadow mode on one repository. Shadow measures everything and emits nothing, the engine has no network access, and no file contents are stored — so nothing leaves your building and nobody’s workflow changes. What we want back is the thing we cannot generate ourselves: a corpus that is not ours.
Or email directly: kristen@nightingaleos.com · info@nightingaleos.com