COMPLIANCE-AS-CODE FOR AI SYSTEMS

SHIP AI WITH YOUR PAPERS IN ORDER.

An open-source CLI that derives AI governance documents from the code itself, then fails the build when the two stop agreeing. The terminal below is not a video. It replays a committed run, and it takes your input.

ballast — interactive · cassettes: classify.jsonl · generate.jsonl
visitor@web $  try: scan · classify · check · drift · why · help
STABILITY GAUGE
LOAD
LINE
★ —
Every star is ballast: weight that keeps an open-source hull upright.
LIVE FROM THE GITHUB API · NO TRACKING, ONE FETCH
01 · THE RUN — RECORDED, COMMITTED, REPLAYABLE WITHOUT A KEY

19 model calls. $1.03. Nothing edited out.

Four agents classified a real hiring system against the EU AI Act on 2026-07-28. Both transcripts are committed with request hashes and token counts, so this table is generated from those files rather than typed out, and every row replays offline.

SEQAGENTREQ HASHTOK IN → OUTWHAT IT DID
classify 00surveyora8f59fb833bb2,125 → 215list_files(.) · read extraction.ts, ranking.ts, screening.ts
classify 01surveyor8db33131f3e26,909 → 308list_files(src) · read extraction.prompt.md, screening.prompt.md, README.md, ballast.config.yaml
classify 02surveyor396f321232fe8,573 → 139read server.ts, store.ts
classify 03surveyorb251a3c0740f10,561 → 107grep(rankCandidatesForJob|ranking)
classify 04surveyora5665cbc0e3010,698 → 94grep(console\.|logger|log\()
classify 05surveyor0ebd184f0e3c10,841 → 3,151thinking
classify 06surveyorf6766de8e5d311,388 → 3,152observed the repository
classify 07pilotf79d87205b6f24,887 → 3,888tier: high-risk · actor role: provider · assumption recorded
generate 00drafter5ae5bf2ad2446,198 → 5,484risk assessment · Resume Screener
generate 01examineraea098250e2910,149 → 601approve
generate 02drafter1304bbe5e8a06,123 → 2,920model card · claude-sonnet-4-6
generate 03drafter28ed97d01daf9,188 → 3,570model card · claude-sonnet-4-6
generate 04examineredb33a2edaa98,051 → 674approve · advisory notes: 2
generate 05drafter8bf4b457cd256,119 → 1,935model card · gpt-4o (via OpenAI API, src/extraction.ts:7)
generate 06drafter69531e1ae0888,156 → 2,764model card · gpt-4o (via OpenAI API, src/extraction.ts:7)
generate 07examiner8829574791377,128 → 1,007approve
generate 08drafterbfcfe56a654d6,122 → 1,882model card · text-embedding-3-small
generate 09drafter1acbdc68db168,150 → 2,381model card · text-embedding-3-small
generate 10examiner40a0d4367ac16,809 → 509approve
19 CALLS · 168,175 → 34,781 TOKENS · ~$1.03 · 4 EXAMINATIONS · 3 SCHEMA RETRIES (IN THE AUDIT LOG, NOT ABOVE)
MOMENTS — EACH ONE IS A DEEP LINK

THE CLASSIFIER SHOWED ITS WORKING.

"…the precise commercial/organisational relationship between the Talent Platform team and any end-using employer was not specified."

pilot · assumptions[] · classify 07

THREE MALFORMED DRAFTS. ZERO REACHED A DOCUMENT.

The schema bounced three model cards, re-sent each with the validation errors attached, and only the corrected replies reached the documents.

schema layer · audit-log.jsonl

THE BUILD IS HELD.

One undeclared model appended to a source file. The manifest no longer describes the ship. Exit code 1. This is the product.

ballast check · exit 1
02 · THE AGENTS

Four narrow jobs. They disagree on purpose.

01

SURVEYOR

Reads the code. Sandboxed read, list and grep, nothing else. Reports what it could not determine.

02

PILOT

Classifies against the AI Act and NIST AI RMF. Citations are a closed enum, so invented law fails validation instead of reaching a document.

03

DRAFTER

Writes the documents. Every substantive claim carries a reference to a finding, an answer, or a provision.

04

EXAMINER

Attacks the draft. Opens the references rather than trusting them. Unresolved objections are printed, not buried.

And one gate no agent can pass: a named person accepts the classification before anything is generated. Machines may propose a legal classification; people accept one.

03 · IN CI

One job in your pipeline. Exit codes that mean something.

# .github/workflows/governance.yml
name: AI governance
on: pull_request

jobs:
  ballast:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: theogandolphe/ballast@main
0clean, rendered quiet, never green
1material drift. the build is held
2no committed baseline to check against

No API key, no network, no per-run cost. A check that bills you per pull request gets budgeted away, and one that needs a secret cannot run on forks.

04 · INSTALL

Two commands, no account.

npx ballast-cli demo

npm install -g ballast-cli
ballast scan

The demo runs against a bundled example and needs nothing else. Requires Node 22 or later.

Published as ballast-cli. MIT, Node 22 or later, no account and no telemetry. The source is on GitHub, and the run replayed above is committed to it.

scan, check and demo never call a model. classify and generate use your own Anthropic key and print what the run cost when they finish, typically a few cents.

05 · LIMITS, STATED PLAINLY

What it is not.

Not legal advice. Ballast never says you are compliant. It reports what it found and which provisions appear to apply, so the conversation with someone who does give legal advice starts from facts about your code.
Not all-seeing. It reads source and a questionnaire. Production behaviour, training data, evaluation results and operational process are outside its reach, and it says so in the documents it writes rather than writing around the gap.
Not first. At least five open-source tools already scan code against the AI Act, and one detects frameworks with a real AST where Ballast uses line matching. What differs is what happens after the scan, and the repository's own competitive analysis argues this against itself.
Pre-1.0. One maintainer, no users, no revenue. Nothing on this page implies otherwise.