Installation
Install
Section titled “Install”Two installs, for the two ways the same policy is evaluated:
pnpm add -D @goodbones/oxlint # the plugin: editor feedback and `oxlint` in CIpnpm add -D @goodbones/cli # the `architecture` CLI: check, baseline, coverage, and the graph familyBoth pull in @goodbones/core (the manifest schema and the evaluators),
@goodbones/typescript (the TypeScript language pack) and @goodbones/campaigns (the
campaigns family, which the core does not
own) transitively; you never install those directly until a second language pack exists. The pack parses files with
oxc-parser and resolves modules with
unrs-resolver; each ships its own native
binary as a platform package, and there is nothing else to configure at the OS level.
Wire it into oxlint
Section titled “Wire it into oxlint”oxlint loads JS plugins with a bare dynamic import(), so the plugin is registered by
specifier and its five rules are enabled by id:
{ "jsPlugins": [{ "name": "architecture", "specifier": "@goodbones/oxlint" }], "rules": { "architecture/imports": "error", "architecture/exports": "error", "architecture/members": "error", "architecture/structure": "error", "architecture/surface": "error", "import/no-cycle": "error" }}import/no-cycle is oxlint’s own, and it owns the one check a per-file rule cannot make.
The plugin reads the manifest from the repository root at module load — architecture.yaml
by name, or one of the other forms — which
is also when it runs the probe check. A
malformed manifest or a vacuous rule fails there, loudly, rather than lowering to a policy
that matches nothing.
A first manifest
Section titled “A first manifest”architecture init writes a starter: one open root, the adoption ceilings at zero, and a
comment per section naming the page that explains it.
pnpm exec architecture initOr start from the tree instead of a blank page: architecture infer describes what the
repository does today as a manifest check already accepts, and the work is deleting from it.
See Starting from the tree.
Or write one by hand. This is a complete policy:
# yaml-language-server: $schema=https://dataquail.github.io/goodbones/schema/architecture.schema.jsonresolve: scopes: - files: "" language: typescript options: { tsconfig: tsconfig.json } unresolved: erroraliases: "@": srctree: "@/domain/": message: "domain/ is the model. It reaches nothing but itself." imports: message: "domain/ may not reach the framework." reset: true external: [effect] allow: ["@/domain/**"] children: "*.ts": {}It says four things:
src/domain/admits.tsfiles and nothing else.- Files there may import from
src/domain/, and fromeffect. - Anything else — another folder, another package — is refused with the message given.
- Every import specifier in the repository must resolve to something.
Verify it fires
Section titled “Verify it fires”Before trusting a new rule, plant the violation it exists to catch and watch it fail:
echo 'import "express";' > src/domain/probe.tspnpm oxlint srcrm src/domain/probe.tsThis is the habit the whole package is built around, and it is automated two ways: the
plugin’s own load-time probe check, and the
architecture CLI.
The editor reads it too
Section titled “The editor reads it too”The first line of the manifest names its JSON Schema. Any editor with a YAML language server — VS Code’s YAML extension, for one — completes every key from it and flags a misspelled one as you type, before the loader runs. The schema is generated from the codec that decodes the manifest, so what the editor accepts is what the loader accepts.
What the editor misses, the loader reports with a file, line and column, and every issue at once rather than the first. A repository that would rather write the manifest as JavaScript can — see Using a JavaScript manifest — and gives up both of those to do so.
Build before you lint
Section titled “Build before you lint”If you consume the plugin from a workspace package rather than from npm, the compiled
output must exist before oxlint runs — oxlint imports JavaScript, and a stale build
enforces a stale policy while still linting green. Make the build a prelint step rather
than a convention.