sq.io website

May 30, 2026 · View on GitHub

Netlify Status

This directory is the source for the sq.io website inside the sq monorepo (site/). It hosts documentation for the sq CLI.

This site is built using:

Production publishes to sq.io are manual (workflow dispatch) or automatic on stable sq releases. Merging site/** to master runs Site CI only. See CI Workflow below.

Contributing

Open an issue or submit a pull request against neilotoole/sq in this monorepo.

1. Clone the monorepo and enter this directory

git clone https://github.com/neilotoole/sq.git && cd sq/site

2. Install dependencies

From this directory (site/), use the Makefile (recommended) or Bun directly:

make deps
# same as: bun install

3. Make changes and test locally

# Dev server at http://localhost:1313 (may take a minute to come up; be patient)
make site-local
# same as: bun start

# Stable checks (what PRs block on): scripts, styles, markdown, and internal links
make site-test
# same as: bun run test:ci

# Optional: Docker smoke checks against a containerized dev server (:8080)
make smoke-test

# Optional: full link crawl (includes third-party URLs; can be noisy/slow)
make site-test-full
# same as: bun run test:full

# Production build to public/
make site-build
# same as: bun run build

Verify local tooling (Bun, Hugo, Netlify CLI, jq, curl): make check.

Netlify API credentials (maintainers only, for make site-netlify-validate):

cp .env.example .env
# Edit .env — see .env.example for where to get each value
make check-netlify

check-netlify runs scripts/checkenv.bash --merge against .env (sync keys from .env.example, then validate; no interactive prompts). .env is gitignored; never commit it.

One-shot check matching Site CI (deps → test → build): make ci.

Netlify deploy-preview validate (Dependabot Full mode / Layer B):

Check out the PR branch at its current head (gh pr checkout <n>) with a clean working tree before validating — Layer B uploads the local site/ tree, not GitHub’s PR ref.

make check-netlify                        # once per machine / after editing site/.env
export MESSAGE="PR #573 dependabot shx"   # optional
make site-netlify-validate

Same variables as Site Publish (dispatch) GitHub Actions secrets.

Runs netlify-cli deploy --build --context deploy-preview and polls the Netlify API until state=ready. See .agents/skills/sq-site-dependabot/.

Site testing

Think of site testing as two layers:

  1. Stable checks (merge-blocking on PRs) make ci runs make site-test, which runs bun run test:ci. That includes link checking against the temporary local build we serve for linting, but it does not crawl arbitrary third-party websites. This is what you want to be strict about: broken docs routes, missing local assets, bad internal links, etc.

  2. External link crawl (informational on PRs) GitHub Actions also runs a full bun run lint:links crawl after make ci. That step is configured as non-fatal because third-party sites can be slow, flaky, or rate-limit automated requests even when your change is fine.

If you want the full external crawl locally, use make site-test-full (or bun run lint:links).

Heads up (bun run test vs CI): bun run test currently runs the full lint pipeline (including external link crawling). PR CI uses bun run test:ci via make site-test, which is the stable lane.

4. Submit a Pull Request

Create a PR in neilotoole/sq with your changes under site/.

Content Style Guide

Alerts

Use Hugo alert shortcodes to highlight important information:

{{< alert icon="👉" >}}
This is an important note for the reader.
{{< /alert >}}

Development

CI Workflow

The project uses GitHub Actions and Netlify for continuous integration:

TriggerAction
Push to master or develop (and PRs).github/workflows/site-ci.yml runs make ci when site/** changes, plus an informational full link crawl
Pull requestNetlify deploy preview (when configured)
Stable GitHub release (vX.Y.Z).github/workflows/site-publish-release.yml builds, deploys to sq.io, and runs post-deploy smoke checks
Manual workflow_dispatch.github/workflows/site-publish-dispatch.yml — publish doc or dependency changes before the next release
Daily schedule / manual.github/workflows/site-links-nightly.yml runs a full external link crawl
Daily schedule / manual.github/workflows/site-data-nightly.yml refreshes data/github.toml; push triggers Site CI only (no production deploy)

Merging to master with changes under site/** runs Site CI (lint, build, artifact validation) but does not update production. Netlify's git integration remains suppressed via [context.production] ignore = "exit 0" in netlify.toml — production deploys go through GitHub Actions + the Netlify CLI (site-publish-netlify.yml).

To publish before the next sq release, use Site Publish (dispatch): Actions tab → Site Publish (dispatch) → Run workflow → select ref → type DEPLOY. Stable sq releases trigger Site Publish (release) automatically when GoReleaser publishes the GitHub release. Requires NETLIFY_AUTH_TOKEN and NETLIFY_SITE_ID repo secrets. The GitHub production environment must not require manual approval or publish stalls.

Netlify still provides deploy previews for every PR with Lighthouse audits for performance, accessibility, best practices, and SEO. Before merging, click through to the deploy preview (e.g., the deploy-preview URL from the PR checks) to verify your changes look correct.

Build-time data & nightly refresh

The header's version badge and GitHub star count are computed at build time rather than fetched in the browser. scripts/gen-site-data.js fetches the latest sq release and the repo star count and writes site/data/github.toml; it also writes static/version.json (served at /version via a redirect). The header template renders those values. The generator runs during prebuild (so every bun run build / make site-build refreshes them), and the committed data/github.toml is the offline / fetch-failure fallback — a GitHub hiccup never fails a build.

The nightly site-data-nightly.yml workflow (07:00 UTC) keeps data/github.toml current in master. When it commits a change, Site CI runs on master (build only — no production deploy until manual dispatch or the next stable release).

Since master uses classic branch protection (enforce_admins=false, no per-app bypass), that push authenticates with the SITE_DATA_PUSH_TOKEN repo secret — a fine-grained PAT owned by a repo admin (Contents: read/write on neilotoole/sq); an admin's push bypasses the PR requirement. Keep the token scoped to this repo only, and prefer an expiration or periodic rotation (it is currently set without one). Revoke it if leaked, or if this workflow is removed.

Commands

Prefer make from this directory for install, test, and production build (see Makefile). In Common.make, make build builds the Docker image, not the Hugo site; use make site-build for a normal production build to public/.

Make targetBun equivalentDescription
make checkVerify Bun, Hugo, Netlify CLI, jq, curl
make check-netlifymake check + checkenv on .env
make depsbun installInstall dependencies
make site-localbun scripts/dev-server.jsHugo dev server
make smoke-test(script)Docker smoke checks (validate-build.sh --start)
make site-testbun run test:ciStable linters + internal link check
make site-test-fullbun run test:fullFull linters + external link crawl
make site-buildbun run buildProduction site → public/
make ci(sequence below)deps, then site-test, then site-build (CI)
make site-netlify-validateNetlify deploy-preview build + API poll (NETLIFY_*)

Other package.json scripts (call with bun run …):

CommandDescription
bun run previewBuild and serve locally at http://localhost:1313
bun run gen:cmd-helpRegenerate command help files in content/en/docs/cmd/
bun run gen:syntax-cssRegenerate syntax highlighting CSS

Regenerating Command Documentation

The gen:cmd-help script (./content/en/docs/cmd/generate-cmd-help.sh) regenerates the .help.txt files in content/en/docs/cmd/. These files contain the help text for each sq command and are included in the documentation pages.

Link checking uses linkinator.

  • Stable / PR-blocking (test:ci) uses lint:links:internal, which checks the locally served build without following arbitrary third-party http(s) links.
  • Full crawl (lint:links) follows third-party links too. This is useful, but inherently more flaky.

Some sites (e.g., StackOverflow) block automated crawlers, returning 403 errors in CI. Those domains are excluded in linkinator.config.json.

Note: linkinator timeouts are configured in milliseconds in linkinator.config.json (see linkinator CLI help).

Redirects

  • You can use the Hugo alias mechanism to maintain an old path that will redirect to the new path.
  • If you need a redirect that's not associated with Hugo content, add an entry to the static/_redirects file. This is what the site uses to serve the sq.io/install.sh script.

Misc

  • Doks comes with commands for common tasks.
  • Use bun run gen:syntax-css to regenerate the syntax highlight theme. The themes (light and dark) are specified in generate-syntax-css.sh.

Asciinema

The site makes use of asciinema via the gohugo-asciinema Hugo module.

Typically, casts are stored in ./static/casts. To include a cast, use this shortcode:

{{< asciicast src="/casts/home-quick.cast" theme="monokai" poster="npt:0:20" rows="10" speed="1.5" idleTimeLimit="3" >}}
  • poster="npt:0:20" specifies that the "poster" or cover image should be taken from 0m20s into the cast.
  • Add autoPlay="true" if the cast should start immediately. This is usually not the case.

If you see this problem:

Error: Error building site: "content/en/_index.md:9:1": failed to extract shortcode: template for shortcode "asciicast" not found

It probably means that the hugo module cache is out of whack. Run bun install and try again.

Documentation

Communities

Acknowledgements

Deploys by Netlify