Skip to content

feat: Zensical documentation site - Material theme, workflow-deployed Pages - #630

Merged
apackeer merged 4 commits into
v2from
feature/docs-zensical-site
Jul 22, 2026
Merged

feat: Zensical documentation site - Material theme, workflow-deployed Pages#630
apackeer merged 4 commits into
v2from
feature/docs-zensical-site

Conversation

@apackeer

@apackeer apackeer commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

What

Replaces the legacy branch-built Jekyll rendering of https://awslabs.github.io/aidlc-workflows/ with a Zensical (Material theme) site built from docs/ and deployed by GitHub Actions: full-text search, light/dark mode, and a sidebar that groups the User Guide, Harness Engineer Guide, and Developer Reference into subsections.

Live preview of this build (served from a fork's Pages): https://apackeer.github.io/aidlc-workflows/

Doc/site-only: no version bump, no CHANGELOG entry, nothing for users to re-copy into projects. No framework behavior changes.

How

  • zensical.toml - site config with an explicit nav (subchapter grouping per doc set, agents ordered by lifecycle position), indigo/cyan palette with dark-mode toggle, admonitions + Mermaid fences. Same stack as sample-collaborative-ai-dlc.
  • pyproject.toml + uv.lock - docs-only dependency group; zensical and all transitives locked, uv sync --locked, uv release pinned in the workflow.
  • .github/workflows/docs.yml - zensical build --strict on every push and pull request to v2 (broken links/anchors fail the build); deploy runs on push/dispatch only, serialized in a single pages concurrency group (cancel-in-progress: false) so an older run can never overwrite a newer site, with Pages/OIDC permissions scoped to the deploy job. All actions SHA-pinned. Bootstrapped on main by ci: bootstrap the docs deploy workflow on the default branch #633 so workflow_dispatch is registered.
  • scripts/docs-rewrite-links.ts - the committed markdown keeps its relative links to files outside docs/ (so local clones navigate normally); this script rewrites them to GitHub blob URLs on the CI checkout just before the build, and exits 1 with file:line if a linked file is missing so a typo'd path fails the deploy instead of shipping a dead link. Fence-aware with CommonMark delimiter rules (opening marker character + length tracked; example links inside code blocks ship verbatim), regression-pinned by tests/unit/t246-docs-rewrite-links-fences.test.ts.
  • roadmap.md -> docs/roadmap.md (pure rename) so the roadmap stays a published page at /roadmap/. The old /roadmap.html URL keeps working on both renderings: a root redirect stub covers the legacy Jekyll site until activation, and the workflow emits site/roadmap.html on the Zensical side.
  • Six stale intra-docs anchors fixed (heading IDs had drifted from the linked fragments; already dead on the live site).
  • /site/, /.cache/, /.venv/ gitignored; the build output is never committed.

Activation (post-merge, needs repo admin)

One-time flip: Settings -> Pages -> Source: "Deploy from a branch" -> "GitHub Actions", then dispatch the workflow (registered via #633) or re-run the last push run. Until the flip, merging is inert: the deploy job fails with a 400 (expected) and the legacy Jekyll site keeps serving unchanged, including the roadmap via the redirect stub.

Breaking (bookmarks/links only)

Published URLs change shape: /docs/guide/00-introduction.html -> /guide/00-introduction/. /roadmap.html redirects to /roadmap/. Repository files outside docs/ are no longer rendered as pages (most already 404'd under Jekyll, which skips dot-directories like dist/claude/.claude/).

Testing

  • zensical build --strict clean after the rewrite step; exit 1 verified on the unrewritten tree (14 issues), so the strict gate is real
  • t246 fence-awareness suite 7/7; smoke+unit tier 174/174 green; doc/version pins t68/t132/t174/t239 green
  • bun scripts/package.ts --check clean; typecheck clean; actionlint clean
  • Deploy path exercised end-to-end on the fork preview above

… Pages (2.5.6)

Replace the legacy branch-built Jekyll Pages rendering with a Zensical
(Material theme) site built from docs/ and deployed by GitHub Actions:

- zensical.toml: site config with an explicit nav grouping the User
  Guide, Harness Engineer Guide, and Developer Reference into sidebar
  subsections; light/dark palette toggle; admonitions + Mermaid fences.
- pyproject.toml (docs-only) pins zensical; .github/workflows/docs.yml
  builds on push to v2 touching docs/** and deploys via
  actions/deploy-pages (all actions SHA-pinned).
- Move roadmap.md -> docs/roadmap.md so the roadmap stays a published
  page (/roadmap/); update the README link.
- Committed markdown keeps its relative links to files outside docs/
  (dist/ agent sources, core/ knowledge, plugins/, root README) so
  local clones navigate normally; the deploy workflow rewrites them to
  GitHub blob URLs at build time via scripts/docs-rewrite-links.ts,
  which exits 1 on a missing link target so a typo'd path fails the
  deploy instead of shipping a dead link. Zensical renders docs/ only,
  unlike Jekyll which rendered the whole branch.
- Fix six stale intra-docs anchors surfaced by the zensical build
  (heading IDs drifted from the linked fragments).
- Gitignore the build output (/site/, /.cache/).

Activation is a one-time repo-settings flip: Pages source from
"Deploy from a branch: v2" to "GitHub Actions".

zensical build after rewrite: clean (0 warnings). Tier: smoke+unit
174/174 green; t68/t132/t174/t239 pins green; package.ts --check clean;
typecheck clean.

@leandrodamascena leandrodamascena left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Findings

P1: Bootstrap the workflow on main first

.github/workflows/docs.yml:13

GitHub only enables workflow_dispatch when the workflow exists on the default branch, which is currently main. Therefore, gh workflow run docs.yml --ref v2 will not work with this workflow only on v2.

Before merging this PR, open a small prerequisite PR against main adding the same workflow file. Keep this PR targeting v2, where the workflow remains necessary for push-triggered deployments.

P1: Make documentation warnings fail the build

.github/workflows/docs.yml:51

zensical build exits successfully when it finds broken internal links or anchors. I reproduced two reported issues followed by exit code zero, meaning the workflow would deploy a broken site.

Please use:

run: uv run zensical build --strict

The current documentation passes strict mode without warnings.

P2: Validate documentation before merge

.github/workflows/docs.yml:3

The workflow only runs after changes are pushed to v2, so broken configuration or documentation is detected after merge.

Please add a pull_request trigger targeting v2, run the build for PRs, and condition the deploy job so it only runs for pushes or manual dispatches.

P2: Preserve the roadmap during the Pages cutover

README.md:8

The new /roadmap/ URL currently returns 404, while /roadmap.html works. Because Pages still publishes the root of v2 through Jekyll, merging the rename first will move the legacy page to /docs/roadmap.html before the administrator switches Pages to GitHub Actions.

Please preserve a root-level redirect/stub until activation, or coordinate the Pages source change so the README never points to a missing page.

P2: Trigger validation when out-of-tree targets change

.github/workflows/docs.yml:7

The documentation links to files under core/, dist/, and plugins/, but changes to those directories do not trigger this workflow. Renaming or deleting one of those targets can therefore leave published dead links without running the rewriter's validation.

Please include the linked source trees in the path filters, or remove the restrictive path filter.

P2: Commit the Python dependency lock

pyproject.toml:7
.github/workflows/docs.yml:30

Only the direct Zensical dependency is pinned. Without a committed uv.lock, transitive dependencies are resolved again on every deployment. Additionally, setup-uv installs latest, so the build tool itself also floats.

Please commit uv.lock, use uv sync --locked, and pin the uv release.

P2: Do not rewrite links inside fenced examples

scripts/docs-rewrite-links.ts:39

The regular expression processes Markdown code fences as ordinary content. I reproduced a relative link inside a fenced Markdown example being rewritten to a GitHub URL; a missing example target also caused the script to fail.

Please make the rewrite fence-aware or use a Markdown parser rather than replacing across the raw document.

P3: Scope Pages permissions to the deploy job

.github/workflows/docs.yml:15

The workflow-level permissions grant pages: write and id-token: write to the build job, although only the deploy job needs them.

Please leave contents: read on the build job and grant Pages/OIDC permissions only to deploy.

Verification

The current branch passes zensical build --strict, bun scripts/package.ts --check, actionlint, version synchronization, and all 174 smoke/unit test files (4,310 assertions).

…eps, fence-aware rewriter, roadmap redirect

Review findings on the docs-site PR:

- zensical build --strict: broken links/anchors now fail the build
  (verified: exit 1 on the unrewritten tree, exit 0 after the rewrite).
- pull_request trigger on v2 validates docs changes pre-merge; the
  Pages artifact upload and deploy job are conditioned to push/dispatch.
- Path filters removed: renames under core/, dist/, plugins/ now also
  run the build, so the rewriter's exists-on-disk check catches doc
  links going stale.
- Workflow-level permissions reduced to contents: read; pages: write +
  id-token: write granted only to the deploy job.
- uv.lock committed, uv sync --locked, setup-uv pinned to 0.11.28
  (matching the lockfile's generator) instead of 'latest'.
- docs-rewrite-links.ts is fence-aware: lines inside ``` / ~~~ blocks
  ship verbatim (example links are content, not navigation); missing
  targets now report file:line.
- /roadmap.html keeps working on both renderings: a root redirect stub
  covers the legacy Jekyll site until activation (README keeps the
  .html URL), and the workflow emits site/roadmap.html on the Zensical
  side; the stub documents its own removal condition.
- .venv/ gitignored (created by uv sync).

Workflow bootstrap on main (workflow_dispatch registration) is a
separate prerequisite PR against main.

actionlint clean; strict build + rewrite dry-run green; pinned tests
t68/t132/t174/t239 green.
@apackeer

Copy link
Copy Markdown
Contributor Author

Thanks @leandrodamascena - all eight findings addressed in e1485fe (kept as a separate commit on top of the reviewed base for an incremental diff):

P1 strict build - zensical build --strict in the workflow. Verified both directions: exit 1 on the unrewritten tree (14 issues), exit 0 after the rewrite step runs.

P1 bootstrap on main - you're right, workflow_dispatch only registers from the default branch. Prerequisite PR opened: #633 (byte-identical docs.yml on main, inert there except dispatch registration). The activation notes in this PR's description stand corrected by that PR.

P2 PR validation - pull_request trigger on v2 added; the artifact upload and the entire deploy job are conditioned on github.event_name != 'pull_request', so PRs build-and-validate only.

P2 roadmap 404 - fixed for both eras: a root roadmap.html redirect stub keeps the legacy Jekyll URL working post-merge/pre-activation (the README keeps the .html URL, which Jekyll serves verbatim), and the workflow emits site/roadmap.html on the Zensical side. The stub documents its own removal condition (delete after the Pages source flip).

P2 path filters - removed entirely. Every push/PR to v2 now runs the build, so a rename under core/, dist/, or plugins/ that strands a doc link fails the rewriter's exists-on-disk check (which now reports file:line).

P2 lockfile - uv.lock committed, uv sync --locked, and setup-uv pinned to 0.11.28 (the lockfile's generator) instead of latest.

P2 fenced links - the rewriter is fence-aware (``` and ~~~, CommonMark up-to-3-space indent): lines inside fences ship verbatim. Reproduced your case in a fixture - a fenced fake link is untouched and no longer errors, while a real out-of-tree link on the same page still rewrites.

P3 permissions - workflow level reduced to contents: read; pages: write + id-token: write granted only to the deploy job.

Re-verified at e1485fe: actionlint clean, strict build + rewrite dry run green (redirect emit included), bun scripts/package.ts --check clean, t68/t132/t174/t239 green, smoke+unit tier green. The fork preview at https://apackeer.github.io/aidlc-workflows/ still reflects the reviewed base commit's build; the fixes don't change the rendered site apart from the added /roadmap.html redirect.

@leandrodamascena leandrodamascena left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for addressing the original review. I verified that the main bootstrap PR #633 is merged with a byte-identical workflow, and that strict builds, PR-only validation, roadmap compatibility, path coverage, locked dependencies, and job-scoped permissions are now in place.

Two issues remain:

P2: Track the opening fence delimiter instead of toggling on every fence-like line

scripts/docs-rewrite-links.ts:46

The new implementation toggles inFence for every line beginning with three or more backticks/tildes. That is not CommonMark fence-closing behavior: a closing fence must use the same marker character and at least as many markers as the opener.

I reproduced this with a valid four-backtick Markdown fence containing a three-backtick example. The inner three-backtick line incorrectly toggles inFence off, and the following example link is processed as navigation:

````markdown
```text
[example](../../missing.md)
```

The script reports the fenced link as missing and exits 1. Please retain the opening marker character and length, and only close on a compatible delimiter. A focused test covering ordinary, tilde, longer/nested, and real out-of-tree links would prevent regression.

### P2: Serialize all production Pages deployments in one concurrency group
`.github/workflows/docs.yml:18`

Including `github.event_name` in the workflow concurrency key puts a `push` deployment and a manual deployment for the same branch in different groups. They can run concurrently, so an older manual run can finish after a newer push and replace the site with stale content.

GitHub's Pages starter workflow deliberately uses one `pages` concurrency group for production deployments. Please keep PR builds independently cancellable, but serialize the `deploy` job across push/manual runs, for example with job-level `concurrency: { group: pages, cancel-in-progress: false }`.

Verification performed on `e1485fe9`: GitHub docs build check passed with deploy skipped; #633 is merged and workflow-identical; actionlint passed; locked install and `zensical build --strict` passed; package parity and typecheck passed; 27 targeted documentation/version tests passed. The aggregate lint command still reports the pre-existing `core/tools/aidlc-doctor-bundle.ts:628` warning from the base branch, unrelated to this PR.

@dreamorosi

Copy link
Copy Markdown

Why does a documentation framework update causes a version increase for AIDLC?

This is just needless churn for customers.

…ges deploys

Round-2 review findings:

- docs-rewrite-links.ts tracks the OPENING fence delimiter (marker char
  + length) instead of toggling on every fence-like line: a fence closes
  only on the same character, at least as many markers, and no info
  string - so a three-backtick example inside a four-backtick block is
  content, a tilde line never closes a backtick fence, and a longer
  marker carrying an info string is content too. Regression-pinned by
  tests/unit/t246-docs-rewrite-links-fences.test.ts (runs the real
  script as a subprocess against fixture markdown: plain/tilde fences,
  nested-delimiter cases, rewrite-resumes-after-close, missing-target
  exit 1 with file:line).
- Production Pages deployments are serialized in one shared `pages`
  concurrency group (cancel-in-progress: false) on the deploy job, so a
  push deploy and a manual dispatch can never interleave and an older
  run cannot overwrite a newer site; PR validation builds stay
  independently cancellable per ref (workflow-level group now cancels
  in-progress only for pull_request events).

actionlint clean; t246 7/7; strict build + rewrite dry run green;
t68/t132/t174/t239/t246 green; typecheck clean.
@apackeer

Copy link
Copy Markdown
Contributor Author

@leandrodamascena both round-2 findings fixed in 15e77c5:

P2 fence delimiters - the rewriter now tracks the opening delimiter (marker character + length) and closes only on the same character, at least as many markers, and no info string. Your four-backtick repro is covered: the inner three-backtick line is content, the example link ships verbatim, exit 0. Regression-pinned by the new tests/unit/t246-docs-rewrite-links-fences.test.ts (t244/t245 are claimed by open PRs #617/#596/#616), which runs the real script as a subprocess against fixture markdown: ordinary + tilde fences, your nested-delimiter case, the marker-character rule (a tilde line cannot close a backtick fence), the info-string-on-closer rule, rewrite-resumes-after-close, and missing-target exit 1 with file:line. 7/7 green.

P2 deploy serialization - the deploy job now carries its own concurrency: { group: pages, cancel-in-progress: false } per the Pages starter-workflow convention, so push and manual deployments share one production queue and an older run cannot overwrite a newer site. The workflow-level group is docs-build-${{ github.ref }} with cancel-in-progress true only for pull_request events, keeping PR validation independently cancellable without touching production builds.

Verified at 15e77c5: actionlint clean, t246 7/7, rewrite + zensical build --strict dry run green, t68/t132/t174/t239/t246 green, typecheck clean.

The changelog policy exempts doc-only changes from version bumps, and
this PR's own entry said "nothing to re-copy into projects" - a new
aidlc-version.ts in every dist tree would wrongly signal installed
copies are outdated. Version stays 2.5.5; the CHANGELOG entry, badge
bump, and the six version-file diffs are removed. The published-URL
migration is recorded in the PR description and served by the
/roadmap.html redirects.

Also removes this PR from the 2.5.x version-slot contention entirely.

package.ts --check clean; t68/t174/t239/t246 green.
@leandrodamascena
leandrodamascena self-requested a review July 22, 2026 20:01
@apackeer apackeer changed the title feat: Zensical documentation site - Material theme, workflow-deployed Pages (2.5.6) feat: Zensical documentation site - Material theme, workflow-deployed Pages Jul 22, 2026
@apackeer
apackeer merged commit 1806d44 into v2 Jul 22, 2026
2 checks passed
@apackeer
apackeer deleted the feature/docs-zensical-site branch July 22, 2026 20:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants