> ## Documentation Index
> Fetch the complete documentation index at: https://docs.stackra.figentra.com/llms.txt
> Use this file to discover all available pages before exploring further.

# 0300 — Five published tooling presets, and spell checking that the gate enforces

> Accepted · 2026-10-22

## Context

Every member extends shared presets for TypeScript, oxlint, vitest and tsdown ([0001](/adr/0001-monorepo-layout.md)), and commitlint
checks commit messages. All five presets are private workspace packages, and their exports do not share one naming pattern
(some export a named preset, some a default export, some a set of named configs). No project outside this repository can use
them, so a project that wants the same checks copies them, and the copies drift.

Spell checking has a `cspell.config.yaml` that the editor reads. No lefthook job and no step of the Quality Gate runs it, so a
misspelling in a pull request passes the gate.

## Decision

1. **Exactly five presets.** They are `@stackra/typescript-config`, `@stackra/oxlint-config`, `@stackra/vitest-config`,
   `@stackra/tsdown-config` and `@stackra/commitlint-config`.
2. **Role-named exports.** A JavaScript preset exports its configurations as `<role>Preset` names, such as `libraryPreset` or
   `servicePreset`, so a consumer picks the role by name. This covers the vitest, tsdown and commitlint presets. The
   TypeScript presets are JSON files and the oxlint presets are JSONC files, so they export no names and keep their
   subpath names (`@stackra/typescript-config/<role>`, `@stackra/oxlint-config/<role>`).
3. **Published to npm.** The five packages are free packages. They publish to npmjs with provenance, as
   [0177](/adr/0177-package-distribution-npmjs-and-keygen.md) sets for every free package.
4. **Consumed through a catalog.** A member pins a preset as `catalog:stackra`, through the `stackra` catalog in
   `pnpm-workspace.yaml`. A project outside this repository declares the same catalog in its own workspace file. Versions
   are exact ([0001](/adr/0001-monorepo-layout.md)).
5. **Spell checking is enforced.** cspell checks the staged `md`, `mdx`, `ts`, `tsx`, `css` and `yaml` files in lefthook, and the
   Quality Gate checks them in CI. It is a catalog devDependency. Its dictionary is British English with `en` as the fallback,
   because the repository's prose is British. `cspell.config.yaml` sets `language: en` today; this decision moves it to
   `en-GB` with the `en` fallback (`language: en-GB,en`). Its word list stays in `cspell.config.yaml`. The Quality Gate is the gate; the
   lefthook job gives early warning, as the lefthook configuration already states for its other jobs.
6. **Class semantics in the TypeScript presets.** The presets set `useDefineForClassFields: true` explicitly, so class
   fields behave the same in tsc, tsgo, oxc and esbuild and no longer depend on `target`. `noImplicitOverride` and
   `exactOptionalPropertyTypes` stay on. A member that authors kinds never turns on `isolatedDeclarations`, because a
   called kind base (`extends Action({ ... })`) is an expression in an `extends` clause, which isolated declarations
   refuse; its declarations come from tsc or tsgo, which is tsdown's default path
   ([0294](/adr/0294-programming-model-v3-grammar-folders-identities-and-naming.md) decision 25).

## Consequences

* A project outside this repository gets the same lint, format, test and commit checks as the workspace, from npm.
* A preset changes in one catalog entry, and every member picks it up through its pin.
* A spelling error in a checked file fails the Quality Gate, so a new word goes into the word list.
* Publishing five packages adds a release step, which the release checks of [0177](/adr/0177-package-distribution-npmjs-and-keygen.md)
  cover.

## Enforcement

Today `base.json` sets `noImplicitOverride` and `exactOptionalPropertyTypes`, and no preset sets `isolatedDeclarations`;
`useDefineForClassFields` is true only because the target is ES2022. The `encore.json` preset, for the Encore
application, turns `noImplicitOverride` and `exactOptionalPropertyTypes` off because generated Encore code trips them.

planned — `useDefineForClassFields: true` written in `base.json`; `language: en-GB,en` in `cspell.config.yaml`, which
sets `language: en` today; a validator check that the workspace has exactly these
five presets, and that each JavaScript preset exports its `<role>Preset` names;
the release workflow publishes the five with provenance; a cspell job in `lefthook.yml` and a cspell step in the Quality Gate
(`.github/workflows/ci.yml`) on the file types above. Nothing of this is in place yet: today the presets are private and cspell
runs only in the editor. Linear: STA-343.

## Alternatives

* Private copies per project, as today: not chosen. The copies drift.
* One merged config package: not chosen. Each preset matches one tool, and a merged package would couple them.
* Spell checking in the editor only: not chosen. A misspelling then passes the gate.
* Remove cspell: not chosen. The word list and the British dictionary keep prose consistent.

## Supersedes and sources

Supersedes: none. Related: [0001](/adr/0001-monorepo-layout.md) (the preset layout and the catalogs),
[0126](/adr/0126-member-shapes-and-scaffold-templates.md) (the `tooling` member shape),
[0129](/adr/0129-house-lint-plugin-and-coding-standard.md) (the house lint rules in `@stackra/oxlint-config`),
[0294](/adr/0294-programming-model-v3-grammar-folders-identities-and-naming.md) (the kind bases that decision 6 serves),
[0177](/adr/0177-package-distribution-npmjs-and-keygen.md) (free packages on npmjs) and
[0196](/adr/0196-repository-config-is-yaml-wherever-the-reader-supports-it.md) (repository config is YAML). Sources: the programming-model v3 wave of 2026-10-22, Linear STA-334.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.