How This Site Is Published
Overview
This site is built with Hugo from the smit-io/docs repo. The rendered HTML is not committed there — a CI workflow builds it and force-pushes the output as a single fresh commit to smit-io/smit-io.github.io, which GitHub Pages serves at smitchoksi.com. No build-artifact history ever accumulates: the Pages repo always holds exactly one commit.
docs repo (source) ──hugo build──▶ public/ ──force-push──▶ smit-io.github.io ──▶ GitHub PagesThe same workflow (.github/workflows/publish.yml) runs two ways:
| Mode | Trigger | Cost |
|---|---|---|
| Local CI | make local-ci-run (via act, Docker) | Free, uses your gh CLI token |
| GitHub CI | Push to main, or make gh-ci-run | Free on public repos |
Both are always available — enabling hosted CI does not disable the local path.
Hosted CI setup
Hosted runs push to a different repo than the one the workflow lives in, so the
default GITHUB_TOKEN is not enough — a personal access token is required.
Create a fine-grained PAT
Go to github.com → Settings → Developer settings → Fine-grained tokens:
- Repository access → Only select repositories:
smit-io/docs,smit-io/hextra,smit-io/smit-io.github.io - Repository permissions → Contents: Read and write
Least privilege: the token can touch these three repos and nothing else.
Add it as a repo secret
gh secret set PUBLISH_TOKEN --repo smit-io/docsPaste the token at the prompt — it never lands in shell history or the chat.
Enable the workflow
make gh-ci-enable # pushes to main now trigger hosted publishes
make gh-ci-status # check state + recent runs
make gh-ci-disable # back to local-only, secret staysHow the workflow authenticates
.gitmodules references the theme submodule over SSH. The workflow’s first step
rewrites SSH URLs to HTTPS with the token:
git config --global url."https://x-access-token:${PUBLISH_TOKEN}@github.com/".insteadOf "[email protected]:"One token then covers the submodule clone and the publish push — on both GitHub
runners and local act runs (where make local-ci-run injects your gh CLI token
instead of the secret).
Notes
- Actions minutes are free and unlimited on public repos (standard runners). If the source repo ever goes private: free plan includes 2,000 min/month and a publish run takes ~2 minutes.
- The force-push means the Pages repo history is disposable by design — never commit anything there by hand.
CNAMElives in the source repo (static/CNAME), so Hugo re-emits it on every build and the custom domain survives the force-push.