Skip to main content
Version: 2026.11

Docs publishing

The documentation site is a Docusaurus site. The prose lives at the repository root in docs/, next to the code it documents; website/ holds only the site machinery (config, React components, styles), so the Python project root stays free of Node tooling.

How it is published​

Everything is driven by the docs.yaml workflow:

TriggerWhat happens
Pull request touching docs/ or website/Type-check and build, docs/ included — a broken link or a bad MDX page fails the PR. Nothing is published.
Push to main touching website/Build the released versions only and publish them to GitHub Pages. A push that only changes docs/ deploys nothing: visitors would see no difference.
Manual Run workflowSame as a push to main.

Publishing uses the GitHub Actions Pages source, so there is no gh-pages branch and no bot commits in the history. The artifact the build produces is handed straight to actions/deploy-pages.

Reviewing a pull request's docs​

GitHub Pages allows exactly one deployment per repository, so a pull request cannot have its own preview URL without giving up the Actions publishing source and going back to a gh-pages branch. Instead, every PR build attaches the finished site to the workflow run:

  1. Open the PR's Docs check → Summary → Artifacts → docs-site-pr-<number>.
  2. Unpack it over website/build.
  3. cd website && npm run serve.

Use npm run serve rather than a generic static server: the site is published under /ha-power-insight/, and a server rooted elsewhere will 404 every asset.

If preview URLs ever become worth the setup, an external host (Cloudflare Pages, Netlify) is the way to get them — it builds fork PRs in its own sandbox, which is the part that is genuinely awkward to do safely from this repository.

One-time Pages setting

Settings → Pages → Build and deployment → Source: GitHub Actions.

This replaced the old Deploy from a branch → gh-pages setting, which the previous MkDocs + mike setup required.

Working on the docs locally​

cd website
npm install
npm start # dev server with hot reload on http://localhost:3000
# (your edits to docs/ are under /ha-power-insight/next)

Two checks worth running before pushing, because CI runs both:

npm run typecheck # the case-diagram component and the case data
npm run build # catches broken links and broken heading anchors

The build treats broken internal links and broken anchors as errors, not warnings. That is deliberate: the reference-case pages are a specification, and a link that silently rots undermines the point.

Markdown vs MDX​

markdown.format is set to detect:

  • .md is parsed as plain CommonMark. Braces and angle brackets in prose and code spans are left alone, which is what most pages want.
  • .mdx is parsed as MDX and can import and render React components.

Only pages that actually embed a component — the reference-case pages, and the landing page — need to be .mdx. Prefer .md for everything else.

Version numbers​

Power Insight is versioned by the month it is released in: YEAR.MONTH.PATCH, so the first release of September 2026 is 2026.9.0 and a fix to it 2026.9.1. The number lives in two places that must agree — custom_components/power_insight/manifest.json and pyproject.toml — and uv lock then updates the lock file. The docs are cut by YEAR.MONTH (below).

Versioning​

The published site carries the released versions only: the latest at the root, older ones in the navbar's version selector. The unreleased docs are never published.

Where you editWhere it appears
docs/nowhere yet — locally and in pull-request builds under /next (Next (unreleased))
website/versioned_docs/version-2026.7/the site root — what visitors get by default

The deploy build leaves docs/ out by setting DOCS_RELEASED_ONLY=true (see website/docusaurus.config.ts). To check that locally:

cd website
DOCS_RELEASED_ONLY=true npm run build

Docusaurus versions by snapshotting source, not built output. Cutting a version copies the whole of docs/ — markdown, the reference-case JSON, all of it — into website/versioned_docs/, and that copy is then frozen. Day-to-day work happens in docs/; nothing you write there changes what a visitor sees until the next version is cut.

Cutting a version at release time​

The docs-version.yaml workflow does it. When a release is published it reduces the tag to YEAR.MONTH (2026.11.0 → 2026.11), snapshots docs/ at the release commit, checks that the site still builds, and opens a pull request docs: cut docs version 2026.11. Merge that pull request and the site root serves the new version.

ReleaseWhat happens
First release of a month (2026.11.0)A docs version is cut and a pull request opened.
Patch release (2026.11.1)Nothing: 2026.11 already exists.
Pre-releaseNothing: its docs stay under /next until the final release.

Before merging, check whether the release needs anything by hand, such as links into pages that were renamed since the last version (the navbar and footer in website/docusaurus.config.ts, and README.md).

Two one-time settings
  • Settings → Actions → General → Workflow permissions → Allow GitHub Actions to create and approve pull requests, or the workflow cannot open its pull request.
  • A pull request opened by a workflow does not start other workflows, so the Docs check does not run on it by itself. Close and reopen the pull request to run it.

To cut by hand (for a release published before the workflow existed, run it from Actions → Cut docs version → Run workflow with the tag), or locally:

cd website
npm run docusaurus docs:version 2026.8 # YEAR.MONTH of the release

That writes versioned_docs/version-2026.8/, a matching sidebar, and a new entry in versions.json; the newest entry becomes what the root serves. Commit all three.

The reference cases need no step of their own. Their results under docs/spec/cases/ are the engine's, and CI fails any commit whose engine no longer produces them, so cutting from a green commit freezes exactly what this release's engine computes. uv run --group engine python tools/snapshot.py --check confirms it locally.

Old versions stay browsable and are still rebuilt on every deploy, because Docusaurus versions source rather than output — so a theme fix reaches every version at once.

Why reference-case data is passed in as a prop

That last point cuts both ways. docs/ is snapshotted; website/src/ is shared across every version. So the reference-case JSON lives under docs/spec/cases/ to be frozen with the prose around it, while the component that draws it is shared — which is why each page imports its own case data and passes it in rather than letting the component reach for it.

Break that split and an old version's page will quietly start rendering today's numbers, when its whole purpose is to show what the engine did at that version.

Older versions are not kept compatible with the component. If the case JSON format changes, the build shows which old pages broke; remove those pages from the old versions (and their sidebar entries) rather than teaching the component every past format. That is what happened to 2026.7's hand-derived anchor cases, which left a one-paragraph stub at spec/index so the navbar link keeps working.

The MkDocs site was versioned with mike. That history stays on the old gh-pages branch and is no longer updated or served.