Context
Every member extends shared presets for TypeScript, oxlint, vitest and tsdown (0001), 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 acspell.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
- Exactly five presets. They are
@stackra/typescript-config,@stackra/oxlint-config,@stackra/vitest-config,@stackra/tsdown-configand@stackra/commitlint-config. - Role-named exports. A JavaScript preset exports its configurations as
<role>Presetnames, such aslibraryPresetorservicePreset, 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>). - Published to npm. The five packages are free packages. They publish to npmjs with provenance, as 0177 sets for every free package.
- Consumed through a catalog. A member pins a preset as
catalog:stackra, through thestackracatalog inpnpm-workspace.yaml. A project outside this repository declares the same catalog in its own workspace file. Versions are exact (0001). - Spell checking is enforced. cspell checks the staged
md,mdx,ts,tsx,cssandyamlfiles in lefthook, and the Quality Gate checks them in CI. It is a catalog devDependency. Its dictionary is British English withenas the fallback, because the repository’s prose is British.cspell.config.yamlsetslanguage: entoday; this decision moves it toen-GBwith theenfallback (language: en-GB,en). Its word list stays incspell.config.yaml. The Quality Gate is the gate; the lefthook job gives early warning, as the lefthook configuration already states for its other jobs. - Class semantics in the TypeScript presets. The presets set
useDefineForClassFields: trueexplicitly, so class fields behave the same in tsc, tsgo, oxc and esbuild and no longer depend ontarget.noImplicitOverrideandexactOptionalPropertyTypesstay on. A member that authors kinds never turns onisolatedDeclarations, because a called kind base (extends Action({ ... })) is an expression in anextendsclause, which isolated declarations refuse; its declarations come from tsc or tsgo, which is tsdown’s default path (0294 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 cover.
Enforcement
Todaybase.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 (the preset layout and the catalogs), 0126 (thetooling member shape),
0129 (the house lint rules in @stackra/oxlint-config),
0294 (the kind bases that decision 6 serves),
0177 (free packages on npmjs) and
0196 (repository config is YAML). Sources: the programming-model v3 wave of 2026-10-22, Linear STA-334.