Contributing to the docs
Maintainer overview
Section titled “Maintainer overview”Keep each change in the documentation surface that owns it. There are three classes.
Agent-facing contract
Section titled “Agent-facing contract”MCP tool schemas and descriptions, refusal and guidance strings, agent and skill definitions, CLI help, and live rules tell agents what the system does. Update these surfaces with the code change in the same story. When a value is enumerated in code, treat that enum as the source of truth and update every surface that repeats it.
Generated reference
Section titled “Generated reference”Pages under docs/src/content/docs/reference/ are generated from plugin metadata, skill frontmatter, hook registries, bin file inventories, and marketplace metadata. Change the source input or docs/scripts/generate-reference.mjs, then regenerate with npm run generate. Never hand-edit a generated page.
Human prose
Section titled “Human prose”Setup, observability, architecture, contributing, and release pages are maintained by hand. Update the affected page in the same story when a user or maintainer workflow changes. If the prose needs a larger follow-up, file a linked docs-writing ticket before the story ships.
Keep user actions in the getting started guide or the relevant plugin guide. Keep implementation boundaries and release mechanics on the maintainer pages.
Build the site
Section titled “Build the site”From docs/, install dependencies and build:
npm cinpm run buildThe build regenerates the reference pages before Astro checks and builds the site. Run npm run screenshots when a committed documentation screenshot needs updating. The screenshot pipeline uses synthetic fixtures and isolated local services.
For plugin-specific contracts, read that plugin’s README.md before changing a guide. Source changes and documentation changes should land together when the user-visible workflow changes.
CRAP delta gate
Section titled “CRAP delta gate”Run the Sidequest CRAP measurement from plugins/sidequest:
npm run quality:crapIt runs the test suite of every plugin the diff touches (Sidequest test:full, a plugin’s own test script, or node --test over its test/*.test.js) under V8 coverage, so a Sidequest-only change does not pay for the gateway suite. The summary line names the suites it ran, and --coverage <dir> skips the run and reuses a coverage directory you captured yourself. It scores changed JavaScript and TypeScript throughout the repository, including test callbacks, and compares changed functions with the merge base against develop (or main in a checkout without develop). Pass --base <ref> to compare against something else. Existing debt does not fail an unchanged branch.
The shared Quality Gate core captures precise V8 coverage and executed script bytes in one inspector session. Child processes need the inherited core preload and QUALITY_GATE_V8_CAPTURE. Raw V8 reports are UNVERIFIED. Direct sources must match the executed bytes; transformed sources need a single-source compiler map naming the scored file with matching embedded source content and exact body ranges. The installed tsx omits source content and Sidequest builds omit maps, so those captures remain UNVERIFIED. Generated export getters cannot cover their unexecuted production functions. Use node ../../scripts/quality/crap.mjs --all when you need every score rather than the functions at or above the threshold.
Every changed function lands in one of three sections: NEW (no partner at the base), MODIFIED-RAISED (its complexity rose since the base) or LEGACY-UNCHANGED (its complexity held or fell). Only the first two must score below 6; a LEGACY row is printed with its number as information and never fails, so a small edit inside a big legacy function is not a refactor demand. Moving the new branches into a new helper that scores below 6 is the way to land a change that would otherwise raise a legacy function’s complexity.
The gate compares complexity at a fixed coverage, so it catches a function that gained branches and not one that only lost test coverage. That second arm needs coverage from the base tree as well, which is a separate measurement pass.
See release process for publishing changes.