Deploy on push
Connect a repository and Readsmith becomes a deployment pipeline: a push to the connected branch fetches that exact commit, compiles it into an immutable bundle, and atomically flips the site to it. Nothing is half-published, a stale build can never overwrite a newer one, and rolling back is repointing to a previous deployment, not rebuilding anything.
Git deploys need the database (deployments live there), so this page assumes
the Docker Compose deployment or an equivalent with
DATABASE_URL set.
Two ways to authenticate
The two-variable path. Create a fine-grained personal access token scoped to the one docs repository with read-only Contents permission, then set:
GITHUB_PAT=github_pat_...
GITHUB_REPO=owner/docs-repoRestart, and the first build enqueues automatically. Give the token an expiry and rotate it like any credential; it lives only in your environment, never in the database.
An App you own, with short-lived per-repository tokens and the webhook
managed by GitHub. Visit /_readsmith/setup/github on your instance: one
click creates the App with read-only contents + metadata permissions,
the push event, and your webhook URL already configured, then shows you
the three variables to set:
GITHUB_APP_ID=...
GITHUB_APP_PRIVATE_KEY="-----BEGIN RSA PRIVATE KEY-----\n..."
GITHUB_WEBHOOK_SECRET=...
GITHUB_REPO=owner/docs-repoInstall the App on the docs repository, restart, and you are connected. The setup pages disappear as soon as credentials are configured.
Manual App creation (no-JS fallback, GitHub Enterprise Server)
Create a GitHub App under Settings → Developer settings with:
repository permissions Contents: read-only and Metadata: read-only;
the Push event subscribed; the webhook URL set to
https://your-docs-host/_readsmith/api/git/webhook with a secret you
generate. Save the App id, generate a private key, and land all three in
the environment variables above.
Configure exactly one mode. Setting both the App pair and a PAT fails fast at boot with a message naming the conflict.
How updates arrive
Webhooks (default)
With an App, GitHub delivers pushes automatically. In PAT mode, add a plain repository webhook pointing at
https://your-docs-host/_readsmith/api/git/webhookwith content typeapplication/jsonand the secret you set inGITHUB_WEBHOOK_SECRET. Every delivery is verified against that secret before anything is parsed.Polling (firewalled hosts)
If GitHub cannot reach your instance at all, set
GITHUB_POLL_INTERVAL=120(seconds). Each tick sweeps every connected site with one API call per connection, comparing the branch head to the last built commit, and builds on change. Polling and webhooks can coexist safely; duplicate triggers deduplicate.
Pushes to other branches and repositories are ignored. Set GITHUB_BRANCH to
build something other than the repository's default branch.
Deployments, atomicity, and rollback
Every build is an immutable, content-addressed snapshot. Publishing means flipping a pointer once the artifact is fully verified, so readers only ever see the old site or the whole new one. If two pushes race, the newer commit wins even when its build finishes first; the stale build is recorded as superseded and never served.
# Build and publish right now (branch head, a named branch, or an exact commit)
pnpm site:build
pnpm site:build main
pnpm site:build 3f9c2e1a...
# The deployment history, newest first (* marks what is serving)
pnpm site:rollback --list
# Repoint to any prior ready deployment: instant, no rebuild
pnpm site:rollback dep:default:41A running server reflects a publish or rollback within about a minute (pages regenerate on a short cadence); a restart reflects it immediately. Search and Ask-AI reindex automatically after every change of what is being served.
Rebuilds are incremental: a persisted render cache means a one-page edit
re-renders one page, and a shared-snippet edit re-renders exactly the pages
that embed it. History keeps the last 20 non-current snapshots by default
(READSMITH_KEEP_DEPLOYMENTS); older ones are pruned after each publish, and
the currently-served deployment is never touched.
By default a page with a broken component or bad syntax builds anyway, with the
problem reported as a diagnostic: one bad page should not take your docs down.
Set READSMITH_FAIL_ON_ERROR=true to invert that for CI-style strictness: any
page error fails the whole build, and the previous deployment keeps serving.
What the build will not do
The build fetches one tarball of your repository over HTTPS from GitHub, with hard limits on size and file count, and compiles it. It runs no code from the repository, materializes no symlinks, follows no submodules, and writes nothing outside its scratch directory, which is deleted after every build, success or failure. Tokens are held in memory and never logged.