lib-layers-new
Pattern of rule lib-layers. Load when creating, renaming or removing a lib — the generator instead of bare nx g, the tag, the alias, the barrel, the README, and how to finish a removal. Moving code be
SKILL.md.claude/skills/lib-layers-new/SKILL.md
GitHub<!-- rt-kit v0.35.0 · patterns/lib-layers-new.md · a97044dda529 · правится надстройкой, не здесь -->
Created by the generator, not by bare
Creating or removing a lib
Pattern of the rule lib-layers. What must be true — the law
docs/constitution/lib-imports.md.
When to use
- A new domain or a new layer of an existing domain is created.
- A lib is renamed.
- A lib is removed.
First — is a lib needed at all
A domain has screens, state and requests. Mechanics shared by several domains is not started as a domain: the layers under it would stay empty forever.
The sign: if there is nothing to fill feature, data-access or api with — these are
utilities, and their place is the lib that already sees them. The frontend always has such a
lib — the family base; the backend — the util layer already listed with every domain.
That is how the list domain lived as nine libs for three files of code: seven libs empty, and
each with its own project.json, vitest.config.mts, barrel, tag and alias.
Created by the generator, not by bare nx g
node tools/generate-domain-lib.mjs
The generator lays out project.json, tsconfig.json, vitest.config.mts and the barrel. Bare
nx g gives a vitest config without passWithNoTests, and a lib that has no tests yet fails
nx run-many -t test with the line "No test files found". The layout check looks at the
presence of the file, not at its content, so it lets such a lib through.
What is added by hand
- The tag in
eslint/boundaries/domains/<family>-<domain>.config.mjs— one per lib, equal to the name and the path. - The alias in
tsconfig.base.json. - The lib's README: what lies in it and who calls it.
Rights to foreign libs are written out as lines with a comment saying why. An import that "just worked" means the tag is not narrowed yet.
Removing and moving a lib
git rm -r libs/<family>/<domain>/<layer>
rm -rf libs/<family>/<domain>/<layer>
git rm -r leaves node_modules/.vite inside the removed directory, and the layout check keeps
seeing it as a domain without layers. Finish with rm -rf.
Then the tag, the alias and the rights lines of everyone who saw the lib are removed.
A move is the same action plus a graph reset. A directory moved by mv is not recounted by
the builder's graph: the project stays in the cache under the old path, and under the new one it
does not exist at all.
mv <old lib path> <new lib path>
npx nx reset
Without the reset the run over all projects stays green and goes over one project fewer: it takes the set from the graph cache, and the dropped project is no longer there. Such a run can be told from a full one only by the number of projects in its output — it does not name the missing one, and the miss lives until the first edit in the dropped lib.
Check
npm run check:layers
The check looks at the layers, the single tag = name = path, the alias, the presence of
project.json, vitest.config.mts and src/index.ts, the empty dependency list of
common/util, the family base boundaries and re-exports. Seconds — run after any creation,
rename or removal.
Common misses
- A lib created for mechanics: the layers are empty and there is nothing to fill them with.
- Bare
nx g— a vitest config withoutpassWithNoTests, and the shared test run goes red. - Removal without
rm -rf— the check sees the ghost of a domain without layers. - A lib nobody imports is checked by nothing.
nx lintandnx testcheck the lib itself, not its contract with the consumer. The first importer is the first check: the models layer is accepted afternx buildand a live run of the scenario, not by a greenlint test. - A lib's own
sourceTagis written as a string literal. The layout check finds the description of a lib by the textsourceTag: '<tag>', not by evaluating the module. A tag taken from a constant passes the lint and is reported as "described in no file". Constants are for the tags inonlyDependOnLibsWithTagsonly.