Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
8f1f73a
Prototype: unified Astro + Starlight docs site (Python + Rust)
Roger-luo Jul 11, 2026
b9913d0
Align generated API panels to the shared widget language
Roger-luo Jul 11, 2026
bf93e26
docs(website): mise tasks, full content migration, link/xref harness,…
Roger-luo Jul 12, 2026
1e27fe6
docs(website): zero-warning build, /404 fix, test harness + widget un…
Roger-luo Jul 12, 2026
d310db4
docs(website): resolve docstring cross-references (Python all formats…
Roger-luo Jul 12, 2026
df9d34c
docs(website): move the API version selector into the header (promine…
Roger-luo Jul 12, 2026
28f9347
docs(website): scope site search to the latest API version + harness
Roger-luo Jul 12, 2026
cfc753b
ci(website): run the search-scope check in CI; make it CWD-independent
Roger-luo Jul 12, 2026
14becff
ci(website): host docs on AWS Amplify; drop gh-pages PR previews
Roger-luo Jul 17, 2026
2dc932f
fix(website): unblock pnpm build scripts so the Amplify install succeeds
Roger-luo Jul 17, 2026
a125224
fix(website): pin UV_PYTHON=3.13 for the Amplify build
Roger-luo Jul 17, 2026
56698bb
refactor(website): drive the docs build tool versions from mise, not …
Roger-luo Jul 17, 2026
0bff951
fix(website): commit src/lib + tests/unit/lib swallowed by the .gitig…
Roger-luo Jul 17, 2026
e9b3015
chore: add aws-cli to mise (operational tooling for Amplify)
Roger-luo Jul 17, 2026
7808b59
fix: move aws-cli out of mise.toml into gitignored mise.local.toml
Roger-luo Jul 17, 2026
0fe189f
perf(website): keep the Amplify cache under 5GB so it actually persists
Roger-luo Jul 17, 2026
84c9517
perf(website): cache only tiny high-value paths (venvs still blew 5GB)
Roger-luo Jul 17, 2026
ef24d57
chore: trigger warm-cache Amplify build (verify notebook cache restore)
Roger-luo Jul 17, 2026
c09421c
fix(ci): green the website PR (lint, format, pytest scope, RUSTDOC_NI…
Roger-luo Jul 17, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,5 +32,8 @@ jobs:
- name: Install the project
run: uv sync --all-extras --dev
- name: Run tests
# For example, using `pytest`
run: uv run pytest
# Scope to the package's own suite (matches `mise run test` = `pytest
# test`). Bare `pytest` would also sweep website/emitters/*/tests, whose
# standalone packages aren't installed by `uv sync` here β†’ collection
# errors. Those emitter suites run under the website tooling instead.
run: uv run pytest test
184 changes: 184 additions & 0 deletions .github/workflows/website-deploy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
name: Website Deploy (Astro -> /next/)

# Publishes the WIP Astro/Starlight docs site to the gh-pages SUBPATH `/next/`
# on every push to the `astro-docs` development branch. This is ADDITIVE to the
# live MkDocs site: `mike` (devdoc.yml/pub_doc.yml) owns the branch ROOT plus
# `dev/`, `latest/`, `v*/`; this workflow only ever writes under `/next/`.
#
# NOTE: deliberately wired to `astro-docs`, NOT `main`. Production cutover to
# the root is Phase F (see website-release.yml).
on:
push:
branches: [astro-docs]

# Share the single gh-pages writer group (see website-preview.yml) so this
# deploy serializes with every mike deploy / PR preview / history squash.
concurrency:
group: gh-pages-write
cancel-in-progress: false

permissions:
contents: write # publish.sh pushes to the gh-pages branch

jobs:
deploy:
name: Build + publish /next/
runs-on: ubuntu-latest
env:
# Publish subpath. `base` MUST equal the publish subpath (see publish.sh).
SITE_BASE: /next/
SITE_URL: https://bloqade.quera.com
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0

# mise is the single source of truth for node/pnpm/uv (see mise.toml).
# mise-action installs them onto PATH and caches them.
- name: Set up mise (node + pnpm + uv)
uses: jdx/mise-action@v2
with:
cache: true

# jdx/mise-action does NOT propagate mise.toml [env] into $GITHUB_ENV, so
# surface the pinned nightly explicitly for every later step that reads it
# (the rustup install below + build_versions.py, which defaults
# --rust-toolchain to $RUSTDOC_NIGHTLY). Mirrors amplify.yml's
# `eval "$(mise env -s bash)"`; `mise exec` runs printenv inside the mise
# env where [env] is set. Single source of truth stays mise.toml.
- name: Export RUSTDOC_NIGHTLY (mise.toml [env]) to later steps
run: echo "RUSTDOC_NIGHTLY=$(mise exec -- printenv RUSTDOC_NIGHTLY)" >> "$GITHUB_ENV"

- name: Install bloqade (pins the API source tags for resolve_sources.py)
run: uv sync

- name: Cache the pnpm store
uses: actions/cache@v5
with:
path: ~/.local/share/pnpm/store
key: pnpm-store-${{ runner.os }}-${{ hashFiles('website/pnpm-lock.yaml') }}
restore-keys: |
pnpm-store-${{ runner.os }}-

- name: Install website JS deps
run: pnpm --dir website install --frozen-lockfile

# docs:unit β€” FAST, isolated component/lib unit tests (vitest + Astro
# Container API). The THIRD docs gate, SEPARATE from the link/xref gate
# (docs:check) and the build-warning + Playwright runtime gate (docs:test)
# below. Needs no full build, no browser, and no generated API content, so
# it runs right after the JS deps install and fails fast.
- name: Docs component/lib unit tests (docs:unit)
run: pnpm --dir website test

# rustdoc JSON (format_version 57) needs a pinned nightly. Date comes from
# $RUSTDOC_NIGHTLY (mise.toml [env], exported to $GITHUB_ENV above). Installed
# as an extra toolchain only β€” rustup's default stays stable, so nothing drags
# the main crates onto nightly; build_versions.py invokes it via +override.
- name: Install pinned Rust nightly for rustdoc JSON
run: rustup toolchain install "$RUSTDOC_NIGHTLY" --profile minimal

- name: Cache cargo registry + Astro content
uses: actions/cache@v5
with:
path: |
~/.cargo/registry
~/.cargo/git
website/.astro
key: website-cargo-astro-${{ runner.os }}-${{ hashFiles('website/pnpm-lock.yaml', 'website/docs.sources.toml') }}
restore-keys: |
website-cargo-astro-${{ runner.os }}-

# Content-addressed cache of EXECUTED notebooks (see
# website/emitters/notebooks/src/.../pipeline.py). The key mirrors the
# per-notebook fingerprint: the jupytext sources + the emitter's own
# source + both lockfiles. On a full match every tutorial is reused with
# NO kernel execution; the restore-keys fallback gives a partial hit so
# only the notebooks whose fingerprint changed re-execute. `v2` tracks
# CACHE_SCHEMA_VERSION.
- name: Restore notebook execution cache
uses: actions/cache@v5
with:
path: website/emitters/notebooks/.notebook-cache
key: notebooks-v2-${{ runner.os }}-${{ hashFiles('docs/digital/**/*.py', 'website/emitters/notebooks/src/**/*.py', 'website/emitters/notebooks/uv.lock', 'uv.lock') }}
restore-keys: |
notebooks-v2-${{ runner.os }}-

- name: Generate dev API content
run: >
uv run python website/scripts/build_versions.py
--versions dev
--clone-dir website/sources

# Cache-first (re)generation of guides/tutorials/** from docs/digital/**.
# EXECUTE_NOTEBOOKS=1 => run + cache executable tutorials (a warm cache =>
# zero kernels; a changed notebook => only it re-executes); tsim/gemini
# opt out (static) per the driver manifest, and anything that fails to
# execute degrades to a static render (never fails the build). Runs before
# the Astro build so every tutorial page + its assets exist.
- name: Generate tutorials (cache-first)
env:
EXECUTE_NOTEBOOKS: "1"
run: uv run --project website/emitters/notebooks bloqade-docs-build-notebooks

- name: Build Astro site
env:
XREF_STRICT: "0" # warn (don't fail the WIP deploy) on unresolved xrefs
run: pnpm --dir website build

- name: Configure Git user
run: |
git config --local user.email "github-actions[bot]@users.noreply.github.com"
git config --local user.name "github-actions[bot]"

# publish.sh replaces ONLY gh-pages:/next/ and preserves every sibling
# (the MkDocs root + dev/latest/v*/pr-preview/). SITE_BASE above ('/next/')
# matches the 'next' subpath passed here.
- name: Publish to gh-pages:/next/
run: bash website/scripts/publish.sh website/dist next

# Additive link + cross-reference gate for the WIP dev deploy. Runs AFTER
# publish (existing steps behave exactly as before) so it only reports a
# pass/fail signal. Isolated STRICT rebuild into `dist-check` (leaves the
# published `dist` untouched):
# * XREF_STRICT=1 -> fail on any unresolved <ApiXref>
# * check_links.mjs -> fail on any unreachable internal link / fragment
# anchor. SITE_BASE from the job env keeps base-prefixing consistent.
# * check_xrefs.mjs -> fail if either emitter stops PRODUCING docstring
# <ApiXref> (per-language floors) or any docstring anchor is
# unresolved. Reuses the SAME dist-check build (no redundant build).
# Mirrors `mise run docs:check`.
- name: Check internal links + API xrefs
env:
XREF_STRICT: "1"
run: |
pnpm --dir website exec astro build --outDir dist-check
node website/scripts/check_links.mjs website/dist-check
node website/scripts/check_xrefs.mjs website/dist-check
node website/scripts/check_search_scope.mjs website/dist-check

# ---- docs:test β€” build-warning gate + per-page RUNTIME error crawl.
# SEPARATE from the link/xref gate above (does NOT replace it). Mirrors
# `mise run docs:test`, but the tutorials were already generated above, so
# it just runs the two harness scripts directly. ----
- name: Cache Playwright browsers
uses: actions/cache@v5
with:
path: ~/.cache/ms-playwright
# Keyed on the pnpm lockfile, which pins the exact playwright version
# (the browser build revision is tied to that version).
key: playwright-${{ runner.os }}-${{ hashFiles('website/pnpm-lock.yaml') }}
restore-keys: |
playwright-${{ runner.os }}-

- name: Install Playwright chromium
run: pnpm --dir website exec playwright install --with-deps chromium

- name: Docs build-warning gate + runtime crawl (docs:test)
# check_build.mjs rebuilds website/dist (mirroring docs:build) and FAILS
# on any non-allowlisted build warning/error; crawl_runtime.mjs then
# serves that dist/ and loads every built page in headless Chromium,
# failing on any per-page runtime error.
run: |
node website/scripts/check_build.mjs
node website/scripts/crawl_runtime.mjs website/dist
141 changes: 141 additions & 0 deletions .github/workflows/website-release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
name: Website Release (Astro) [NOT PRODUCTION]

# ============================================================================
# SKELETON for the future tag-based release build of the Astro/Starlight docs
# site (Phase F cutover). It is intentionally:
# * MANUAL-ONLY β€” `workflow_dispatch`, so a `v*` tag push does NOT trigger it
# (the live MkDocs release deploy, pub_doc.yml, still owns
# tag pushes and the gh-pages root);
# * NON-DEPLOYING β€” the publish step is HARD-DISABLED (`if: false`) so it can
# NEVER write to the gh-pages root before cutover.
# Running it today only proves the release CONTENT build (`--versions <X.Y>
# --keep 3`) works end to end; nothing is published.
#
# PHASE F TODO (cutover):
# 1. Add the real trigger: on: { push: { tags: ['v*'] } }.
# 2. Set SITE_BASE=/ (root) + the production SITE_URL.
# 3. Replace the disabled publish step with the real root deploy (retiring or
# redirecting the MkDocs `mike` root), and remove `[NOT PRODUCTION]`.
# ============================================================================
on:
workflow_dispatch:
inputs:
version:
description: "Release doc version to build, e.g. 0.35 (maps to api/<X.Y>)."
required: true
type: string

concurrency:
group: gh-pages-write
cancel-in-progress: false

permissions:
contents: write

jobs:
release:
name: Build release docs (dry run β€” no deploy until cutover)
runs-on: ubuntu-latest
env:
# Phase F TODO: at cutover this becomes SITE_BASE=/ so the release site
# replaces the MkDocs root. Until then we build under /next/ for parity
# with the WIP deploy and DO NOT publish.
SITE_BASE: /next/
SITE_URL: https://bloqade.quera.com
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0

# mise is the single source of truth for node/pnpm/uv (see mise.toml).
# mise-action installs them onto PATH and caches them.
- name: Set up mise (node + pnpm + uv)
uses: jdx/mise-action@v2
with:
cache: true

# jdx/mise-action does NOT propagate mise.toml [env] into $GITHUB_ENV, so
# surface the pinned nightly explicitly for every later step that reads it
# (the rustup install below + build_versions.py, which defaults
# --rust-toolchain to $RUSTDOC_NIGHTLY). Mirrors amplify.yml's
# `eval "$(mise env -s bash)"`; `mise exec` runs printenv inside the mise
# env where [env] is set. Single source of truth stays mise.toml.
- name: Export RUSTDOC_NIGHTLY (mise.toml [env]) to later steps
run: echo "RUSTDOC_NIGHTLY=$(mise exec -- printenv RUSTDOC_NIGHTLY)" >> "$GITHUB_ENV"

- name: Install bloqade (pins the API source tags for resolve_sources.py)
run: uv sync

- name: Cache the pnpm store
uses: actions/cache@v5
with:
path: ~/.local/share/pnpm/store
key: pnpm-store-${{ runner.os }}-${{ hashFiles('website/pnpm-lock.yaml') }}
restore-keys: |
pnpm-store-${{ runner.os }}-

- name: Install website JS deps
run: pnpm --dir website install --frozen-lockfile

# docs:unit β€” FAST, isolated component/lib unit tests (vitest + Astro
# Container API). Needs no full build, no browser, and no generated API
# content, so it runs right after the JS deps install and fails fast.
- name: Docs component/lib unit tests (docs:unit)
run: pnpm --dir website test

# rustdoc JSON (format_version 57) needs a pinned nightly. Date comes from
# $RUSTDOC_NIGHTLY (mise.toml [env], exported to $GITHUB_ENV above). Installed
# as an extra toolchain only β€” rustup's default stays stable, so nothing drags
# the main crates onto nightly; build_versions.py invokes it via +override.
- name: Install pinned Rust nightly for rustdoc JSON
run: rustup toolchain install "$RUSTDOC_NIGHTLY" --profile minimal

- name: Cache cargo registry + Astro content
uses: actions/cache@v5
with:
path: |
~/.cargo/registry
~/.cargo/git
website/.astro
key: website-cargo-astro-${{ runner.os }}-${{ hashFiles('website/pnpm-lock.yaml', 'website/docs.sources.toml') }}
restore-keys: |
website-cargo-astro-${{ runner.os }}-

# Content-addressed cache of EXECUTED notebooks β€” same key as the WIP
# deploy/preview workflows (see website/emitters/notebooks/.../pipeline.py).
# `v2` tracks CACHE_SCHEMA_VERSION.
- name: Restore notebook execution cache
uses: actions/cache@v5
with:
path: website/emitters/notebooks/.notebook-cache
key: notebooks-v2-${{ runner.os }}-${{ hashFiles('docs/digital/**/*.py', 'website/emitters/notebooks/src/**/*.py', 'website/emitters/notebooks/uv.lock', 'uv.lock') }}
restore-keys: |
notebooks-v2-${{ runner.os }}-

# Release build: emit api/<X.Y>/** and PRUNE to the newest 3 releases
# (`dev` is always kept). Mirrors pub_doc.yml's KEEP_RELEASES=3 policy.
- name: Generate release API content (--keep 3)
run: >
uv run python website/scripts/build_versions.py
--versions ${{ inputs.version }}
--clone-dir website/sources
--keep 3

# Cache-first (re)generation of guides/tutorials/** from docs/digital/**
# (see the deploy/preview workflows). Runs before the Astro build so every
# tutorial page + its assets exist.
- name: Generate tutorials (cache-first)
env:
EXECUTE_NOTEBOOKS: "1"
run: uv run --project website/emitters/notebooks bloqade-docs-build-notebooks

- name: Build Astro site
run: pnpm --dir website build

# PHASE F CUTOVER: enable this (real `if:`), rebuild with SITE_BASE=/, and
# publish to the branch ROOT. publish.sh deliberately REFUSES an empty
# subpath today, so root deploys are an explicit cutover decision, not a
# flag flip. Disabled so this workflow can never touch the live root.
- name: Publish release to gh-pages root (DISABLED until cutover)
if: false
run: echo "Phase F cutover not yet enabled β€” no deploy."
8 changes: 8 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@ eggs/
.eggs/
lib/
lib64/
# The broad `lib/` rule above (Python build artifacts) ALSO matches the website's
# real TypeScript source + test dirs, silently excluding them from every clone
# (broke the Astro build: "Could not resolve ../lib/nav"). Re-include them.
!website/src/lib/
!website/tests/unit/lib/
parts/
sdist/
var/
Expand Down Expand Up @@ -185,5 +190,8 @@ main.py
*.json
.ruff_cache
.python-version
# personal, per-machine mise overrides (e.g. operational tools like aws-cli that
# must NOT reach CI/Amplify `mise install`)
mise.local.toml
!package.json
!src/**/**/main.py
6 changes: 3 additions & 3 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,13 +51,13 @@ good-to-have practices:

## Documentation

We use `just` for managing command line tools and scripts. It should be installed when you run `uv sync`. To build the documentation, simply run:
We use [`mise`](https://mise.jdx.dev) to manage the toolchain and command-line tasks (`brew install mise`, then `mise install`). Run `mise run` to list every task. To preview the existing MkDocs documentation, run:

```bash
just doc
mise run mkdocs:serve
```

This will launch a local server to preview the documentation. You can also run `just doc-build` to build the documentation without launching the server.
This will launch a local server to preview the documentation. You can also run `mise run mkdocs:build` to build the documentation without launching the server. The new Astro + Starlight docs site under `website/` has its own `docs:*` tasks (`mise run docs:dev`, `mise run docs:build`, …) β€” see [`website/README.md`](website/README.md). The bare top-level tasks act on the Python package: `mise run build` (`uv build`) and `mise run test`.

## License

Expand Down
Loading
Loading