feat: single-page documentation type - #36
Merged
Merged
Conversation
Onboarding a doc app previously required a full static-site toolchain: a
headless build, a marketplace.json manifest, and a release workflow. That is
the right cost for a real docs site and far too much for the common case of a
team with one or two markdown files, who ended up parked behind an iframe entry
or not onboarded at all.
A docs repo now onboards by adding ONE workflow file and nothing else.
actions/publish-docs/ — reusable composite action
Takes a YAML/JSON list of doc definitions (md, title, description, slug, plus
optional icon and tags), validates it defensively — every failure names the
entry and the fix, and all problems are reported in one run — then renders
each markdown file to headless HTML inside the action: GFM tables, task
lists, autolinks and footnotes, highlight.js code fences on the slate surface
from STYLE_GUIDE.md, and ```mermaid blocks rendered client-side.
Mermaid is vendored into the artifact rather than pulled from a CDN, because
marketplace pages are re-hosted inside a web fragment behind a strict CSP; if
the script never runs the diagram source stays visible.
Every doc in the repo is packed into ONE dist.tar.gz — a bundle.json manifest
plus a directory per slug — and uploaded to the repo's latest release,
replacing any existing asset.
Dependencies are pinned inside the action dir so it stays self-contained and
the root package.json is untouched. src/template.js is deliberately
dependency-free: the knowledge base's fixture generator imports it, so the
test fixture cannot drift from real published output.
Knowledge base support for type: "single-page"
A registry entry carries no per-doc metadata at all — { repo, type, version }
— so adding or renaming a doc never touches this repo again. The build reads
bundle.json and expands that one entry into N apps, extracting each doc into
apps/{slug}/. Expansion is recorded in apps/.single-page.json and spliced back
into the registry by loadRegistry(), so Astro resolves exactly what the build
did without mutating the committed apps.json.
Manifest parsing, expansion and the global slug-collision guard live in
src/utils/single-page.js, shared by the GitHub fetch path, the prebuilt/local
path and Astro, so the three cannot drift. A doc bundle can never quietly take
over another app's URL prefix.
Rendering mirrors the iframe type: getAppPages() emits one route flagged
singlePage, and the catchall wraps the body in main.mp-single-page — masthead,
no sidebar, ~800px of centred content. Expanded docs appear as normal catalog
cards.
Tests and docs
A hermetic single-page bundle fixture (two docs, exercising headings, a table,
a code block, a task list and mermaid) is generated by setup-test-apps.mjs and
committed unpacked so it stays reviewable and CI needs no setup step. Build
integrity covers expansion, the absent sidebar, the centred-column class,
absolute URL rewriting and vendored mermaid; the fragment suite covers card
listing, navigation and shadow-DOM rendering. A CI job runs the action's own
self-test, which the Playwright suites deliberately do not depend on.
contract/SINGLE_PAGE.md documents the bundle format and the copy-paste
workflow; README, CLAUDE.md and HEADLESS_RULES.md describe all three
onboarding types.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CRZk4ZQsApxLANJtzQpVXb
The action only ever produces single-page bundles — bundle.json, one directory per doc, the centred reading column. Calling it "publish-docs" implied it was the general way to publish documentation, which would send teams with a real docs site down the wrong path; the packaged type still goes through their own headless build and marketplace.json. Renamed with git mv so history follows. Every reference updated: the CI job id and its working directories, the action's own README and package name, the onboarding `uses:` in contract/SINGLE_PAGE.md and README.md, the setup-test-apps import of template.js, the fixture text, and the error messages in build-vite.js / fetch-apps.js that point onboarding repos at the action. The onboarding repo's own workflow filename stays publish-docs.yml — that is the consuming repo's file, not ours. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CRZk4ZQsApxLANJtzQpVXb
The single-page type had no way to look at real action output in a browser —
the E2E fixture is hand-written body HTML by design, so it proves the pipeline
but not the rendering of genuinely converted markdown.
Registers the sibling knowledge-base-example-single-page repo (three markdown
docs, dist.tar.gz produced by the real action, vendored mermaid included) via
the existing `prebuilt` mechanism:
npm run build:local && npm run preview
http://localhost:4321/knowledge-base/
That artifact lives outside this repo, so a committed entry pointing at it would
break CI's build job, which only checks out this repo. Rather than leaving the
wiring undocumented in a README, entries may now carry `"optional": true`: the
build skips them with a warning when their prebuilt/localPath artifact is
missing. Entries without the flag still hard-fail, so a lost fixture can never
quietly produce an empty deployment — the safety that matters is kept, and only
entries that opt in are allowed to be absent.
Emitted from setup-test-apps.mjs so apps.json stays stable across test runs
(the Playwright webServer regenerates it before every build). Kept last so the
hermetic fixture remains the first single-page entry the suites inspect.
Verified: clean-tree headless build with the sibling repo absent exits 0, warns,
and emits no example pages; with it present, build:local renders all three docs
in the centred column with no sidebar, and preview serves them plus the vendored
mermaid bundle at 200.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CRZk4ZQsApxLANJtzQpVXb
oto-macenauer-absa
force-pushed
the
feat/single-page-docs
branch
from
August 4, 2026 10:59
89fbe51 to
4738ba3
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
feat: single-page documentation type (#35)
Closes #35.
Adds a third onboarding type to the knowledge base:
single-page— zero-config documentation published straight from plain markdown. A docs repo onboards by adding a single workflow file; no mkdocs, no build config, no manifest files.Reusable action —
actions/publish-single-page-docsdocslist (YAML) — each entrymd,title,description,slug, optionalicon+tagscontract/STYLE_GUIDE.md), Mermaid diagrams (vendored, no CDN — pages stay self-contained)dist.tar.gz(subdir per slug +bundle.jsonmanifest) and uploads it to the repo's latest release (--clobber); optionalrelease-taginput defaults to the triggering releasepackage.json/lockfile), covered by a new CI self-test jobKnowledge base
apps.jsonentry:{ "repo": "org/repo", "type": "single-page" }— no per-doc metadata; the build readsbundle.jsonand expands the entry into one app per doc (slug-collision guarded, expansion recorded inapps/.single-page.jsonand spliced back vialoadRegistry()so Astro sees what the build saw)main.mp-single-pagereading column, light-onlyprebuiltbundles supported for hermetic/offline builds; registry entries may be"optional": true(skip-with-warning when the local artifact is absent — keeps CI green while enabling local visual testing against a sibling example repo)Onboarding (copy-paste for a docs repo)
Docs & tests
contract/SINGLE_PAGE.md(bundle format + onboarding guide); README, CLAUDE.md,contract/HEADLESS_RULES.mdupdatedNotes for reviewers
knowledge-base-example-single-page(not part of this PR) exercises the real action output visually vianpm run build:local && npm run preview🤖 Generated with Claude Code
https://claude.ai/code/session_01CRZk4ZQsApxLANJtzQpVXb
Release Notes