diff --git a/.kb-sync/features.yml b/.kb-sync/features.yml index 59165fc..e8edb51 100644 --- a/.kb-sync/features.yml +++ b/.kb-sync/features.yml @@ -9,8 +9,8 @@ # `synced` is empty until the first full run documents a release. synced: - tag: null - sha: null + tag: v1.3.1 + sha: f95eb35b47051b66fb0154319780aefe4431ba17 # Upstream paths that never carry user-facing behaviour; changes here are ignored. ignore: diff --git a/data/showcase.yml b/data/showcase.yml index 7e183da..3e85684 100644 --- a/data/showcase.yml +++ b/data/showcase.yml @@ -12,13 +12,14 @@ content: | - Docs Example + Knowledge Base @@ -27,15 +28,15 @@ content: |
- MkDocs Template + User Guide

- Publish your docs to the
- Knowledge Base + One portal for all
+ your documentation

-

A minimal, branded template. Clone it, write Markdown, tag a release — your documentation is live.

+

The Knowledge Base collects documentation from every team's repository into a single branded portal. Publish from a Markdown file or a full docs site, run the portal yourself, or embed it in your app.

@@ -43,52 +44,52 @@ content: |
- -

Everything you need, nothing you don't

-

The template ships with a pre-built theme, a build script, and a CI/CD pipeline. You only ever touch your content and configuration.

+ +

Publish, run and embed

+

Teams keep their docs in their own repositories. The Knowledge Base aggregates them at build time into one static site.

-

Markdown-first content

-

Write in plain Markdown. MkDocs builds it into polished HTML — no HTML knowledge needed.

+

Three ways to publish

+

Single-page docs from Markdown with one workflow file, a packaged static site, or an iframe stopgap for docs hosted elsewhere.

-

Zero build setup

-

Run npm run build and you're done. The script installs dependencies, builds the docs, and packages the artefact.

+

A checked contract

+

Every requirement has a rule ID. Run the checker locally, on pull requests with check-docs, and on every release.

-

Branded theme

-

Pre-built CSS with a customisable colour palette and typography. Theme files stay untouched.

+

Run your own

+

A reusable build workflow, a hardened nginx image and a deployment-repo pattern, including private networks and mirrors.

-

Headless & standalone modes

-

Build a standalone site or a headless fragment that slots directly into the knowledge base chrome.

+

Embed anywhere

+

Serve the portal as a web fragment inside a host app, with no page reloads and no third-party requests.

-

CI/CD pipeline included

-

A GitHub Actions workflow builds and packages your docs on every tagged release — just push and go.

+

Release-driven

+

Publish a GitHub Release and the action attaches kb-docs.tar.gz. The portal picks it up on its next build.

-

Expandable structure

-

Add Markdown pages or standalone HTML pages at any time. Navigation updates automatically from page frontmatter.

+

Docs Template

+

This guide is built with the MkDocs Docs Template: clone it, write Markdown, tag a release.

@@ -99,29 +100,29 @@ content: |
-

From clone to live docs in three steps

-

No framework expertise required. The template is designed for teams who want to focus on content, not tooling.

+

From repo to portal in three steps

+

The same path works for a Markdown file or a full docs site.

1
-

Clone and configure

-

Clone this repo, update kb-docs.json with your slug and name, and set site_name in mkdocs.yml. That's the only configuration you need.

+

Pick a type

+

Add one workflow for single-page docs, or make your site's build headless and describe it in kb-docs.json.

2
-

Write your content

-

Replace the starter Markdown files in docs/ with your own content. Add pages by creating .md files — navigation is generated automatically from frontmatter.

+

Publish a release

+

The publish action validates your docs against the contract rules and attaches kb-docs.tar.gz to the release.

3
-

Tag a release

-

Push a version tag (e.g. v1.0.0). The GitHub Actions workflow builds your docs, packages them, and attaches the artefact to the release — ready for the knowledge base to consume.

+

Register

+

Open a PR adding { "repo": "owner/name" } to the deployment's registry. Everything else is read from your manifest.

@@ -132,20 +133,20 @@ content: |

Ready to publish your documentation?

-

Read the template docs to get started, or visit the full user guide for setup and registration.

+

Start with the onboarding guide, or read how to run and embed the Knowledge Base.

- Knowledge Base Docs Example — MkDocs Template + Knowledge Base User Guide — built with the Docs Template Docs  ·  - Knowledge Base + How it works
diff --git a/docs/index.md b/docs/index.md index 77d42c2..cd16380 100644 --- a/docs/index.md +++ b/docs/index.md @@ -20,15 +20,19 @@ At build time it: 4. Produces a single static `dist/`, served by nginx in Docker or embedded into a host application as a web fragment. -The output makes no third-party requests at runtime. +The output makes no third-party requests at runtime. This guide describes release +**v1.3.1**. ## Who this guide is for | You want to… | Start with | |---|---| -| Publish your team's documentation to the Knowledge Base | Publishing your docs | -| Run your own Knowledge Base deployment | Running a Knowledge Base | -| Embed the Knowledge Base inside a host application | Embedding | +| Understand how the portal works and what readers see | [How it works](kb/how-it-works.md) | +| Publish your team's documentation to the Knowledge Base | [Choosing how to onboard](kb/onboarding.md) | +| Check your docs against the contract | [Contract rules and the checker](kb/rules.md) | +| Run your own Knowledge Base deployment | [Registry](kb/registry.md), [Building](kb/building.md), [Deployment](kb/deployment.md) | +| Embed the Knowledge Base inside a host application | [Web fragment embedding](kb/embedding.md) | +| Let an AI agent onboard a repo | [Agent skill](kb/agent-skill.md) | | Start a new docs site quickly | [Using the Docs Template](template.md) | ## About this site diff --git a/docs/kb/actions.md b/docs/kb/actions.md new file mode 100644 index 0000000..c98adf7 --- /dev/null +++ b/docs/kb/actions.md @@ -0,0 +1,102 @@ +--- +title: GitHub Actions +order: 25 +section: Publish Your Docs +--- + +# GitHub Actions + +Three reusable composite actions live in `AbsaOSS/knowledge-base/actions/`. They share +one pinned dependency tree, so your repo needs no toolchain, `package.json` or lockfile +for them. They run on Node 20. + +All three also take `npm-registry`, `npm-token`, `node-mirror` and `node-mirror-token` +for runners without public internet; see [Private networks](private-networks.md). + +## publish-docs + +Validates a built headless site against the [contract](rules.md), packs +`kb-docs.tar.gz`, and attaches it to a release (replacing an existing asset of that +name). + +```yaml +- uses: AbsaOSS/knowledge-base/actions/publish-docs@v1 + with: + manifest: kb-docs.json + dist: dist +``` + +| Input | Required | Default | Description | +|---|---|---|---| +| `manifest` | no | `kb-docs.json` | Path to the manifest, relative to the workspace. | +| `dist` | no | `dist` | The built headless output. With one app, that app's directory; with several, a directory holding one subdirectory per slug. | +| `release-tag` | no | triggering release, else the latest | Release to attach to. | +| `github-token` | no | `{% raw %}${{ github.token }}{% endraw %}` | Needs `contents: write`. | +| `notify-repo` | no | empty | `owner/name` of a deployment repo to notify after publishing. Needs `notify-token`; skipped silently if either is unset. | +| `notify-token` | no | empty | Token with `contents: write` on `notify-repo` only. The default token cannot dispatch to another repository. | +| `npm-registry`, `npm-token`, `node-mirror`, `node-mirror-token` | no | empty | See [Private networks](private-networks.md). | + +| Output | Description | +|---|---| +| `slugs` | Comma-separated slugs published. | +| `count` | Number of apps in the artifact. | +| `artifact` | Absolute path of the packed `kb-docs.tar.gz`. | +| `release-tag` | Tag of the release it was uploaded to. | + +With `notify-repo` and `notify-token` set, a successful publish fires a +`repository_dispatch` of type `kb-docs-published` carrying `{ repo, tag, slugs }` at the +deployment repo, so it rebuilds without waiting for its schedule. A failed notify never +fails the publish. See [Deployment](deployment.md#rebuilding-when-a-docs-repo-publishes). + +## check-docs + +Runs the same checks on a pull request without packing or uploading anything. Findings +are annotated by rule ID and summarised on the run. Add it next to the publish workflow +with the same build step and `dist`. + +```yaml +on: pull_request + +jobs: + check: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - run: npm ci && npm run build -- --headless + - uses: AbsaOSS/knowledge-base/actions/check-docs@v1 + with: + manifest: kb-docs.json + dist: dist +``` + +| Input | Required | Default | Description | +|---|---|---|---| +| `manifest` | no | `kb-docs.json` | Path to the manifest. | +| `dist` | no | `dist` | The built headless output, as for `publish-docs`. | +| `strict` | no | `false` | `"true"` also fails on warnings. Errors always fail. | +| `npm-registry`, `npm-token`, `node-mirror`, `node-mirror-token` | no | empty | See [Private networks](private-networks.md). | + +| Output | Description | +|---|---| +| `errors` | Number of error findings. | +| `warnings` | Number of warning findings. | + +## publish-single-page-docs + +Renders Markdown into headless HTML and publishes it. See [Single-page docs](single-page.md). + +| Input | Required | Default | Description | +|---|---|---|---| +| `docs` | yes | — | YAML or JSON list of doc definitions (`md`, `title`, `description`, `slug`, optional `icon`, `tags`). | +| `release-tag` | no | triggering release, else the latest | Release to attach to. | +| `github-token` | no | `{% raw %}${{ github.token }}{% endraw %}` | Needs `contents: write`. | +| `npm-registry`, `npm-token`, `node-mirror`, `node-mirror-token` | no | empty | See [Private networks](private-networks.md). | + +Outputs: `slugs`, `count`, `artifact`, `release-tag`, as for `publish-docs`. + +## Versioning + +Pin to the floating major tag (`@v1`), not a branch. Pushing a `vMAJOR.MINOR.PATCH` +tag moves the major tag to it. A breaking contract change is a new major (`@v2`) with a +`kbVersion` bump, so repos pinned to `@v1` keep publishing against the contract they +were written for. diff --git a/docs/kb/agent-skill.md b/docs/kb/agent-skill.md new file mode 100644 index 0000000..3772706 --- /dev/null +++ b/docs/kb/agent-skill.md @@ -0,0 +1,51 @@ +--- +title: Agent skill +order: 27 +section: Publish Your Docs +--- + +# The `kb-docs-add` agent skill + +An agent skill that onboards a repo's docs for you. It follows the open `SKILL.md` +format, so it works in Claude Code, GitHub Copilot and other readers. + +## Install + +```bash +# interactive +npx skills add AbsaOSS/knowledge-base --skill kb-docs-add + +# non-interactive, project scope, named agents +npx skills add AbsaOSS/knowledge-base --skill kb-docs-add -a claude-code -a github-copilot -y + +# user scope +npx skills add AbsaOSS/knowledge-base --skill kb-docs-add -g +``` + +Or copy the directory by hand: + +| Agent | Project | Personal | +|---|---|---| +| Claude Code | `.claude/skills/kb-docs-add/` | `~/.claude/skills/kb-docs-add/` | +| GitHub Copilot | `.github/skills/kb-docs-add/` | `~/.copilot/skills/kb-docs-add/` | +| Open spec | `.agents/skills/kb-docs-add/` | `~/.agents/skills/kb-docs-add/` | + +Then ask the agent to "add this repo's docs to the knowledge base". + +## Modes + +**Onboard.** It classifies the repo and writes the minimum: + +| It finds | Type | It writes | +|---|---|---| +| Markdown files, no site generator | single-page | one workflow file | +| A docs site (MkDocs, Starlight, Docusaurus, Jekyll…) | packaged | `kb-docs.json`, the smallest change to make the build headless, one workflow file | +| Docs hosted elsewhere | iframe | nothing; it explains the registry entry | + +It pins actions to `@v1`, checks slugs and descriptions against the limits, and tells +you the two steps only you can do: publish a release and register the repo. + +**Audit.** For a repo that is already onboarded, it runs the contract checker from a +scratch clone of the Knowledge Base, fixes each finding by [rule ID](rules.md) at its +source (never in built output, never in a third-party theme), and reports what the +checker cannot see, such as URLs built at runtime. diff --git a/docs/kb/building.md b/docs/kb/building.md new file mode 100644 index 0000000..48694a9 --- /dev/null +++ b/docs/kb/building.md @@ -0,0 +1,87 @@ +--- +title: Building +order: 41 +section: Run a Knowledge Base +--- + +# Building + +Requires **Node.js 24 or newer**. A GitHub fetch needs `GITHUB_TOKEN` (or an +authenticated `gh` CLI). + +```bash +npm install +npm run build:headless # hermetic: builds from the committed registry fixtures +``` + +## Build modes + +| Command | Source of apps | +|---|---| +| `npm run build` | Fetch GitHub Release artifacts | +| `npm run build:headless` | Same, with web-fragment output | +| `npm run build:local` | Build `localPath` entries from local checkouts | +| `npm run build:local:headless` | Local, headless | +| `npm run preview` | Serve the built `dist/` (Astro preview, port 4321) | +| `npm run dev` | Astro dev server; needs artifacts in `apps/` already | +| `npm run dev:fetch` | Fetch artifacts, then start dev | + +| Flag | Environment variable | Effect | +|---|---|---| +| `--headless` | `KB_HEADLESS=true` | Web-fragment output: `data-kb-headless="true"` on ``. Anything else, including unset, is standalone. A per-app `headless` in the registry wins. | +| `--strict` | `KB_STRICT=true` | Production mode; see below. | +| `--local` | — | A `repo` entry without a `localPath` is skipped with a warning. | + +Other environment variables: + +| Variable | Description | +|---|---| +| `GITHUB_TOKEN` | Auth for fetching Release artifacts. | +| `KB_REGISTRY` | Registry file to build from. Default `apps.json`. See [Registry](registry.md). | + +The URL prefix `knowledge-base` is **not** configurable. nginx and the gateway route +patterns hard-code the same string. + +### Strict mode + +`--strict` / `KB_STRICT=true` is for production. It rejects `prebuilt`, `localPath` and +`optional` entries, an empty registry, any entry that yields no apps, and any artifact +with an `error` finding from the [contract checker](rules.md). Warnings never fail a +build. The registry committed in the Knowledge Base repository is a fixture and fails +strict mode by design. + +## Pipeline + +1. Stage each artifact and install its apps into `apps/{slug}/`. Archives are extracted + safely: no traversal, absolute paths or links ([archive rules](manifest.md#the-archive)). +2. Run the contract checks and log findings grouped by rule. +3. Hoist inline ` + + +``` + +`initializeWebFragments()` must run before anything renders a ``. With +piercing on, an earlier element fails with `portalHost is not a function` and falls +back to client rendering. + +## Host router and fragment history + +`src` on `` decides how the fragment's history relates to the host's. + +| | `src` set — **unbound** | no `src` — **bound** | +|---|---|---| +| Fragment history | private stack inside the reframed iframe | the host's `window.history` | +| Address bar | never moves; the host router hears nothing | moves to `/knowledge-base/…` per page; the host router gets a `popstate` | +| Deep links, back/forward | none | work | +| Host route needed | the one route the element sits on | a wildcard covering every fragment page: `/knowledge-base/**` | + +**Unbound** is the safe default when the host router must own the URL. `src` is read once +when the element connects; re-create the element to show a different page. + +**Bound** gives fragment pages real URLs. The host route config must cover the whole +prefix, otherwise the first click lands on the host's fallback route and destroys the +fragment. In Angular: + +```ts +// app.routes.ts +{ path: 'knowledge-base', children: [{ path: '**', component: KnowledgeBasePage }] } + +// main.ts — before bootstrapApplication() +import { initializeWebFragments } from 'web-fragments'; +initializeWebFragments(); +``` + +Guards and resolvers on that route run on every fragment page. Document requests for +`/knowledge-base/…` reach the host, so Angular SSR must render the shell for them; the +wildcard route does that. An Angular host also needs `"outputMode": "server"` and +`"externalDependencies": ["web-fragments/gateway", "web-fragments/gateway/node", "htmlrewriter"]` +in its build target. + +## What to know when you publish docs + +Pages are re-hosted inside the host document, so [contract rules](rules.md) such as +KB-HTML-008 (links to non-HTML files) and KB-JS-001 (page-relative `fetch()` URLs) exist +specifically for embedded use. Navigation between pages is by Astro's client router, with +view transitions. diff --git a/docs/kb/how-it-works.md b/docs/kb/how-it-works.md new file mode 100644 index 0000000..4186054 --- /dev/null +++ b/docs/kb/how-it-works.md @@ -0,0 +1,75 @@ +--- +title: How it works +order: 10 +section: Knowledge Base +--- + +# How the Knowledge Base works + +The Knowledge Base is a build-time aggregator. A **registry** (`apps.json`) lists where +each team's documentation comes from; the build collects it and produces one static +`dist/`. + +``` +Browser ──► /knowledge-base/ landing catalog + /knowledge-base/{slug}/… each documentation app + /__wf/knowledge-base/… assets when embedded as a web fragment + │ + ▼ + nginx (Docker) ─or─ web-fragments gateway (embedded) + │ + ▼ + dist/ (static) +``` + +## The build, step by step + +1. **Obtain** each registered artifact: a GitHub Release asset (`kb-docs.tar.gz`), a + local checkout, or a prebuilt tarball or directory. See [Registry](registry.md). +2. **Read the manifest** (`kb-docs.json`) inside each artifact. It declares one or + more apps with their slug, name, description, icon, tags and pages. See + [The manifest](manifest.md). +3. **Check** every artifact against the [contract rules](rules.md) and log the findings. +4. **Move inline scripts into files** so the site can be served with `script-src 'self'`. +5. **Re-host every page**: rewrite URLs, wrap CSS, wrap the page in the masthead. +6. **Generate the catalog** landing page. + +The output makes no third-party requests at runtime: the Inter typeface is self-hosted +and mermaid is vendored into each single-page artifact. + +## Reading the portal + +- **Masthead** — shown on every page. It carries the branding and a *Library* link + plus the current app's navigation. +- **Catalog** — the landing page at `/knowledge-base/`, one card per app showing its + name, description, icon and tags. Apps registered as an `iframe` entry carry an + **External** badge. +- **App pages** — each app keeps its own sidebar, routing and internal navigation. + Single-page docs render in a centred reading column with no sidebar. +- **Light only** — there is no dark mode and no theme toggle. + +## What happens to your HTML + +Artifacts come from other repositories, so their HTML is treated as untrusted input. +When a page is re-hosted: + +- Every `href`, `src`, `action`, `formaction` and `poster` URL (and `srcset`, `url()` + in styles, and URL-bearing `` content) is rewritten to an absolute + `/knowledge-base/{slug}/…` path. A `` element is removed. +- Each sub-app stylesheet is wrapped in the `kb-app` CSS cascade layer, below the + Knowledge Base's own rules, so a docs theme cannot restyle the masthead or catalog. + `!important` defeats this (KB-CSS-001 in [Contract rules](rules.md)). +- Inline `on*` event handlers are removed, and so are a theme bootstrap script and a + `dark` class on ``/``. +- Inline `