Local CI
The engine’s CI runs locally. bin/ci is the gate, wired to a pre-push
hook, and the hosted GitHub Actions workflow is opt-in (workflow_dispatch).
Why local
Section titled “Why local”The hosted workflow was billing-gated and had been reporting nothing for days —
every job refused before it started, so main sat red and the signal was
worthless. Worse, its only real check was a single shell test, run redundantly
across nine billed jobs; the generate and verify steps were stubs that
echoed and exited.
Everything worth checking here is reproducible on a laptop in seconds, so that is where it lives.
bin/ci # fast stages — what the pre-push hook runsbin/ci --full # also builds the landing + docs sitesbin/ci --stage links # run one stagebin/ci --list # list stagesExit code is 0 if everything passed, 1 otherwise.
Stages
Section titled “Stages”| Stage | What it proves |
|---|---|
source-hash | The generate/ digest helper hasn’t drifted. This is the one real check the hosted workflow ran. |
shell | Every .sh parses (bash -n) and passes shellcheck -S error. |
python | Every .py compiles. |
paths | No foreign absolute home paths (/Users/<name>/…, /home/<name>/…). |
vault-refs | Every llm-wiki-* name the engine mentions is either a real vault or an allowlisted placeholder. |
links | Cross-vault links are well formed — the visible vault-short: matches the vault= param — and targets resolve. |
build | The Astro landing + docs sites build. Only in --full; auto-skips when Node or deps are missing. |
paths and vault-refs exist because the same two regressions kept coming
back: another machine’s absolute paths, and real private vault names leaking
into examples. They are regression guards, not style checks.
The pre-push hook
Section titled “The pre-push hook”bin/install-hooks # sets core.hooksPath=.githooks (idempotent)install.sh does this automatically. core.hooksPath is local git config, so
each clone runs the installer once.
Bypass when you need to:
git push --no-verify # skip onceLLM_WIKI_SKIP_CI=1 git push # skip via envWhat CI deliberately ignores
Section titled “What CI deliberately ignores”vaults/— each vault is its own git repo with its own history..private/— the operator overlay. Naming real vaults is its whole job, so linting it as engine content produces nothing but false positives.golden-corpus/— a frozen regression fixture. Its content is the fixture; “fixing” it would invalidate the baselines..ralph/prd-*.json— dated records of completed work.
Adding a placeholder vault name
Section titled “Adding a placeholder vault name”If a doc needs an example vault that doesn’t exist, add it to
.ci/vault-placeholders.txt. That file is the allowlist, which is what stops a
real private vault name from quietly becoming an example.
Hosted runs
Section titled “Hosted runs”The Golden Corpus workflow still exists and can be triggered by hand from the Actions tab, or:
gh workflow run "Golden Corpus"Pages deployment is a known exception
Section titled “Pages deployment is a known exception”GitHub Pages deployment (deploy.yml) is still an Actions workflow, because
publishing to Pages needs an OIDC token minted by the runner. While Actions is
billing-gated the docs site does not update — it has been frozen since
2026-08-10 — so the page you are reading may be behind main.
bin/ci --full builds both sites locally, which proves the build is not broken;
it simply cannot publish.
This is postponed rather than forgotten. The diagnosis, the two viable fixes (settle the billing, or switch Pages to deploy-from-branch) and the reason local CI cannot cover it are written up in issue #60.