Documentation pipeline¶
This site is built, validated and published on its own, without compiling the firmware or installing the training toolkit. Editing a page, checking it and shipping it takes seconds and needs nothing but Python.
Commands¶
All five live in plxy.sh, the script that already runs everything else in this
project — there is no separate docs tool to learn or to keep in step.
| Command | Does |
|---|---|
./plxy.sh docs-preview [port] |
serve the site locally with hot reload |
./plxy.sh docs-check |
validate without publishing — what CI runs on a PR |
./plxy.sh docs-build |
validate, then generate the static site into site/ |
./plxy.sh docs-deploy |
validate, then trigger the GitHub Actions deployment |
./plxy.sh docs-clean |
remove site/ |
docs-build is a superset of docs-check: the build validates first and refuses
to emit a site that did not pass, so there is no way to publish an unvalidated
build by picking the wrong command.
Local preview¶
Then open http://127.0.0.1:8001/.
Port 8001, not 8000 — 8000 is the live dashboard, and having both open at once is normal. Override with an argument or the environment:
The preview gives you:
- hot reload — save any file under
docs/and the open page refreshes - local search, the same index the published site uses
- the real navigation, so tab and section structure can be tested
- light, dark and system themes via the toggle in the header
- responsive layout — narrow the window, or use the browser's device mode
- broken links visible as you click, and images that resolve or do not
The preview is deliberately not strict: it must not die because a link you
are halfway through typing does not resolve yet. docs-check is the gate.
First run¶
The docs commands build their own environment on first use:
.venv-docs is created from requirements-docs.txt, which contains exactly one
requirement — mkdocs-material. It is separate from the project .venv on
purpose: the docs build must never be able to pull in torch, opencv or
onnxruntime.
| Variable | Default | Effect |
|---|---|---|
PLXY_DOCS_PYTHON |
discovered | interpreter to use |
PLXY_DOCS_VENV |
.venv-docs |
where the toolchain is installed |
PLXY_DOCS_PORT |
8001 |
preview port |
PLXY_DOCS_NO_VENV |
unset | 1 uses the ambient interpreter and never creates a venv — what CI sets |
PLXY_DOCS_SITE_URL |
the published Pages URL | base URL to build for — docs-preview sets it to the local address, and a fork can point it at its own Pages URL without editing mkdocs.yml |
Validation¶
docs-check runs a strict MkDocs build, in which every warning is an error,
followed by a credential scan. It fails on:
| Checked | Caught as |
|---|---|
| Broken internal links | contains a link, but the target is not found |
Broken #anchors |
does not contain an anchor |
| Nav entries pointing at nothing | included in the nav configuration, which is not found |
| Pages missing from the nav | omitted from the nav configuration |
| Missing images and assets | reported as an unresolved link |
| Duplicate routes | two files claiming one URL |
| Invalid Markdown that breaks the build | build error |
| Absolute links that should be relative | the absolute_links validation |
| Credential leakage | the secret scan below |
| Any other build warning | Aborted with N warnings in strict mode |
Links that leave docs/ — to source files, or to PROJECT_STATE.md — must be
absolute GitHub URLs, because those files do not exist in the published
site. Strict validation is what enforces that.
The credential scan¶
The scan runs over docs/, mkdocs.yml and the generated site, because a
secret can also arrive through a theme setting or an included snippet and never
appear in docs/ at all. It matches unambiguous credential shapes only — PEM
private keys, AWS access key ids, GitHub tokens, Slack tokens, Google API keys
and JWTs.
It deliberately does not use a broad password-assignment pattern. This project documents a compiled-in Wi-Fi AP password on purpose (and says so), and a scan that fires on every page mentioning it is a scan somebody switches off.
GitHub Actions¶
Two workflows, and only one of them can publish.
docs-deploy.yml — publish¶
on:
push:
branches: [main]
paths:
- "docs/**"
- "mkdocs.yml"
- "requirements-docs.txt"
- "plxy.sh"
- ".github/workflows/docs-deploy.yml"
workflow_dispatch:
Checkout -> Setup Python 3.12 (pip cache) -> Install requirements-docs.txt
-> Configure Pages -> ./plxy.sh docs-build (validate + links + secret scan)
-> Upload Pages artifact -> Deploy -> Report URL, commit and timestamp
It requests the minimum permissions Pages needs, and notably not
contents: write — the workflow never pushes to the repository:
permissions:
contents: read
pages: write
id-token: write
concurrency:
group: pages
cancel-in-progress: false
cancel-in-progress: false because cancelling a Pages deployment half way is
how a site ends up in a partial state.
docs-check.yml — pull requests¶
Runs on documentation pull requests with permissions: contents: read only, so
it cannot deploy even in principle:
Reviewers download the documentation-site artifact and open it locally before
approving. Nothing is published until the pull request is merged to main.
Running the same thing everywhere¶
Both workflows call ./plxy.sh docs-check and ./plxy.sh docs-build rather than
inlining mkdocs commands. A green CI run and a green local run therefore mean
the same thing, and there is no second copy of the build to drift.
Deployment safety¶
The pipeline is constrained so a documentation change cannot affect anything else:
- Never builds or deploys the application. No firmware compilation, no container image, no registry push, no database, no integration environment, no release.
- Never modifies production infrastructure. The only artifact it produces is a static site, and the only thing it writes to is GitHub Pages.
- Never writes to the repository.
contents: read. - Never publishes an invalid build.
deployis a separate job gated onneeds: build; if validation fails the deployment never starts, and the previously published site stays exactly as it was. - Never publishes from a laptop.
docs-deployvalidates locally and then dispatches the workflow, so every published build went through CI. - Never exposes secrets. No workflow secret is read, and the credential scan runs over the generated output as well as the sources.
Deployment result¶
Each run writes a summary to the GitHub Actions job page:
| Reported | From |
|---|---|
| Build status | the build job |
| Page count | the generated site |
| Commit SHA | GITHUB_SHA |
| Build timestamp | UTC, at build time |
| Deployment status | the deploy job |
| Documentation URL | the deploy-pages output |
| Deployment timestamp | UTC, at deploy time |
The live site is https://sengphirum.github.io/PLXY_DrowsyGuard/, linked from the repository README.
Enabling Pages on a fork¶
Once, in Settings → Pages, set Source to GitHub Actions. No
gh-pages branch is used and none is created — the site is served from the
uploaded artifact, which is why the workflow needs no write access to the
repository.
Adding a page¶
- Create the Markdown file under
docs/. - Add it to
nav:inmkdocs.yml. A page that is not in the nav fails strict validation, which is deliberate — an unreachable page is a bug, not a draft. ./plxy.sh docs-previewand read it../plxy.sh docs-checkbefore pushing.
Open a pull request and the same checks run again in CI; merge to main and it
publishes itself.