archprint
0.14.0
Minor Changes
Undeclared (phantom) dependencies and the server/client boundary can now be enforced with plain ESLint, like layer boundaries. When your repo does not use dependency-cruiser,
generate --include-structuralwrites them into.archprint/eslint.mjsasarchprint/no-phantom-dependenciesandarchprint/no-server-only-in-client, with no extra plugin, and they pass on the code they were generated from. The phantom-dependency rule reads yourpackage.jsoneach time ESLint starts, so declaring a package is enough; no regenerate. Both rules are now adopted, whichever tool enforces them:archprint checkreports a new break andarchprint allowaccepts one.Circular dependencies are now enforced. When your code has no cycle (and enough files to say so),
generateandinitadopt the ruleno-cycles, without--include-structural, andarchprint checkreports each import that closes a new cycle in a pull request; to accept a cycle, allow every file in it. There is no lint rule for cycles, because finding one needs the whole import graph. The phantom-dependency and server/client rules still need--include-structural. Older archprint versions do not recognize these adopted rules, so update archprint in CI (for example the GitHub Action'sarchprint-version) before you regenerate.Fixes: the server/client rule written for dependency-cruiser flagged every server module that correctly imports
server-only, and missed the client component importing it; it now covers exactly the client components and server-only modules the scan found. A module that only mentions "server-only" in a comment or a string is no longer treated as server-only. A "use client" directive after a byte-order mark or a shebang line is recognized.#subpath imports andscheme:specifiers (such asbun:test) are no longer reported as undeclared packages.Package internals and entry purity can now be enforced with plain ESLint too. When your repo does not use dependency-cruiser,
generate --include-structuralwritesarchprint/no-dependency-internals(importing a package'ssrcorinternalfolders) andarchprint/no-import-framework-entry(importing a page, layout or route handler from other code) into.archprint/eslint.mjs. Both pass on the code they were generated from and are adopted, soarchprint checkreports a new break andarchprint allowaccepts one. The entry rule recognizes pages and routes by their path, so new routes are covered without regenerating.Fixes: the entry-purity rule written for dependency-cruiser flagged a page importing another page, test files, and the imports that already existed when it was generated; it now exempts all three. Package-internals evidence no longer counts
#subpath imports orscheme:specifiers as packages.
0.13.1
Patch Changes
- The README now walks through adopting the layer boundaries you agree with: read them with
scan, write the ones you chose withgenerate --include-structural --rules, and reference them withwire.
0.13.0
Minor Changes
Layer boundaries can now be enforced with plain ESLint. When your repo does not use dependency-cruiser,
generate --include-structuralwrites each layer boundary into.archprint/eslint.mjsas its own rule, such asarchprint/no-lib-to-app, with no extra plugin, andrecommendnames ESLint as its enforcer. The rule checks.tsand.tsxfiles and reads imports the way the scan counted them: relative paths and tsconfig aliases, side-effect and dynamic imports, but not type-only imports, test files, or the folders the scan skips (build, dot-folders, and the ones your.gitignoreexcluded when you generated). It exempts the files that already broke the boundary, so it passes on the code it was generated from. Layer rules are now adopted:archprint checkreports a new break, andarchprint allowaccepts one, whether ESLint or dependency-cruiser enforces it. Older archprint versions do not recognize adopted layer rules, so update archprint in CI (for example the GitHub Action'sarchprint-version) before you generate with--include-structural.--rulesnow selects any generated rule, not onlyAP-rules: anAP-id or the name ESLint prints for it, a family rule such asimport-styleortest-isolation, or a layer rule by its id (no-lib-to-app) or by the labelscanprints (lib !-> app). It keeps only the rules it names, so--rules AP-002no longer also writes the other families. A name that matches no rule the run would generate is an error that lists the ones it would, and nothing is changed.
Patch Changes
Layer boundaries written for dependency-cruiser no longer fail on their first run. A rule such as
libmust not importappused to flag the few existing exceptions it was generated with, test files, and type-only imports, none of which the scan counts. It also matched every folder with the layer's name at any depth, so alib/folder inside a route likeapp/(dashboard)/lib/counted as theliblayer. The rule now matches only the folders the layer was found in, and in a monorepo it matches paths the way dependency-cruiser reports them from the folder where you ran archprint.Layer boundaries are now found from imports as written in every scan mode, which is how dependency-cruiser, ESLint and ts-arch read them. A full scan used to follow re-exporting index files and could find a boundary its own rule then contradicted. Exceptions to other dependency-cruiser rules also match on a folder boundary now, so an exception for
lib/legacy.tsno longer exemptsmylib/legacy.ts.
0.12.4
Patch Changes
Three fixes found by reviewing archprint's output on popular open-source repos before writing about them:
- Circular dependencies are now shown as a real import loop, for example
a.ts -> b.ts -> a.ts, plus how many other files are in the same cycle. Before, the files of a cycle were listed in alphabetical order with arrows between them, which read like an import chain that did not exist. - The rule that request handlers must not import the database client directly now recognises Supabase (
@supabase/supabase-js,@supabase/ssr,@supabase/postgrest-jsand the older auth helpers) and your own modules that create a Supabase client, so an app that reaches its database through Supabase is no longer told its handlers avoid the database. Database client modules created with a type argument, such asnew Kysely<DB>(...)orcreateServerClient<Database>(...), are recognised too. - The UI and data rule now says what it measures: components that never import the data layer directly. It no longer claims they go "through services", which it does not check.
- Circular dependencies are now shown as a real import loop, for example
0.12.3
Patch Changes
Files in folders whose names glob patterns read as syntax, such as Next.js
[id],[...slug],(group)and@slotroute folders, now work everywhere.archprint allowaccepts them, andarchprint checkno longer stops with "must be a file path relative to the app" afterwards. The ESLint rules exempt exactly that file: before, a path likeapp/[id]/page.tsxcould exempt the wrong file (app/i/page.tsx) and keep flagging the right one. An allowed exception must still name one file;*and?are refused.Two related fixes: an exception to an
AP-rule no longer also exempts a file in another folder whose path merely ends the same way, and the review-held env-access and workspace-package rules now exempt their existing exceptions when the ESLint config sits at the repository root of a monorepo.
0.12.2
Patch Changes
archprint ejectnow restoresREADME.md,.prettierignoreand.npmignorebyte for byte. Before, a file without a final newline, with several trailing newlines, or with mixed line endings came back slightly different after archprint added and then removed its section.
0.12.1
Patch Changes
- The rule that keeps request handlers away from the database client (AP-001) no longer adds a request handler that creates its own client to the list of modules it forbids importing. Such a handler is still reported as breaking the rule; it just no longer changes the rule's definition, so
archprint checkdoes not show AP-001 as changed when a pull request adds or removes one.
0.12.0
Minor Changes
.archprint/is back to two files for a single linter:config.jsonandeslint.mjs. The adopted rules and the exceptions you allow witharchprint allownow live inconfig.json(itsrulesandallowedlists) instead ofrules.jsonandallow.json. Setups from 0.9.0 to 0.11.x keep working:checkstill readsrules.jsonandallow.json, including on a base branch that has them, and the nextarchprint generatemoves both intoconfig.jsonand deletes them.checkalso warns when a pull request removes the rules fromconfig.json.
0.11.0
Minor Changes
New
archprint allow <rule> <file> --reason "..."records a justified exception to an adopted rule in.archprint/allow.json.archprint check(and the GitHub Action and the MCParchprint_checktool) no longer counts an allowed exception as a new violation, lists every exception added in the pull request with its reason, and points out exceptions the code no longer needs. The nextarchprint generatestops ESLint flagging the allowed file for that rule. Wheninitorgeneratere-infers the rules, allowed exceptions are left out of each rule's evidence, so allowing one justified break never drops the rule it breaks (and an allowance never promotes a rule that was not adopted). An exception without a reason is rejected, andallowrefuses a rule that does not report the file.--removetakes an exception back out, andejectremoves the list.ESLint also gets more precise for the rules that share
no-restricted-imports(import style, test isolation): a file excepted for one of them is still checked by the others. Before, an exception for one of them exempted the file from all of them.File exceptions in the generated ESLint config, including the ones grandfathered at adoption, now also match when your ESLint config sits at the root of a monorepo: each one is written with the app's path in front as well as relative to the app, so it applies to that app only.
0.10.5
Patch Changes
archprint now deletes and writes only where it should. Before,
generate,init,ejectandmigrateremoved every path listed in.archprint/config.json, the outputs manifest, or an oldarchprint.json'srulesDir, so an edited file could make them delete folders elsewhere in the repo or outside it.- Only paths inside archprint's own folder are deleted, with symlinks resolved first. The old
archprint-rules/folder is cleared file by file from its manifest and removed only when empty, so files you put there stay. - If
.archprint(or the old rules folder) is a symbolic link, archprint refuses to write or delete through it. - Every file archprint writes stays inside its folder: a file there that is a symbolic link is replaced with a real file, never written through, and a linked subfolder pointing elsewhere is refused.
- The README,
.prettierignore,.npmignoreand the linter configs archprint edits are left alone when they link outside the repository. archprint eject --outmust name a folder inside the repository, not the repository itself, and an--outinside the repository that a symbolic link redirects elsewhere is refused.
- Only paths inside archprint's own folder are deleted, with symlinks resolved first. The old
0.10.4
Patch Changes
- The "Adopted rules" section in your README now says what
archprint wireandarchprint ejectdo, instead of saying the rules run "oncearchprint wireconnects them", which read as "not yet" after you had already wired them.
0.10.3
Patch Changes
- The README section
archprint initwrites no longer says the rules are already wired into your linter. It lists them under "Adopted rules" and says they run in your linter oncearchprint wireconnects them, which is true before and after you runwire.
0.10.2
Patch Changes
- The MCP
archprint_scanandarchprint_explainresults now say, for each rule, whether archprint enforces it, holds it for review, or only reports it (adoption:enforce,revieworreport-only). Before, they gave only the gate status (AUTO or SUGGEST), and agents described rules archprint holds for review as enforced.
0.10.1
Patch Changes
archprint checknow reports when a pull request removes the adopted rules. If the change deletes.archprint/rules.jsonorconfig.json(or the whole.archprint/folder) that the base commit has, it warns and lists every rule that stops being checked, instead of saying it did not run. It still does not fail the job; the docs show how to require a code owner's review for such a change.
0.10.0
Minor Changes
The MCP server has a fourth read-only tool,
archprint_check. An agent can ask which of the repo's adopted rules its current change breaks, uncommitted edits included, and fix them before it finishes. It returns the same report asarchprint check --format json, without the version field. That JSON now also names theappthe file paths are relative to, which matters in a monorepo.archprint_explainnow returns how to fix a violation and when not to adopt the rule for the database and UI rules, and its description says what it adds overarchprint_scan. The recommendation for those rules is labelled "Forbidden imports (database client or UI in request handlers)".archprint checkno longer uses a git worktree for the base commit: it copies the base commit's files to a temporary folder with git's own plumbing, so it runs none of the repository's git hooks and writes nothing inside.git. A branch or commit name starting with-is refused.
0.9.0
Minor Changes
Add
archprint check, which reports only the violations a change introduces, compared with a base branch or commit, for the rules your team adopted withinitorgenerate. It works in any CI. On GitHub,--format githubshows each finding inline on the pull request, with its evidence, plus a step summary that also counts the violations the change fixed. It warns by default;--fail-on newfails the job so you can make it a required status check.--format jsonand exit codes (0ok,1new violations,2the CI setup is wrong) cover other CI systems.initandgeneratenow also write.archprint/rules.json, the exact definition of each adopted mechanical rule, whichcheckuses so it never re-infers a rule. If you set up archprint with 0.8.x or earlier, runarchprint generateonce; until thencheckreports that it did not run.
Patch Changes
- The same repository now gives the same output on every machine. archprint reads files in name order instead of the order the filesystem returns them, which differs between macOS and Linux, so an example exception or a generated fixture no longer changes between a laptop and CI.
generate --expandnow writes each forbidden-import rule's files from that rule. Before, the database rule (AP-001) got the UI rule's ESLint message, rule card text and fixtures, so its failing fixture imported a UI component that AP-001 never flags. Each rule's message now states the rule, its card lists what it forbids, and its failing fixture imports something the rule really reports: one of the repo's own exceptions when there is one, otherwise the database wrapper or component folder archprint found.- The local MCP server now says plainly when it is given a repository URL instead of a directory, and points to
archprint mcp --httpfor scanning a public repository by URL. Before, it reported a missingtsconfig.jsonunder a path built from the URL. It also reads afile://URL as the local directory it names, and ignores spaces around a path. - Plainer wording. The database and UI rules (AP-001, AP-002) now say "request handler" instead of "request-entry" or "server-entry" file, in scan output, ESLint messages, rule cards and fix guidance.
scanprints each of these rules as a sentence followed by "N of M files it applies to follow it".
0.8.3
Patch Changes
- The MCP server is ready for MCP directories. Each tool now has a human-readable title and is marked read-only and non-destructive, so clients can show it as safe to run (the remote
--httptools are also marked as reaching the internet). The package declares its MCP Registry name, and every release publishes to the official MCP Registry automatically.archprint scannow labels each rule group the same wayinitandrecommenddo: dependency hygiene and dependency declaration read "review before enforcing", and circular dependencies read "report only". The README lists example prompts to ask your agent.
0.8.2
Patch Changes
archprint initandarchprint recommendno longer list circular dependencies under "Enforcing now". Archprint does not write a lint rule for cycles, so nothing was enforcing them. They now appear under a new "Report only" group, which is also recorded asreportOnlyin.archprint/config.json, inrecommend --json, in the MCParchprint_recommendresult, and in the README sectioninitwrites.- The README is reorganised so anyone can follow it: a plain-words explanation of what Archprint does and who it is for, the demo recordings and a "try it in your browser" link up front, a section on using it with AI coding agents (with the measured comparison), a short quick start, and a plain explanation of how it decides which rules to trust before the reference material. It also corrects the list of rule families that turn on automatically: dependency declaration is held for review, as the detector table and
initalready said. Circular dependencies are now described as reported rather than enforced, since no lint rule is written for them yet, and the README states precisely what makes generated rules green on your code and whatgenerate --checkadds.
0.8.1
Patch Changes
archprint ejectnow restores an ESLint config exactly when its array starts on the same line as its first entry (for exampleexport default [{ ignores: ['dist/'] }, ...]).wireused to break that line to insert its reference, andejectleft the line break behind.wirenow inserts the reference inline on that line, andejectremoves exactly what it added. Configs with a multi-line array are unchanged.- Scanning now skips the same files git does for
.gitignorepatterns where a wildcard has to reach past a partial match, such asf*o/*/*matchingfoo/b/c. Before, a few such patterns failed to match and those files were scanned. Scan output is unchanged on the large repositories we checked. - The README and docs show three short recordings (scan, explain, and asking Claude Code in plain words) and a measured comparison of the same question in Claude Code with and without archprint on the demo app, with the method, harness and every answer published alongside.
0.8.0
Minor Changes
- The MCP tools and
scan --jsonnow say what each rule means and which files break it. Every rule carries a plain-languagestatement(the same wordingarchprint scanprints) and anexceptionslist naming the files that break it (up to 10;violatingFilesstill has the full count).archprint_explainnow explains any rule from the scan by its label, such asenv-accessorlib !-> app, not only theAP-rules, and returns every exception file. An agent can now answer "what rules does this repo follow?" accurately from a single scan, instead of guessing what a family name means.
Patch Changes
archprint initnow ends with the right next step. It names the config file it actually wrote (.archprint/config.json) and tells you to runarchprint wireto reference the generated rules from your linter config, instead of describing an older file layout.- The README and docs now open with a short recording of
archprint scanandarchprint explainon a real Next.js API, and link to a demo you can try in the browser on StackBlitz with nothing to install. The MCP section shows an MCP client callingarchprint_scan.
0.7.1
Patch Changes
The remote MCP server now answers health checks at
/healthas well as/healthz. Cloud Run reserves/healthzand answers it before the request reaches the server, so use/healththere.The docs now say plainly which server to use for what: the local stdio server (
archprint mcp) is the one for private code, because it reads your local checkout and your source never leaves your machine; the remote HTTP server scans public repositories by URL, and since every request clones and scans, a hosted instance belongs behind authentication.Refresh the README so it describes the current release: the sample CLI output no longer shows an old version banner, and the wording about the
.archprint/layout is stated as when it arrived rather than as the latest release, so it stays accurate in future versions.
0.7.0
Minor Changes
- Add
archprint mcp --http, a remote MCP server that scans a public repository by URL. It clones the repo shallow to a temp directory (public github.com, gitlab.com, or bitbucket.org only), runs the same read-onlyscan,recommend, andexplainanalysis, returns the result, and deletes the clone, so an agent can inspect a repo's architecture without anything being installed locally. The tools take arepoURL and an optionalref. The server is stateless and binds0.0.0.0:8848/mcpby default (--host/--port, or$PORT); put an authenticating, rate-limited proxy in front before exposing it publicly. - Add
archprint mcp, which runs archprint as an MCP server over stdio so Claude, Cursor, and other agents can inspect the architecture rules a repo already follows before they write code. It exposes three read-only tools,archprint_scan(the rules the repo follows, with evidence),archprint_recommend(what to enforce now, review, or adopt), andarchprint_explain(the confidence-gate evidence behind one rule id), and never writes to the repo. Point any MCP client atnpx -y archprint mcp.
Patch Changes
- Make deep scans dramatically faster on real repositories by not loading
node_modulesinto the analysis. Deep resolution now resolves first-party imports (includingbaseUrlandpaths) and workspace packages, but skips pulling external dependencies into the TypeScript program, and caches module resolution. A single large app drops from about 5 minutes to under 20 seconds and a 14-app monorepo from over 30 minutes to about 2 minutes, with byte-identical results, sogenerateis now practical on large codebases. - Scanning now skips everything git ignores, not just the root
.gitignore: nested.gitignorefiles in subdirectories and repo-local.git/info/excludeare honored too. This keeps generated, vendored, and locally excluded directories out of the analysis, so a scan of a monorepo root is both faster and matches what you would expect git to track. Machine-global excludes are intentionally not read, so the same repository scans identically across machines.
0.6.0
Minor Changes
Archprint now writes a minimal
.archprint/directory instead of a folder of per-family files.generateandinitemit one self-contained rules file per linter you actually use (.archprint/eslint.mjsand/or.archprint/dependency-cruiser.json) plus a.archprint/config.jsonthat records what is enforced and what Archprint manages. The plain-language summary that used to beADOPTION.mdis now a managed section in yourREADME.md, and a managed.prettierignoreentry keeps the generated files out of your formatter.--expandwrites the granular artifacts (per-family configs, per-rule cards and fixtures, the eslint-plugin, ts-arch tests, and the layer graph) inside.archprint/for anyone who wants to inspect or vendor individual rules.- New
archprint migrate(aliasupgrade) moves an olderarchprint-rules/setup to the new layout and rewrites the reference in your linter config in place, writing the new files before removing the old ones so the config never points at a deleted file.generateandinitstop and point you to it if they detect the old layout. wireimports the single rules file with an ESM-safe relative specifier, andejectremoves the files, the config, the managed README section, and every wired reference.
0.5.0
Minor Changes
- archprint now generates rules for the enforcers your repo actually uses. It detects whether you have ESLint or dependency-cruiser and emits each rule for a tool you already run, instead of writing dependency-cruiser configs you have no way to enforce. On an ESLint-only repo it expresses test isolation as an ESLint
no-restricted-importsrule; dependency-cruiser configs are only written when dependency-cruiser is present.archprint recommendnow names, per rule, the installed tool that will enforce it (or what you would need to install). archprint generate --readmewrites anADOPTION.mdin the output directory summarizing what is enforced now, held for review, and worth adopting, each with the tool that enforces it. It is tracked in the manifest, soarchprint ejectremoves it too.archprint generategains two output controls:--emit <eslint|dependency-cruiser|all>forces the output format regardless of the tooling archprint detects, and--no-graphskips the layer dependency graph (Mermaid and Graphviz).archprint generategains finer output control:--only <family>emits a single rule family,--rules <ids>emits only the named forbidden-import rule ids, and--checkruns the generated ESLint rules against your repo and reports whether they pass, so you can confirm before wiring.
Patch Changes
Generated rules are now green-by-construction: a rule archprint says you "already follow" passes clean when you wire it, instead of flagging code that was there all along. Emitted rules are scoped to exactly the files the detector measured (test files and cli/config files are excluded, matching what the analysis skips) and exempt the specific exceptions the confidence gate accepted. This covers the console, environment-access, deep-relative-import, workspace-package, test-isolation, phantom-dependency, and dependency-internals rules across both ESLint and dependency-cruiser. The ESLint import rules (deep-relative, workspace, test) are also emitted as a single merged block so they no longer override one another in flat config.
More fixes so an "enforce now" rule cannot flag code it was mined from:
- The dependency-cruiser test-isolation, phantom-deps, no-internals, and public-API deep-import rules now exclude test files (
__tests__,e2e,cypress,.test/.spec/e2esuffixes), matching what the analysis excludes. - The public-API deep-import rule also exempts the tolerated deep importers the confidence gate already accepted, so an "enforce now" rule cannot flag code it was mined from.
- no-internals matches only the internals directories the analysis measures (
src,internal,internals), not a package's normaldist/libentry. - no-internals and phantom-deps are now held for review (emitted with
--include-structural) rather than auto-enforced, because their rules match resolved paths or dependency types and can flag a package whose public entry resolves throughsrc/, or a workspace package with no localpackage.jsonentry. - Phantom (undeclared) dependency checking is emitted only for dependency-cruiser; the ESLint form is dropped because it flags test files and first-party path aliases the analysis excludes.
wireonly splices into a recognized flat-config array or factory (defineConfig,tseslint.config); an unrecognized call such asexport default loadConfig()bails instead of reporting a false success.generate --checkreports files it could not parse instead of calling them clean.
- The dependency-cruiser test-isolation, phantom-deps, no-internals, and public-API deep-import rules now exclude test files (
wireparses your ESLint config with the TypeScript AST, so it reliably edits the commonconst config = [...]; export default config;shape and is not fooled byexport defaultappearing inside a string or comment.- archprint no longer writes rule files for a tool your repo does not use; pass
--emit allto force every format. - The wired ESLint config and the shareable preset ignore archprint's own generated files, so linting your repo never flags them.
archprint generate --checkreports only violations of the rules archprint generated.
archprint wirenow edits the common config shape where the ESLint flat config is bound to a name and exported by reference (const config = [...]; export default config;, the default for Next.js and many TypeScript projects) instead of falling back to a manual edit. It resolves the exported name to its declaration, including adefineConfig([...])wrapper, andarchprint ejectreverses it as before.
0.4.1
Patch Changes
- Scan repositories that declare a TypeScript project but have few source files. Archprint now recognizes
tsconfig.base.json(not onlytsconfig.json) and always scans a repo that has a tsconfig, instead of failing with a "no scannable app directory" error on TypeScript-light repos.
0.4.0
Minor Changes
- Monorepo-friendly
recommend,generate, andinit.recommendnow discovers every app directory under a monorepo root and reports per app (its--jsonoutput gains anappsarray, matchingscan).generateandinitautomatically use the single app directory they find under a root, or, when a monorepo has several, list the directories to point at instead of failing with a generic message.
Patch Changes
- More accurate layer-boundary inference. A layer boundary is now trusted for auto-enforcement only when the evidence for its direction is strong (many imports consistently flow the dominant way). Boundaries inferred from just a handful of cross-layer imports, where the direction could be noise, are held for review instead, which removes spurious layer rules while keeping the well-evidenced ones.
- More accurate role-layering inference. A role boundary (for example, a repository must not import a service) is now trusted for auto-enforcement only when both the file roles are confidently classified and the direction is strongly evidenced. Boundaries whose direction rests on just a couple of imports, where it could be a coin flip, are held for review instead.
0.3.0
Minor Changes
- Add Angular support: Archprint now detects Angular in your stack and recognizes Angular components, so the component-aware rules (such as UI/data separation) apply to Angular projects.
- Generate a shareable ESLint preset.
archprint generatenow writes a single, self-containedeslint-preset.archprint.mjsthat inlines the inferred rules and needs only eslint, so you can commit it, publish it, or hand it to another repository and adopt the rules in one line:import archprint from './eslint-preset.archprint.mjs'. - Scan Vue and Svelte single-file components. Archprint now reads the
<script>block of.vueand.sveltefiles, treats them as UI components, and follows their imports, so the component-aware rules (such as UI/data separation) apply to Vue and Svelte projects. - Emit architecture boundary tests for ts-arch. Alongside the ESLint and dependency-cruiser outputs, Archprint now writes a ts-arch test file for the inferred first-party boundaries (layer, role, and UI/data), so you can run them inside your existing Vitest or Jest suite.
0.2.0
First public release. Archprint mines the architecture rules your repository already follows from its real import graph, gates each on statistical evidence, and emits them into the tools you already use.
Highlights
- Evidence-gated rule inference across 20 families, including forbidden imports (DB client / UI in a server entry), import cycles, test isolation, console isolation, import style, public-API barrels, dependency hygiene and declaration, layer and role boundaries, UI/data separation, entry purity, server/client boundaries, feature-slice and app isolation, env access, workspace-package API, and stories isolation. Mechanical families auto-enforce; inferred structural families are held for review.
- CLI:
init(zero-config setup),scan(the rules your code already follows, with the evidence),recommend(adoption tiers backed by a census of tens of thousands of public repositories, works on a fresh repo too),explain(per-rule evidence, codeframes, and how-to-fix),generate(write the rule configs), andwire/eject(reference the generated rules from your config, reversibly). - Emits into your stack: ESLint, including a generated plugin for the forbidden-import rules, and dependency-cruiser, wired in with a single managed reference that survives regeneration.
- Clean lifecycle: re-running refreshes the output and drops any rule the evidence no longer supports; the few known exceptions are grandfathered so adoption is green on day one.
- Framework awareness: Next.js, Nest, SvelteKit, Nuxt, Remix, and React / Vue / Svelte stacks.
- Machine-readable output (
scan --json,recommend --json) and stable exit codes for CI.