Skip to content
LIVEOPEN SOURCEstealth design system

hullcheck

Check the hull before you trust the air.

Test coverage told a generation of engineers whether their code runs. Nothing told them whether their policy runs. hullcheck reads the rules a repository states, finds the gates that actually execute in CI, hooks, Makefiles and checker scripts, and reports every rule with nothing behind it. Declare the links and it proves them: a gate that passes while its rule is broken is FAKE. Built for Spaceship Alpha 9's own monorepo, where on day one it read 47% coverage and a Time-to-Truth of never. Apache-2.0, written in Go.

Runs onCLI
github.com/space-pirate-zero/hullcheck● LOCKED
Open source β€” Apache-2.0, written in Go

Open source β€” Apache-2.0, written in Go

Five verdicts: HOLD, BREACH, UNLOGGED, FAKE, BROKEN

Time-to-Truth: how long before a breach actually surfaces

Dogfooded on a 7,000-file monorepo: 9 defects found and fixed in one night

WHY THIS EXISTS

Why hullcheck exists

// problem

The world before hullcheck

Manual processes and outdated utilities drain engineering time that should be spent on real problems.

// solution

Enter hullcheck

Test coverage told a generation of engineers whether their code runs. Nothing told them whether their policy runs. hullcheck reads the rules a repository states, finds the gates that actually execute in CI, hooks, Makefiles and checker scripts, and reports every rule with nothing behind it. Declare the links and it proves them: a gate that passes while its rule is broken is FAKE. Built for Spaceship Alpha 9's own monorepo, where on day one it read 47% coverage and a Time-to-Truth of never. Apache-2.0, written in Go.

CAPABILITIES

What hullcheck can do

Purpose-built capabilities engineered to deliver on every promise.

HOLD / BREACH / UNLOGGED

Every stated rule lands in a bucket: enforced by something that runs, stated with nothing behind it, or a gate running that no written rule covers.

Verified mode: FAKE and BROKEN

Declare which gate guards which rule, give it a fixture that breaks the rule, and hullcheck proves the gate fails. A gate that passes anyway is FAKE; one that fails either way is BROKEN.

Time-to-Truth

p50, p90 and worst case for how long a breach takes to surface. A gate that only runs nightly is not the same as one on the pull request, and a manual checker is never.

Ratchet, don't gate

hullcheck diff reports the rules left unenforced since a baseline, and go test assertions fail on new breaches only, so a repo can carry known gaps without letting new ones in.

A denominator you can check

Clauses are judged by their whole block, an explicit Gate: line counts on its own, and --clauses prints every numbered clause it saw and did not count.

Apache-2.0, in Go

One binary, no daemon, no account. Reads the repo it is pointed at and prints a reading.

FREE AS IN FREEDOM

hullcheck is open source

The full source lives on GitHub under the Apache-2.0 license. No license fees, no lock-in, no sales team. Read it, run it, fork it β€” and if it breaks, file an issue and watch it get fixed in the open.

terminal
$ git clone https://github.com/space-pirate-zero/hullcheck.git

Apache-2.0 licensed Β· star it, fork it, ship it

FIELD REPORT

We pointed our own tool at ourselves

hullcheck is open source. The first thing it found was us.

Greg Chambers Β·

A tiny astronaut presses a cyan scanner to the hull of the Spaceship Alpha 9 saucer; one hairline seam glows pink.

Every repo has a rules file

Ours is called RULES.md and it is long. It says the palette is exactly four hexes. It says there is one spaceship and you do not draw a second one. It says every piece of art records where it came from. It says nobody deploys without a go.

Nice rules. Firm tone. Here is the question nobody asks about a rules file: what actually runs when one of them gets broken? For most rules in most repos the honest answer is nothing. The rule sits there in bold, looking sealed, and the first hard signal that it failed is the one you can't act on anymore.

So we built a tool that asks the question for you, pointed it at our own studio, and open-sourced it. The tool's first real customer was us, and we did not pass.

A cathedral wall of stone tablets; half are wired to glowing machinery, half hang dark and unconnected.

Why the studio needed it

Spaceship Alpha 9 is a two-person studio that runs like a small fleet: books, audio dramas, a daily news show, an album, a merch shop and a dozen websites in one monorepo, with dozens of branches open at once and master moving several times a day. A lot of that work gets drafted at machine speed.

Machine speed removed the rate limiter on writing code. It did not remove the need to check it. A rule that only lives in prose is a rule that gets skipped the first busy Tuesday. Our own essay, The Living Codebase, put it in one line: a rule that cannot execute is a wish. hullcheck is that sentence, compiled.

A brass pressure gauge with a blank face; the needle is pinned against the stop and the warning lamp beside it has never been lit.

Reading one: 47%, and β€œnever” on every rule

The first reading, on 6 September, said 47% gate coverage. The real finding was the Time-to-Truth column: never, for every single rule. The repo had 201 checker scripts and every one was manual. There was no CI in the studio repo at all.

Even the 47% was generous. The matcher credited a gate to a rule on one shared word, including words in the gate's file path, and in a monorepo a path is a bag of topics. Our voice-ID rule scored HOLD against every brand checker in the tree on the word β€œbrand”. Nothing checked voice IDs.

A pristine starship hold; hundreds of identical cyan crates pour through a jammed airlock.

Five hundred files that never belonged in git

A merged pull request landed more than five hundred files of a Python virtual environment on master. .venv/ was in .gitignore the whole time; the rule said keep build junk out of git; nothing ran on it. It went from BREACH to HOLD the same day, and check_git_hygiene.py now blocks the whole class.

A gallery wall of glowing framed emblems; every frame has an empty hook for its provenance card except one.

94 artworks, one receipt

Our rules say every asset records its provenance: a small sidecar beside it saying what made it, from what prompt, under what licence. The provenance audit went looking. The merch folder held 94 master artworks and exactly one sidecar. The pipeline had been shipping art without receipts, and nobody knew, because nothing counted.

A launch gantry at night; the ignition lever is chained shut with one giant pink padlock and every indicator lamp is dark.

The CI we added never ran a single step

So we added the studio's first ever workflow. It died at zero seconds, every time, and each cause hid the next. The @v1 it pointed at had never been tagged. Fixed, the ratchet would still have failed every PR: it unpacks the base revision with git archive under a 60-second timeout, and our 3.47 GB tree took 169 seconds. A .gitattributes that skips media for git archive took it to 60 MB and 4 seconds. Under both sat an account billing lock, which on a private repo looks exactly like a broken workflow file.

A gate that has never run is a BREACH wearing a HOLD costume. The tool caught it in its own wiring.

A curved hull plate at night with nine freshly welded cyan seams; a lone welder finishes the ninth in a spray of pink sparks.

Nine defects, filed against ourselves, fixed in one night

A 7,000-file creative monorepo is a stress test no toy repo gives you. We filed every place hullcheck lied to us as an issue upstream: nine of them. Directories no longer count as evidence. A clause is judged by its whole block, so rules written as declarative headlines stop being invisible (it had seen 2 of the 12 rules in our operations section). Rules are addressed by document and ID, so one entry can't flip a second studio's rule. Verify mode's scratch copy is gitignore-aware and refuses when it's too big, instead of trying to copy 241 GB per rule.

All nine landed on 7 September, between half two and four in the morning.

A colossal cyan ratchet wheel with a pink pawl locked in its teeth, turning one way only.

Wishes became gates

Within eight days, rules that had been wishes got something that runs: build junk out of git, deploys only from origin/master, no giant media forced past .gitignore, the cast only on registered voices, every render updating its operator doc, and provenance as a ratchet so the backlog only shrinks. Git hooks put the gates before the commit, so Time-to-Truth went from never to seconds.

On 14 September the studio cut its first release, studio-v1.0.0. The first release check refused to tag: it had found a real canon defect in one of the books.

Today's reading finds 83 rules where the old build found 38, and coverage still went up, to 64%. The tool learned to read, the denominator more than doubled, and the studio holds more of it. The 30 breaches left are a list with names on it. You can't fix a wish you can't see.

hullcheck .
83 rules found in 4 policy documents
316 gates found in CI, hooks and checker scripts

HOLD        53   rule has a gate, and something runs
BREACH      30   stated, nothing runs on it
UNLOGGED   132   a gate runs, enforcing nothing anyone wrote down

Gate Coverage  64%
The studio repo, read by hullcheck on 2026-09-28.
OUR MISSION

A rule that cannot execute is a wish. hullcheck is the difference between a policy document and a policy.

β€” The hullcheck Team at Spaceship Alpha 9
BUILT WITH

Tech Stack

GoGitHub ActionsGit hooksgo test
AVAILABLE ON

Get hullcheck

CLI

Follow the Commits

hullcheck is open source β€” the code is already yours. Drop your email for release notes, roadmap drops, and breaking-change warnings.

hullcheck is one of 7 products in the SA9 fleet.