2026.08.27

building prodcheck because shipping needs evidence

a local production-readiness CLI that audits a repo before release and separates verified checks from assumptions.

TypeScriptNode.jsGitHub ActionsRepository

i have noticed that a lot of software feels done right before it becomes dangerous.

the code compiles. the feature works on the happy path. the pull request looks reasonable. everybody wants to ship. then somebody asks the annoying but necessary question:

what have we actually verified?

not what do we believe should work. not what the tests probably cover. not what the framework usually handles. what did we check, what changed, and what is still a guess?

that question is why i built prodcheck.

the product idea

prodcheck is a local CLI for pre-release checks.

the first command is intentionally simple:

sh
readiness audit

it runs inside the current git repository and writes a Markdown report. the report is not trying to be a security scanner, CI platform, or deployment dashboard. it is trying to be a clear pre-ship note:

  • what changed;
  • what kind of risk the change introduces;
  • what commands are available;
  • what was actually run;
  • what still needs a human to confirm.

the important part is the boundary between proof and assumption.

a report that says "tests available but not run" is more useful than a report that quietly implies everything is fine because a test script exists.

what the first version checks

the first release inspects the repo instead of reaching for external integrations.

it looks at git status, the current branch, changed files against a base branch, package manager files, language markers, scripts in package.json, Makefile targets, Python project files, CI workflows, deployment files, env surfaces, and migrations.

then it classifies risky changed paths into buckets like auth, billing, webhooks, migrations, deployment, secrets, routing, database, dependencies, CI, frontend, and backend.

that classification is intentionally boring. filenames are imperfect, but they are cheap evidence. if a diff touches auth, billing, webhook, .env, migrations, or deployment config, the report should make that visible immediately.

the CLI does not print secret values. env files are listed as surfaces, not read as data.

running commands should be explicit

i did not want the default command to run arbitrary project scripts.

that is one of those features that sounds helpful until a tool runs a slow integration suite, mutates a database, starts containers, or does something surprising on a machine that was not prepared for it.

so the default mode only inspects.

if i want it to run discovered checks, i have to say so:

sh
readiness audit --run

for the first release, it runs known local commands like tests, typechecks, builds, lint, and project check scripts. the report records each command and whether it passed, failed, or timed out.

that makes the output usable in a pull request because it has evidence attached to it. one section can say a local typecheck passed. another can say CI files were found, but remote CI status was not checked.

this is the tone i want from tooling. calm, specific, and allergic to pretending.

the first real run already found a problem

after the first release, i ran prodcheck against itself and against this website.

against prodcheck, it behaved the way i expected. it detected the TypeScript project, npm, GitHub Actions, available scripts, and with --run it recorded passing tests, typecheck, build, and the combined check command.

against this website, it also worked, but it exposed a heuristic that needed tightening.

the site has older content files with names like infrastructure-as-code.md. the first release classified those as deployment-related files because the deployment detector was too broad. that was not a catastrophic bug, but it was exactly the kind of small false positive that erodes trust if it appears often.

that became the first hardening pass: make the deployment detector path-aware, add explainable risk findings, add JSON output, and add optional GitHub Actions readback.

what changed after the mvp

the useful version needed more than a Markdown file.

so i added:

  • named risk rules with severity, reason, and matched files;
  • --json-output for automation;
  • --github for GitHub Actions readback through the gh CLI;
  • --run-kind so cheap checks can run without triggering everything;
  • --pr-comment-output for compact PR notes;
  • --smoke-url for basic HTTP checks against local or preview URLs;
  • project config through prodcheck.config.json;
  • check packs for migrations, auth, billing, and webhooks.

that moves the project closer to the real workflow: a developer can run it before opening a PR, before merging a risky branch, or before deploying a release candidate.

what i like about it

i like that it starts from local reality.

there is no dashboard to configure, no account to connect, no big promise. you run it in a repo and it tells you what it can see. that feels right for the kind of engineering judgement i want to practice: read the system first, separate evidence from guesses, then decide what remains.

i also like that the report format is plain Markdown. it can go into a PR comment, a release note, a deployment checklist, or a personal journal of what was checked before shipping.

the tool is small, but the habit behind it is not small.

what is still missing

the obvious missing pieces are deeper CI integration, deployment provider checks, browser-level smoke tests, dependency diffing, and more detailed migration safety checks.

but i do not want to jump into all of that too quickly.

the core of the tool has to stay honest. every future feature should preserve the same distinction:

  • verified means the tool actually checked it;
  • recommended means the tool found a sensible next step;
  • unknown means nobody should pretend.

that is the product.

not the CLI. not the Markdown file. not the risk labels.

the product is a small pause before shipping where the system asks: are we saying this is ready because we know, or because we are tired?

that pause is worth building.