Skip to content

Contributing

Contributions are welcome. This page explains how to work on the plugin itself: how to get the repository running, which checks to run before you open a pull request, and where the parts live.

This is a pnpm workspace. One directory holds everything published to npm. The rest proves that the plugin works and keeps it working.

  • Directorypackages/
    • Directorystarlight-pydocs/ the published package, the only thing shipped to npm
      • Directorylib/ framework-free code (no Astro imports), unit-tested here
      • Directorycomponents/ the .astro components that render the API pages
      • Directorytests/ the Vitest suite
  • Directorydocs/ this Starlight site, which uses the plugin and runs the Playwright suite
  • Directoryexamples/
    • Directoryvanilla/ a plain Astro site that shows the plugin works without Starlight
  • Directoryfixtures/ Python packages plus their checked-in griffe dump JSON
  • prek.toml the formatting, linting and type-checking hooks

The package has no build step. It ships its .ts and .astro source, and the host Astro project transpiles it. The dev server picks up edits inside packages/starlight-pydocs directly.

You need Node 22.12 or later, and pnpm 10.33 (the version pinned in packageManager). You must use pnpm: the workspace links starlight-pydocs into the docs site and the example with workspace:*, and npm and yarn resolve this differently or not at all. Install pnpm with npm install -g pnpm. Node v25 removed Corepack, so corepack enable no longer works on a current Node.

You do not need Python to run the unit tests. The griffe dump JSON files under fixtures/ are checked in, so the test suite never shells out. You do need uv for two tasks: regenerating those dumps, and building this site, because the build extracts demopkg and numpkg from their Python sources. If your PATH has neither uvx nor a python that can import griffe, extraction fails and the build fails with it. Two package entries read a pre-generated dump instead, so they need no Python at all: api/sphpkg and the second demopkg entry at 1x/api/demopkg.

  1. Clone the repository and install the workspace:

    Terminal window
    git clone https://github.com/ewels/starlight-pydocs
    cd starlight-pydocs
    pnpm install
  2. Install prek. It is a separate tool, not an npm dependency. Let it write the git pre-commit hook, so every commit runs prettier, eslint and the type-checker:

    Terminal window
    pipx install prek
    prek install

    Skip this step if you would rather run the checks by hand.

  3. Start this documentation site:

    pnpm dev

    Open http://localhost:4321/starlight-pydocs. The site is served under its base path, so plain localhost:4321 returns a 404. The first run extracts the fixture packages with griffe and caches the result in node_modules/.astro. Later starts are quick.

Task Command
Unit tests (Vitest) pnpm test
One test file pnpm --filter starlight-pydocs exec vitest run tests/model.test.ts
Watch · coverage pnpm --filter starlight-pydocs test:watch · … test:coverage
End-to-end tests (Playwright) pnpm test:e2e
Type-check pnpm typecheck
Lint · format pnpm lint · pnpm format
Everything, as CI runs it prek run --all-files
Regenerate the fixture dumps pnpm gen:dumps
Regenerate the inventory pnpm gen:inventory

pnpm test:e2e builds and previews both sites (this one on port 4321 under base /starlight-pydocs, the vanilla example on 4322), then runs the Playwright suite against them. Every assertion runs against real generated output. It needs a browser binary the first time:

pnpm --filter starlight-pydocs-docs exec playwright install chromium

pnpm typecheck runs the typecheck script of every workspace package. It runs tsc --noEmit over the framework-free code in packages/starlight-pydocs/lib, then astro check in this site and in the vanilla example. Those astro check runs type-check the .astro components, not the package’s own tsc script, because Astro compiles them where it consumes them.

Prettier does not format .mdx files. It reflows the Python signatures and directive examples in these guides in ways that break them. Format MDX by hand. Starlight also does not support custom heading IDs, so a heading takes whatever slug its text produces.

fixtures/demopkg, fixtures/numpkg and fixtures/sphpkg are Python packages with a wide API surface: three docstring styles, inheritance, overloads, __all__, pydantic models and deprecations. Each has a checked-in griffe dump JSON beside it. The tests and this site read that JSON, not the Python source.

Editing the Python source alone changes nothing. Regenerate the dumps and commit them in the same commit:

Terminal window
pnpm gen:dumps # needs uv on PATH; rewrites fixtures/*/dump.json
pnpm gen:inventory # only when the fixture Sphinx inventory needs new names

A guarded test regenerates the dumps live when uv is available and compares them against the committed ones. CI has uv installed, so this test catches any drift between the committed dumps and the fixture sources.

ARCHITECTURE.md records every architecture decision, the alternatives rejected and the griffe behaviour notes. CLAUDE.md records the working conventions. Before you change the package, know these two rules:

  • lib/ never imports astro or @astrojs/starlight, and components never import @astrojs/starlight. Starlight glue lives only in index.ts, libs/starlight.ts, middleware.ts and routes/starlight.astro. Everything else must work in a plain Astro site.
  • The package registers no remark or rehype plugin. At astro:config:done, it renders docstring prose through the host project’s configured markdown processor into a sidecar JSON. The components then consume that pre-rendered HTML.

Notable changes go under the Unreleased heading at the top of CHANGELOG.md, in the same pull request as the change. The Changelog page is generated from that file, so there is nothing to keep in sync by hand.

To cut a release:

  1. Move the Unreleased entries into a new ## **Version X.Y.Z** (YYYY-MM-DD) section. Bump version in packages/starlight-pydocs/package.json to match.

  2. Commit and push to main.

  3. Publish a GitHub release with a tag matching the version, for example v1.0.0.

Publishing the release triggers the release workflow. It publishes to npm through trusted publishing over OIDC, so there is no token to manage. It checks that the release tag matches the package version first. A mismatch fails the run instead of shipping the wrong version.

The first publish is the exception. You can only configure npm trusted publishing on a package that already exists, so the first release goes out by hand: run npm login, then pnpm release. Afterwards, add the GitHub repository as a trusted publisher in the package settings on npmjs.com. Every later release then publishes itself.