A documentation pipeline that fails closed.
One template repo. Documents carry their own state, five gates are computed live and never stored, a named human signs the exact bytes, and publishing is a validated git commit. No database. No SaaS. Zero LLM calls in the pipeline.
Invite-only alpha. This page is the tour. There's nothing public to install yet.
- Distribution
- one template repo
- State
- frontmatter, not folders
- Quality bar
- 5 gates, computed live
- Sign-off
- hash-bound attestation
- Publish
- a validated git commit
- Go live
- git push → CDN
The core model
Status lives in the document, not in a folder or a database.
Every document carries eight core fields in YAML frontmatter. status
is a closed set: draft → in-review → promote-ready → published,
with two terminal states for the archive. The pipeline reads that field, checks the rules, and is the
only writer allowed to change it.
There are no status folders to shuffle files between. Lanes exist only as filtered views in the app. A document physically moves at most twice in its life: once when it publishes, once if it's archived. Everything else is a field change, so everything else is a clean, reviewable git diff.
The app writes all frontmatter through forms. Your editor (VS Code, Obsidian, Notepad, whatever the OS hands the file to) only ever touches prose. Structured data stays structured because no human hand-edits YAML.
---
title: Vendor Access Review
status: draft
owner: Sam Okafor # a person, never a role
audience: internal # fail-safe default
version: "0.1"
created: "2026-07-05"
updated: "2026-07-05"
review_cycle: quarterly
sop_number: 2 # Library-declared extra
---
The quality bar
Five gates. Computed live. One red gate stops everything.
There is no force-publish, no admin override, no exception path. The interesting part is where the gates
live: one Python module is the single authority. The UI consumes a
generated gates.json, and a pytest drift guard fails the build if
the two ever disagree. A gate is defined exactly once, or the test suite says no.
01
Owner
A named person is accountable. No owner, no promotion.
02
Metadata
All eight core fields present and valid, plus every extra this Library declares.
03
Structure
The document's headings match its Library template, in order.
04
Reviewed
A fresh attestation whose hash still matches the current body.
05
Audience
Only public documents reach the published site. Internal stops at in-review.
✗ 2 gates failing. The pipeline fails closed.
✓ 1. Owner Sam Okafor
✓ 2. Metadata 8 core fields + 1 Library extra, valid
✓ 3. Structure headings match the sops template
✗ 4. Reviewed not reviewed yet: 'reviewed_by', 'reviewed', 'reviewed_hash'
missing. The review form writes the Attestation.
✗ 5. Audience audience is 'internal'; internal documents stop at in-review.
Human accountability
The signature is bound to the bytes.
Review isn't a checkbox. It's an attestation. A named person signs, and the app writes three fields: who, when, and a SHA-256 of the document body at that exact moment (first 12 hex chars).
Edit one character of the content afterward and gate 4 breaks by itself, because the stored hash no longer matches the recomputed one. Nobody has to notice. The signature notices.
We're precise about the claim: it's a tripwire, not a security boundary. It won't stop a malicious insider with git access. It will catch the thing that actually happens: a well-meaning edit after sign-off that silently invalidates the review.
reviewed_by: Stuart Dorfman
reviewed: "2026-07-07"
reviewed_hash: 625a3d00ec2d # sha256(body)[:12]
# edit the body afterward →
✗ 4. Reviewed: attestation hash no longer matches the current body
Publishing
The UI's enforcement is UX. The pipeline's is law.
The app refuses to set promote-ready unless every gate is green, and
then promote re-validates all of it anyway, from the file on disk.
Hand-edited YAML can't sneak past, because the pipeline never trusts that the UI did its job.
def plan(draft) -> PromotePlan:
# pure function: re-check status + all five gates,
# resolve doc + asset targets. No side effects -
# purity is enforced by its own tests.
def execute(plan, publisher) -> PromoteResult:
# publisher is an adapter (Astro today).
# strict build validates BEFORE anything ships;
# any failure restores the previous state. > re-validating status + 5 gates ......... all green
> astro build (strict) ................... ok
> copy doc + assets → web/ .............. ok
[master 5bc0084] docs: promote vendor-support-contacts.md
[master 59a586c] audit: record promote vendor-support-contacts.md
status: published; go-live is git push, and stays human.
The receipt
Every promote and rollback leaves an append-only trail.
One audit module owns the line format, the timestamp, and the append-only write. The writer and the reader
are the same code, so they can't drift. Each transaction lands as two commits: the change itself, then the
audit record. Your compliance story is git log.
[2026-07-05T21:10:31Z] [PROMOTE_SUCCESS] [drafts/kb/sample-kb-article.md] [web/src/content/docs/kb/sample-kb-article.md] [e93372e]
[2026-07-05T21:10:51Z] [ROLLBACK_SUCCESS] [drafts/kb/sample-kb-article.md] [web/src/content/docs/kb/sample-kb-article.md] [c35c010]
[2026-07-06T21:31:39Z] [PROMOTE_SUCCESS] [drafts/procedures/ssl-certificate-renewal.md] [web/src/content/docs/procedures/ssl-certificate-renewal.md] [3a7863b]
[2026-07-07T05:08:10Z] [PROMOTE_SUCCESS] [drafts/kb/vendor-support-contacts.md] [web/src/content/docs/kb/vendor-support-contacts.md] [5bc0084]
The parts that surprise people
Decisions that look boring until you sit with them.
Your docs ship agent-readable
The published site emits /llms.txt, generated from the
same content collection as the human pages, so the agent feed and the site can't drift.
A document is in the feed exactly when it has a published page.
# FIT Docs
> Published documents from the pipeline.
> Every entry is gate-checked and promoted.
## Documents
- [SSL Certificate Renewal](/procedures/...)
- [Vendor Support Contacts](/kb/...) Deterministic to the bone
Zero LLM calls, zero API keys, zero network dependencies in the pipeline. Every gate check, every promote, every hash is reproducible: the same input produces the same answer on any machine, including an air-gapped one. In 2026, that's the contrarian feature.
Delete us, keep everything
There is no database. State is frontmatter; history is git; the site is static files. Every document is plain Markdown you can grep, diff, and blame. If you abandon the product tomorrow, you keep a complete, readable, versioned archive, because that's all it ever was.
Windows is first-class
Not "should work on Windows." First-tested on Windows, with PowerShell-safe setup scripts and the
execution-policy wall designed out. setup checks prerequisites
and tells you exactly what's missing; it never installs anything outside its own folder. "I couldn't
install it" is treated as a sev-1 product bug.
The product is a template repo
Click "Use this template," run one command, and you own a complete instance: drafts, pipeline, app,
and published site in one private repo. Going live is git push
to Cloudflare Pages. The pipeline never holds deploy credentials; the last mile stays human.
Assets travel with the doc
Images live per-document with relative links. Promote, rollback, and archive move the document and its assets as one unit and verify every link still resolves, so screenshots don't orphan when a doc changes state.
- Python pipeline · ~180 pytest green
- Node + Astro app · Starlight site
- three CI gates: ruff+pytest / lint+build / astro build
- no Docker
- one setup command
- works offline
The alpha is small on purpose.
A handful of invited operators, four weeks, GitHub-native feedback, and a named go/no-go at the end. If you want a seat when one opens, or you just want to argue about the architecture, we'd genuinely like to hear it.
Private alpha · evaluation use only · the product name is a working name while the real one clears the paperwork.