Skip to content
Readsmith

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-repo

Restart, 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.

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

  1. 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/webhook with content type application/json and the secret you set in GITHUB_WEBHOOK_SECRET. Every delivery is verified against that secret before anything is parsed.

  2. 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:41

A 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.

Was this page helpful?