Archprint

io.github.Tommkruixv0.8.3更新於 Oct 2, 2026

Mine the architecture rules your TypeScript repo already enforces, with the evidence attached.

概覽

AI 產生的概覽

讓助理在寫程式前查詢 TypeScript 專案已遵循的架構規則,並附上證據。

功能
Archprint 讀取 TypeScript 專案的匯入圖,推斷程式碼已遵循的架構規則,並回報有多少檔案符合、哪些檔案違反以及信賴分數。透過 MCP 提供三個唯讀工具:archprint_scan、archprint_recommend 與 archprint_explain,每條規則都以白話說明並附上證據與例外檔案。它也能辨識 Next.js、Nest、SvelteKit、Nuxt、Remix 等技術堆疊,並對 React、Angular、Vue、Svelte 的 UI 元件分類。實際的強制檢查交由 CLI 產生 ESLint 與 dependency-cruiser 規則來完成。
適用情境
當編碼助理應遵循專案既有架構慣例而非自行猜測時適用,例如新增 API 路由之前,或詢問儲存庫已遵循哪些規則時。也適合希望從自身程式碼推斷出有證據支撐的 lint 規則、而非手寫規則的團隊,以及想快速了解陌生 TypeScript 專案結構的人。
執行需求
需要 Node.js 20 或更新版本,以及含有 tsconfig.json 的 TypeScript 專案。透過 npx archprint mcp 以 stdio 在本機執行,也可安裝為開發相依套件。未宣告任何身分驗證、環境變數或標頭。選用的 --http 模式需要網路存取以複製公開儲存庫,並監聽指定的主機與連接埠。
安裝前請注意
MCP 工具是唯讀的,不會寫入儲存庫;真正的強制檢查由 CLI 的 generate 與 wire 指令完成,它們會寫入 .archprint/ 目錄,並在 ESLint 或 dependency-cruiser 設定中加入一行受控引用(eject 可完全還原)。預設的 stdio 伺服器讀取本機檢出,README 表示原始碼不會離開你的機器。選用的 --http 模式會複製並掃描公開的 GitHub、GitLab 或 Bitbucket 網址,預設監聽 0.0.0.0:8848;README 提醒應將其置於身分驗證之後,否則任何人都能消耗你的運算資源。

安裝

在 SourceWeft 中

  1. 開啟 儀表板中的 Archprint,將其新增到工作區。
  2. 為需要使用其工具的對話啟用該服務。

Desktop only,透過 STDIO。 STDIO 服務會啟動本機處理程序,因此需要 SourceWeft 桌面主機。

其他 MCP 客戶端

參照 儲存庫 中的啟動說明。

README

Archprint

[npm version] [CI] [npm downloads] [license] [docs]

Mine the architecture rules your repo already enforces, with the evidence attached.

Try it in your browser, nothing to install · Quick start · Use with AI agents · Docs

What it does, in plain words

Every codebase has unwritten rules. "Pages never talk to the database directly." "Shared code never reaches back into the app." Nobody wrote them down, but the code follows them, until one day someone (or an AI assistant) breaks one without noticing.

Archprint reads a TypeScript project, finds the rules its code already follows, and shows you the proof for each one: how many files follow it, which files break it, and how sure it is. The rules you trust become automatic checks in the tools your team already runs, so a break is caught the next time lint runs (in your editor, a pre-commit hook or CI), not weeks later in review.

Think of it as a building inspector who surveys the house first and writes down how it was actually built, instead of handing you a rulebook from somewhere else.

  • For developers and tech leads: inferred, evidence-backed lint rules for ESLint and dependency-cruiser, generated with init, connected with wire, and removed with eject.
  • For teams using AI coding agents: Claude Code, Cursor and other agents can ask Archprint for the project's rules, with the evidence, before they write code.
  • For anyone evaluating a codebase: a quick, honest picture of how a project is actually structured.

Your CLAUDE.md is guidance. Your lint rules are enforcement. Archprint closes the gap by generating the enforcement from patterns your codebase already demonstrates, so you adopt rules you can trust instead of authoring them by hand.

See it in action

The recordings below use archprint-demo, a small Next.js API whose routes reach the database only through a service layer.

1. Find the rules your code already follows. Each rule comes with its evidence.

[archprint scan listing the rules a Next.js API already follows, with the evidence for each]

2. See why one rule is trusted. The confidence check, step by step.

[archprint explain showing the confidence gate behind AP-001]

3. Turn the rules on, watch a break get caught, and remove it all again. Archprint writes its files, adds one line to your ESLint config, lint flags a route that imports the database directly, and eject restores your project exactly.

[archprint init and wire adding the rules to ESLint, lint catching a route that imports the database, and eject restoring the config exactly]

Try it yourself, nothing to install: open the demo in StackBlitz. The scan runs as soon as it opens, and the demo's README walks through enforcing a rule in ESLint, breaking it, and asking for the rules over MCP.

Use it with AI coding agents

AI coding agents can ask Archprint for a project's rules through MCP, an open standard that lets agents use outside tools. You ask in plain words; the agent calls Archprint on its own and answers with the evidence. Archprint only reports. Enforcement still runs in your linter.

Claude Code calls Archprint by itself when you ask about the architecture:

[Claude Code answering "What architecture rules does this repo already follow?" by calling archprint]

Cursor works the same way. In these recordings Cursor was set to Grok 4.7, not Claude. In the desktop app's chat, its agent called Archprint's scan tool on its own; this screenshot shows the tool result and the answer:

[Cursor's desktop chat, running Grok 4.7, answering from archprint's scan result: the rules and lib/db.ts as the one exception]

In the terminal (cursor-agent), it asks once before running the tool, then answers from it:

[Cursor's terminal agent, running Grok 4.7, approving archprint_scan once and answering with the rules and lib/db.ts as the one exception]

Measured: the same question with and without Archprint

We asked Claude Code (Opus 5.5) "What architecture rules does this repo already follow?" on the demo app (70 files), five runs each way. Median [range]:

Without ArchprintWith Archprint
Tokens read81k [58k to 96k]52k [52k to 52k]
Tokens written1.1k [1.1k to 1.4k]0.6k [0.6k to 0.6k]
Cost per question$0.083 [$0.078 to $0.153]$0.037 [$0.032 to $0.076]
Time17 s [15 to 19]10 s [9 to 31]
Tool calls5 [4 to 10]2 [2 to 2]

What the answers showed:

  • Both found the main rule: routes reach the database only through lib/services/.
  • With Archprint, every run gave the evidence for each rule and named the one file that breaks one (lib/db.ts reads process.env outside the config layer). No run without it noticed that.
  • Without Archprint, Claude also described naming conventions Archprint does not check.

Read these numbers with care: about 50k of the tokens read in both columns are Claude Code's own system prompt, and this is one small repo; larger ones are not measured yet. Method, harness and every answer.

Setup for Claude Desktop, Claude Code, Cursor and other clients is in MCP setup.

Quick start

Requires Node 20 or newer. Run these in a folder with a tsconfig.json. In a monorepo, scan and recommend also accept the root and cover every app, while init and generate work on one app at a time (for example apps/web); at a root with several apps they stop, list the apps, and ask you to rerun with one.

bash
# 1. See the rules your code already follows, with the evidence. Changes nothing.npx archprint scan .
# 2. Set up enforcement for the rules your code already follows cleanly,#    and record what to review or adopt next in .archprint/config.jsonnpx archprint init .
# 3. Connect the generated rules to your ESLint / dependency-cruiser config (one managed line)npx archprint wire
# Then run your linter as usual. To undo everything, exactly:npx archprint eject

To keep it in the project instead of using npx: npm install --save-dev archprint.

More commands for a deliberate, step-by-step setup:

bash
# Inspect the evidence behind one rulearchprint explain AP-002 apps/web
# Write the auto-trusted (mechanical) rules to .archprint/, only for the linters your repo uses.# Structural-inference rules are held for review; add --include-structural to emit them too.archprint generate apps/web
# Confirm the generated rules pass on your repo before wiringarchprint generate apps/web --check
# Generate a single rule by id after reviewing it (including a SUGGEST rule)archprint generate apps/web --rule AP-001
# Recommend a rule set from the evidence and the detected stack (fresh repos too)archprint recommend apps/web
# Upgrading from 0.5.x? Move an older archprint-rules/ setup to the .archprint layoutarchprint migrate

Or build from source:

bash
git clone https://github.com/Tommkruix/archprintcd archprintnpm cinpm run buildnode dist/cli.js scan <path-to-your-app>

How it decides what to trust

Archprint is deliberately cautious: one wrong rule hurts more than no rule. Every candidate rule passes two checks before it is turned on for you.

1. Is there enough evidence? Seeing 5 of 5 files follow a pattern is not proof; 40 of 40 is. Archprint scores each rule with a Wilson score lower bound, a standard statistical measure that combines how often the rule holds with how many files it was checked on. Each rule lands in one of three groups:

  • AUTO (enforceable): the 95% lower bound on conformance is at least 90%, with at most 3 exceptions and a confidently classified role.
  • SUGGEST (provisional): the pattern holds in at least 80% of files and the role is at least 50% certain, but one AUTO condition fails: the confidence floor is under 90% (too few files, or too many that break it), more than 3 files break it, or the role is under 80% certain. Surfaced for review, not auto-generated.
  • REJECT: not enough signal.

2. Could the rule itself be wrong? A rule can pass the numbers and still be wrong if Archprint guessed a folder's purpose incorrectly. So only the mechanical families, which rest on unambiguous signals, are trusted without review: forbidden imports (AP-001, AP-002), circular dependencies, test isolation, import style, console isolation, and public-API barrels. An adversarial correctness audit (three rounds over four real repositories) found zero false positives in these every round. All of them except circular dependencies are written as lint rules; for cycles, Archprint reports the result but does not write a rule yet.

The structural families infer a "layer" or "role" from paths, which can be wrong (layer and role boundaries, UI/data separation, entry purity, server/client, feature-slice and app isolation, env access, workspace package API, stories isolation). Dependency hygiene, whose enforcement can over-flag, and dependency declaration are held back too. All of these are held for your review by default and written as enforcement only with --include-structural, regardless of their statistical score, until they earn the same clean record. Nothing that could be wrong is enforced without you opting in.

Generated rules are green by construction: each one lets through the few known exception files it was inferred from, so adopting it keeps your lint green while new violations are still caught, and a self-consistency check refuses to write a rule whose evidence does not hold together. To run the generated rules against your code before connecting them, use archprint generate --check.

What it can detect

Ships as: Auto = turned on as enforcement (mechanical families). Review = held for your review by default; emit with --include-structural. Report = shown only, never enforced.

Archprint recognizes the stack (Next.js, Nest, SvelteKit, Nuxt, Remix) and classifies UI components across React (.tsx), Angular (.component.ts, .directive.ts), and Vue and Svelte single-file components (it reads the <script> block of .vue/.svelte files), so the component-aware rules apply regardless of framework.

DetectorRule it can inferShips as
Forbidden imports (AP-001, AP-002)AP-001: a request entry (route handler) must not import the DB client. AP-002: a server entry must not import the UI layerAuto
Circular dependenciesThe module graph should stay acyclic (gated on how cycle free it already is); reported, no lint rule written yetReport
Test isolationProduction (non-test) code must not import test or spec filesAuto
Dependency hygieneImport third-party packages by their public entry, not a dependency's src/internal internalsReview
Dependency declarationEvery imported third-party package must be declared in package.json (no phantom/transitive deps)Review
Import stylePrefer workspace aliases over deep relative imports (../../../)Auto
Console isolationLibrary (non-CLI) code must not call console.*Auto
Public API (barrel) boundariesFiles outside a feature or package must import it through its index barrel, not deep import its internalsAuto
Layer boundariesFiles in one layer must not import another, inferred from the dominant dependency directionReview
Role layeringSemantic tiers keep their direction (a REPOSITORY must not import a SERVICE, a SERVICE must not import a CONTROLLER)Review
Entry purityFramework entries (pages, routes, layouts) must not be imported by other first-party codeReview
UI / data separationReusable UI components must not import the DB/data layer directlyReview
Server / client boundaryA Next.js "use client" module must not import a server-only moduleReview
Feature-slice isolationSibling slices under a features/modules/slices/domains container must not import each otherReview
App isolationSibling apps under an apps/services container must not import each other directlyReview
Env accessRead process.env only in the config/env layerReview
Workspace package APIImport a monorepo workspace package by its name, not a deep path into its sourceReview
Stories isolationStorybook .stories files must not be imported by other codeReview
Orphan modulesFiles nothing imports and that are not framework entries (dead code candidates)Report
Transitive reachabilityA layer boundary that a plain import rule passes but that leaks through an intermediary layerReport

recommend (and init) sort every rule family into tiers: rules your code already follows (enforce now), rules your code follows that Archprint reports but does not write yet (circular dependencies today), rules with thin evidence (review and adopt), and rules that comparable repos commonly follow but yours does not yet (adopt from day one). Each recommendation carries the share of comparable repos (your detected stack, else overall) that already enforce that rule, mined from a census of tens of thousands of public TypeScript repositories. So even a fresh repo, with little code to learn from, gets a stack-aware baseline backed by what the ecosystem actually does rather than hand-picked defaults.

What it writes to your project

archprint generate (and init) writes a minimal .archprint/ folder, and only for the linters your repo actually uses. It detects ESLint and dependency-cruiser and emits each rule for a tool you already run, so you are not left with config for a tool you do not have. --emit <eslint|dependency-cruiser|all> forces the format.

  • .archprint/eslint.mjs: one self-contained ESLint flat-config file that inlines every inferred ESLint rule (marker-based forbidden imports, no-restricted-imports import-style boundaries, console isolation) and needs no extra plugins: it adds rules to your existing ESLint setup, which already parses your TypeScript. So you can commit it, publish it, or hand it to another repo and adopt it in one line (import archprint from './.archprint/eslint.mjs'). It self-ignores **/.archprint/**. The forbidden-import rules (AP-) ship as a generated local eslint plugin inside it, so wiring the eslint config enforces them too, no extra install.
  • .archprint/dependency-cruiser.json (when dependency-cruiser is present): one forbidden ruleset with the mechanical boundaries (public-API deep-import, test-isolation); the review-held ones (layer, role-layering, feature-slice, app-isolation, entry-purity, dependency-internals, phantom deps) are added only with --include-structural, after you review them.
  • .archprint/config.json: what is enforced, followed but only reported, held for review, and worth adopting, plus the list of managed outputs eject removes.
  • A managed section in your README.md summarizing what is enforced now, followed but only reported, held for review, and worth adopting (written by init, or generate --readme), plus a managed .prettierignore entry so the generated files stay out of your formatter.

--expand additionally writes the granular artifacts inside .archprint/: the per-family ESLint and dependency-cruiser JSON, per-rule cards (.md) with passing and failing fixtures, the eslint-plugin-boundaries element-types config, ts-arch tests, and the Mermaid and Graphviz DOT layer graph.

Staying in sync, and leaving cleanly. Re-running generate (or init) refreshes .archprint/ and drops any rule the evidence no longer supports, so the output never drifts from the code. wire inserts a single managed reference into each enforcement tool your repo uses (a flat eslint config, a .dependency-cruiser.json), one that survives those regenerations; for a config it cannot safely edit (a JS dependency-cruiser config, say), it prints the exact snippet to paste. eject removes Archprint's files and every wired reference, restoring each config exactly. generate --check runs the generated ESLint rules against your repo and reports whether they pass, so you can confirm before wiring. Upgrading from 0.5.x? archprint migrate moves an older archprint-rules/ setup to this layout and rewires your configs in place.

MCP setup

archprint mcp runs Archprint as an MCP server over stdio, so an agent can ask what architecture rules your repo already follows, with the evidence, before it writes code. It exposes three read-only tools: archprint_scan, archprint_recommend, and archprint_explain. Each rule comes back stated in plain words, with its evidence and the files that break it, and archprint_explain takes any rule label from the scan (for example AP-002 or env-access). Point Claude Desktop, Claude Code, Cursor, or any MCP client at it:

json
{  "mcpServers": {    "archprint": { "command": "npx", "args": ["-y", "archprint", "mcp"] }  }}

Things to ask your agent. You do not name the tools; the agent picks them:

  • "What architecture rules does this repo already follow?"
  • "Which file breaks the env-access rule, and how should I fix it?"
  • "I am adding a new API route. What rules should it follow in this codebase?"
  • "Which rules should we enforce now, and which are worth adopting?"

Your code stays on your machine. This default is a local server: it reads your local checkout, so it is the one to use for private code, and your source never leaves your machine, whichever git host you use.

If the server will not start. If the client says the server failed to start or npx was not found, it cannot see your shell's PATH. Desktop apps opened from the Dock or Start menu do not load it, which is common when Node comes from nvm or Homebrew. A full path to npx alone is not enough, because npx itself needs node on the PATH. Point both at the folder that dirname "$(which node)" prints, for example /opt/homebrew/bin:

json
{  "mcpServers": {    "archprint": {      "command": "/opt/homebrew/bin/npx",      "args": ["-y", "archprint", "mcp"],      "env": { "PATH": "/opt/homebrew/bin:/usr/bin:/bin" }    }  }}

Starting the editor from a terminal also works, because it then inherits your shell's PATH.

Scanning a public repo by URL. archprint mcp --http runs a remote server instead. It clones the repo shallow to a temp dir, runs the same read-only analysis, returns the result, and deletes the clone (only public github.com, gitlab.com, and bitbucket.org URLs; nothing is written or kept). The tools then take a repo URL (and an optional ref). It listens on 0.0.0.0:8848/mcp by default (set --host 127.0.0.1 to keep it to your own machine, or --port/$PORT to change the port) and answers health checks at /health (use this one on Cloud Run, which reserves /healthz) and /healthz. Every request clones and scans, so a server anyone can reach spends compute on anyone's behalf: keep it behind authentication, such as Cloud Run's IAM, unless you accept that cost.

The tools are read-only (they never write to the repo); use the CLI's generate/wire to actually emit and enforce rules.

How it compares

Established TypeScript tools (dependency-cruiser, eslint-plugin-boundaries, Nx, Sheriff, ts-arch) all enforce architecture rules you write by hand. Archprint infers them from the actual import graph and gates each one on statistical evidence before proposing it. It then emits into those tools' formats, so it complements your stack rather than replacing it.

Verified against each tool's documentation (TypeScript ecosystem). The two columns that matter are the ones no other TypeScript tool fills:

ToolEnforces arch rulesAuto-infers from the import graphAttaches statistical evidence
Archprintyesyesyes
dependency-cruiseryesnono
eslint-plugin-boundariesyesnono
@nx/enforce-module-boundariesyesnono
Sheriffyesnono
ts-archyesnono
madge / knipanalysis onlynono

Honest caveat: in other ecosystems, Tach (Python) and ArchLint (Java) do auto-infer module boundaries, so Archprint's specific niche is auto-inference plus statistical evidence gating in the TypeScript ecosystem. Archprint also overlaps in detection with dependency-cruiser (cycles, orphans, reachability) and knip (dead code); rather than compete, it writes the rules it generates in those tools' formats.

Commands

  • archprint init [path]: zero-config setup. Detects the stack, enforces the rules the code already follows, and writes .archprint/ plus a managed README section. Options: --expand, --include-structural, --out <dir>, --fast, --force.
  • archprint scan [path]: reports the rules the repo already follows, with evidence. Changes nothing. --deep resolves through barrels and aliases.
  • archprint explain <id> [path]: shows the gate breakdown for one rule, with a codeframe per exception plus how to fix, when not to use it, and how to enforce it.
  • archprint recommend [path]: recommends a rule set from the repo's evidence and detected stack (works on a fresh repo too), and names the installed tool that will enforce each rule it can write.
  • archprint generate [path]: writes the auto-trusted mechanical rules to .archprint/ for the linters your repo uses; structural rules are held for review. --emit <eslint|dependency-cruiser|all> forces the format, --only <family> and --rules <ids> narrow the output, --check runs the generated rules against your repo, --readme adds the README section, --expand also writes the per-family files, cards, fixtures and graph, and --rule <id> emits one reviewed rule. Also --include-structural, --no-graph, --out <dir>, --fast.
  • archprint wire: references the generated rules from the enforcement tools your repo uses (flat eslint config, .dependency-cruiser.json) through a managed, reversible reference. --out <dir>, --dry-run.
  • archprint eject: removes Archprint's generated files, its config, the managed README section, and any wired references, restoring each config exactly. --out <dir>, --dry-run.
  • archprint migrate (alias upgrade): moves an older archprint-rules/ setup to the .archprint/ layout and rewires your configs in place. --dry-run.
  • archprint mcp: runs Archprint as an MCP server so Claude, Cursor, and other agents can call the read-only scan, recommend, and explain tools. Serves over stdio by default; --http runs a remote server that scans a public repo by URL.

scan --json and recommend --json emit stable, version-keyed JSON for scripting. Exit codes are the contract: 0 on success, 1 on error.

Example on a real repo

A real scan of inbox-zero (apps/web, 2,232 TypeScript files), trimmed:

Scanned 2,232 TypeScript filesWorkspace aliases: 18 resolved
GENERATED RULES  AP-002  no-ui-layer-in-server-entry      confidence 97%          Evidence: 216/217 role files conform (99.5% observed)          Exceptions: 1
LAYER BOUNDARIES (review before enforcing)  utils !-> app  layer boundary   confidence 99%          Evidence: 650/653 utils files conform (99.5%); 451 app file(s) depend on utils  hooks !-> app  layer boundary   confidence 94%          Evidence: 65/65 hooks files conform (100%); 121 app file(s) depend on hooks

AP-002 is a mechanical family, so it auto-generates as enforcement. The layer boundaries are inferred, so they are shown for review, not written as enforcement unless you pass --include-structural. Every number is measured from the import graph, not estimated.

Technical notes

Fast and deep modes. scan defaults to a fast specifier-level pass (no type checker). generate defaults to a deep pass that resolves through barrels and workspace aliases, since generation is the commitment point. Structural analysis (cycles, orphans, reachability, public-API) always uses the fast graph: it is faithful to deep resolution for those, and public-API detection in fact requires it (deep resolution would resolve through a barrel and erase the barrel-versus-deep signal).

Determinism. The same repo at the same version produces the same output. Analysis is pure and sorted; there is no randomness, and the analysis engine is pinned to an exact version.

Status

Published on npm and safe to run on your real repo. Every rule is review-gated by default, reversible in one command (archprint eject), and deterministic, and generated rules are green by construction on the code they were inferred from.

  • Validated at scale: scan and recommend ran over a corpus of 92,861 public TypeScript repositories (61,690 apps) with zero crashes; 91 repos (0.1%) could not be fetched or timed out. The full init/wire/eject round-trip ran clean on a 2,000-repo stratified sample.
  • Production-ready today: scan and recommend, and auto-enforcement of the mechanical families, with a self-consistency check at generate time, an init scaffolder for fresh repos, and framework coverage across React, Angular, Vue, and Svelte. The engine (twenty detectors, the confidence gate, and emitters for a self-contained ESLint file, dependency-cruiser, ts-arch, and the layer graph) is in place and tested.
  • Still ahead: hardening the structural families toward auto-enforcement (a real per-file role-confidence measure, layer cohesion, role-classifier ordering).
  • Versioning is still 0.x, so the CLI surface and rule format can refine between minor versions. That is a maturing surface, not experimental analysis. The compact .archprint/ layout arrived in 0.6.0, and archprint migrate upgrades an older setup in place.

A companion benchmark, AgentRuleBench, measures the guidance-vs-enforcement question directly (a pre-registered, honest null result on the boundary it tested).

Words used here

  • Import: a line in one file that uses code from another. Archprint's rules are about which files may import which.
  • Lint rule / linter: an automatic check that runs on your code (ESLint is the most common one) and flags problems as you write.
  • AUTO / SUGGEST / REJECT: how confident Archprint is in a rule; see How it decides what to trust.
  • Mechanical / structural families: rules based on unambiguous signals (trusted without review) versus rules that depend on guessing a folder's role (held for your review).
  • MCP: an open standard that lets AI agents use outside tools such as Archprint.

Documentation

Full docs live at tommkruix.github.io/archprint and in docs/: getting started, concepts (the confidence gate, mechanical vs. structural, fast vs. deep, the generate/wire/eject lifecycle), and the rule-family reference (what each rule detects, how it ships, and when not to use it).

Contributing

See CONTRIBUTING.md. The project lints, type checks, and tests itself; every change keeps coverage above its thresholds and ships a changeset.

License

MIT

來源:README.md,提交 e408683

工具

0
工具後設資料尚未被收錄。

版本歷史

1
  1. v0.8.3最新Oct 2, 2026