Category files under development/ replace the decision prose that was scattered through README.md and CONTRIBUTING.md. Each decision is a block with Decision (YYYY-MM) / Why / Rejected / Known issue; the new library.md records the public API contract and its limitations. AGENTS.md and backlog.tasks now point at the new home.
3.7 KiB
Development documentation
These files explain why this project works the way it does: the decisions behind it, what was rejected, and the shortcomings and known issues we carry. They are written for maintainers and contributors of the project itself.
The actionable rules — how to set up, run, test, and submit — live in CONTRIBUTING.md. This folder is the "why" behind those rules: read the relevant file here before changing an area, and update it when a decision changes, rather than leaving an obsolete reason behind. A rule and its reason drift apart when they live in one place and are maintained in two; keeping the rule in CONTRIBUTING.md and the reason here keeps each single-homed.
User-facing documentation lives in README.md. A docs/ folder
is deliberately not used yet: the convention is that docs/ is the future
user documentation site, and deploying that site is out of scope. When it
exists, these files stay here — they are not user documentation.
Layout
One file per category:
| File | Covers |
|---|---|
| library.md | Public API design, the type-level contract, and its limitations |
| workflow.md | Branching and merging, script prefixes, feedback tiers, commit messages |
| tooling.md | Toolchain choices and configuration, editor setup |
| testing.md | Test strategy and type-driven development |
| ci.md | CI pipeline, runner image, coverage serving |
| publishing.md | Release and npm publishing |
A category that outgrows one file becomes a folder with an index, but we start with one file per category because each area is small enough to hold in mind at once. When a category splits, the links in CONTRIBUTING.md and README.md keep pointing at the category, not at a single decision.
Decision blocks
Every non-obvious choice is recorded as a block inside the relevant category file, using this shape:
## Runner image
#### Decision (2026-09)
Bake Node into the CI job image at the setup-node tool-cache layout instead
of downloading per job.
#### Why
- ...
#### Rejected
- Gitea Pages / per-job download
- force-pull
#### Known issue
- a Dockerfile-only change re-pushed under an unchanged tag is invisible to the runner
- recover with `docker rmi <image>`
- The date is the month the decision was made, not the date the file was last edited. It is the anchor a reader uses to tell "this is current" from "this was current once".
Rejectedis what makes the record worth keeping: it stops the project from re-litigating the same alternatives. An emptyRejectedusually means the alternatives were never written down.Known issueis where shortcomings live. If a caveat is not tied to one decision, put it under a## Known issuessection at the end of the file.- A superseded decision is replaced in place, not archived in a second file — the file always describes the current world, and git history is the archive.
Adding to these docs
- Pick the category file for the area you are changing:
workflow,tooling,testing,ci, orpublishing. - Add or update a decision block. Keep the existing text unless the decision actually changed.
- If the change alters an actionable rule, update CONTRIBUTING.md in the same commit and cross-link the two.