This page is part of the site it describes. The docs deploy to Cloudflare Pages, and this page documents the pipeline that ships them: edit Knap and JSON, rebuild with the tool, prove the committed output is current, merge, and Pages takes it from there. The tool documents its own deployment.
The whole loop: edit docs/src/*.knap or docs/data/*.json, rebuild the site, prove the committed output is current, ship it through a PR. On merge, the deploy workflow pushes docs/site/ to Cloudflare Pages:
$ sh docs/build.sh
rendered: index shell templates contract dogfood deploy
$ git diff --exit-code docs/site/ && echo clean
clean
The gate is the docs-repro job in .github/workflows/ci.yml: it builds the dogbed binary, runs sh docs/build.sh, and fails with git diff --exit-code docs/site/ if anything differs. A red build means exactly one thing — you forgot to rebuild the site before committing. Watch it fail on a stale tree:
$ echo stale >> docs/site/index.html
$ git diff --exit-code docs/site/
diff --git a/docs/site/index.html b/docs/site/index.html
index 3de7d22..65b7de6 100644
--- a/docs/site/index.html
+++ b/docs/site/index.html
@@ -43,3 +43,4 @@
<p><a href="index.html">index</a> · <a href="shell.html">shell</a> · <a href="templates.html">templates</a> · <a href="contract.html">contract</a> · <a href="dogfood.html">dogfood</a> · <a href="deploy.html">deploy</a></p>
</body>
</html>
+stale
$ echo "exit: $?"
exit: 1
The Cloudflare setup, as inspected: the project is dogbed — live at dogbed.filed.fyi and on the default dogbed.pages.dev domain. The output directory is docs/site/, committed to the repo — the deploy ships the exact bytes in the tree, no build step on the Pages side. The deploy path is wrangler direct upload from GitHub Actions: the repo carries the two secrets below, and no Cloudflare GitHub App checks appear on commits, so the Pages integration path is not in play.
$ gh secret list --repo drawmeanelephant/dogbed
CLOUDFLARE_ACCOUNT_ID 2026-09-30T00:10:25Z
CLOUDFLARE_API_TOKEN 2026-09-30T00:10:33Z
The deploy workflow is checkout and deploy, nothing else:
$ cat .github/workflows/deploy.yml
name: deploy
on:
push:
branches: [main]
jobs:
pages-deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Deploy docs/site to Cloudflare Pages
uses: cloudflare/wrangler-action@v3
with:
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
command: pages deploy docs/site --project-name=dogbed
Cloudflare keeps every deployment. To roll back:
dogbedmain is listed with its commit$ npx wrangler pages deployment rollback <deployment-id> --project-name=dogbed
The deploy workflow first fired on the merge of the very PR that added it — push to main, 28 seconds, deployed. No build step, no ceremony: checkout and wrangler. The workflow log, trimmed to the wrangler action (timestamps are the runner’s):
2026-09-30T00:28:04.4001917Z command: pages deploy docs/site --project-name=dogbed
2026-09-30T00:28:04.4906387Z [command]/usr/local/bin/npx --no-install wrangler --version
2026-09-30T00:28:11.8067446Z [command]/usr/local/bin/npm i wrangler@3.90.0
2026-09-30T00:28:19.0876014Z ✅ Wrangler installed
2026-09-30T00:28:19.0896103Z [command]/usr/local/bin/npx --no-install wrangler --version
2026-09-30T00:28:19.8311712Z 3.90.0
2026-09-30T00:28:19.8842932Z [command]/usr/local/bin/npx wrangler pages deploy docs/site --project-name=dogbed
2026-09-30T00:28:22.2939592Z Uploading... (0/7)
2026-09-30T00:28:22.7886426Z Uploading... (2/7)
2026-09-30T00:28:22.8702344Z Uploading... (5/7)
2026-09-30T00:28:22.9625881Z Uploading... (7/7)
2026-09-30T00:28:22.9628024Z ✨ Success! Uploaded 7 files (1.71 sec)
2026-09-30T00:28:24.2006374Z 🌎 Deploying...
2026-09-30T00:28:25.4739626Z ✨ Deployment complete! Take a peek over at https://a505925f.dogbed.pages.dev
And both domains answered the moment it landed:
$ curl -s -o /dev/null -w "%{http_code}" https://dogbed.pages.dev/
200
$ curl -s -o /dev/null -w "%{http_code}" https://dogbed.filed.fyi/
200