slopbrick 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,902 @@
1
+ # slopbrick
2
+
3
+ > **The AI-coding-agent drift detector.** Stops the `zustand + redux in the same project`, the three-modal-systems, the off-scale `p-[13px]`, the hardcoded `sk-...` keys, and the `expect(x).toBeDefined()` tests that no one wrote and no one will run. Run `npx slopbrick` and get a single Repository Coherence score (0–100) with per-rule precision/recall so you know which findings to fix and which to ignore. Add the MCP server and your AI agent reads your existing patterns before it writes new ones.
4
+
5
+ **The problem.** AI coding assistants write logic well, but they drift. Every project ends up with three button variants, a hardcoded API key, inline styles next to Tailwind utilities, and a test file full of `expect(x).toBeDefined()`. The drift isn't the agent's fault — it's that the agent doesn't know your conventions. Existing linters catch syntax; nothing catches "you just invented a fourth modal system when this repo already has three."
6
+
7
+ **What this does.** `slopbrick` extracts the canonical patterns from your codebase (state lib, form lib, modal system, API client, data-fetching), enforces a declared Constitution at PR time, and exposes the pattern inventory to AI agents via MCP (`slop_suggest`) so they reuse what's there instead of inventing new patterns. The headline Repository Coherence score (0–100) is a proof that the Constitution is being followed — but the actual moat is the Constitution + Pattern Inventory itself, not the number.
8
+
9
+ ## What an AI agent gets from `slop_suggest` (the primary entry point)
10
+
11
+ The MCP tool `slop_suggest` returns, in one call:
12
+
13
+ - **Existing patterns** — the canonical modal, button, API client, state library, data-fetching library the project already uses.
14
+ - **Do-not-create list** — explicit `constitution.forbidden` packages + canonical patterns not to duplicate.
15
+ - **Top issues by rule** — what to fix first in the changed files.
16
+ - **Hot files by issue count** — where the slop is concentrated.
17
+ - **Composite Repository Health** — the headline 0-100 score.
18
+
19
+ > **Call this BEFORE writing new code so the agent reuses existing patterns instead of duplicating them.**
20
+
21
+ `src/mcp/tools.ts:69-81`. The MCP server is one command: `slopbrick mcp`.
22
+
23
+ ## Headline 5-bucket score (compressed from 13 subscores)
24
+
25
+ The full diagnostic surface is 13 subscores. The user-facing surface is 5 buckets:
26
+
27
+ | Bucket | What it measures | One-line question | v4.1 calibration |
28
+ |--------|------------------|-------------------|------------------|
29
+ | **Architecture Consistency** | Cross-file pattern duplication + token usage + component reuse | "Are components and patterns consistent?" | 8 USEFUL rules, top signal: Pattern Fragmentation |
30
+ | **AI Slop Signal** | Ghost defensive code, debug logs, unused state, missing auth, hardcoded secrets | "Does this look like AI wrote it?" | 18 USEFUL rules with measured P/R/FPR |
31
+ | **Security** | Hardcoded secrets, dangerous CORS, unsafe HTML, SQL concat, missing auth | "Are there security holes?" | 4 USEFUL, 3 INVERTED |
32
+ | **Delivery Quality** | Test quality, business-logic coherence, docs freshness | "Can the team ship safely?" | 4 PASS, 3 INVERTED |
33
+ | **Codebase Health** | DB schema, design-token drift, product consistency | "Will this codebase hold up at scale?" | 5 INVERTED/DORMANT — calibration pending |
34
+
35
+ `Repository Health` (the composite) = `0.25 × Architecture + 0.30 × AI Slop + 0.25 × Security + 0.10 × Delivery + 0.10 × Codebase`.
36
+
37
+ The 13-subscore diagnostic surface remains available behind `slopbrick scan --format json` and `--format detailed` for the calibration / power-user audience.
38
+
39
+ ## Why this works (calibration evidence, v4.1)
40
+
41
+ The rules are calibrated against a balanced 1:1 corpus:
42
+
43
+ - **95,467 human-written frontend files** — 39 production repos (mui 16k, supabase 6.8k, antd 5.5k, storybook 3.5k, react-spectrum 3.3k, refine 6.3k, appsmith 5.5k, heroui 2.1k, …) + 54,980 from `ai-slop-baseline`.
44
+ - **76,981 AI-generated frontend files** — 50 existing repos + **100 NEW shallow-cloned vibe-coded repos** (Claude Code, Cursor, Lovable, Bolt, gpt-pilot, v0, BloopAI, tldraw) in `corpus-expansion/positive/vibe-coded/`.
45
+
46
+ The form engineers actually trust, per-rule (full table in [`docs/research/v4-per-rule-pr-fpr.md`](./docs/research/v4-per-rule-pr-fpr.md)):
47
+
48
+ > `security/missing-auth-check` fires on **0.63% of AI files** and **0.04% of human files**. When it fires, **92% of the time the file is AI**.
49
+
50
+ Top 5 AI signals (v4.1 P/R/FPR):
51
+
52
+ | Rule | Precision | Lift | Verdict |
53
+ |------|----------:|-----:|---------|
54
+ | `logic/ghost-defensive` (dead `if (x) return` guards) | 94.74% | 22.5× | USEFUL |
55
+ | `security/missing-auth-check` (auth bypass) | 92.47% | 15.3× | USEFUL |
56
+ | `logic/math-console-log-storm` (debug logs everywhere) | 89.84% | 11.0× | USEFUL |
57
+ | `logic/zombie-state` (unused `useState`) | 83.33% | 6.2× | USEFUL |
58
+ | `test/duplicate-setup` (`beforeEach` copy-paste) | 70.97% | 3.1× | USEFUL |
59
+
60
+ The 18 USEFUL rules have **per-file P/R/FPR thresholds** in `tests/integration/calibration-expanded.test.ts` that fail CI when the signal drifts. See [`docs/research/calibration-report-2026.md`](./docs/research/calibration-report-2026.md) for the full calibration trajectory (v1 ratio → v3 ratio → v4 ratio → **v4.1 P/R/FPR**).
61
+
62
+ ## For humans
63
+
64
+ - `slopbrick scan` in CI gates PRs on `slopIndex` and the Constitution.
65
+ - `slopbrick pr` scores the PR itself, weighted by severity.
66
+ - `slopbrick architecture` is the headline consistency number.
67
+ - `slopbrick security` is the categorical security gate.
68
+ - `slopbrick test` / `business-logic` / `patterns` / `db` are specialised subcommands.
69
+ - `slopbrick drift` exits 1 on any Constitution violation.
70
+ - `slopbrick --format json` exposes the 13-subscore diagnostic surface + per-rule P/R/FPR for the calibration audience.
71
+
72
+ ## For AI agents
73
+
74
+ Install the MCP server (`@slopbrick/mcp`), then call `slop_suggest` before writing new code. The agent never has to guess what's already in the codebase.
75
+
76
+ ## What it does not do
77
+
78
+ It does **not** detect whether a human or AI wrote the code. It surfaces patterns that AI generates disproportionately (4 modal systems, exposed `NEXT_PUBLIC_OPENAI_API_KEY`, `if (NODE_ENV === 'development') return true`), and enforces the constitution the project has declared.
79
+
80
+ ---
81
+
82
+ ## 13-score diagnostic surface (for the calibration audience)
83
+
84
+ The headline 5-bucket score is a compression of 13 subscores. The full surface is what `slopbrick scan --format json` returns, and what the [`tests/integration/calibration-expanded.test.ts`](./tests/integration/calibration-expanded.test.ts) test guards against drift.
85
+
86
+ **Tier 1 — Deterministic (Constitution enforcement):**
87
+
88
+ | Score | Shape | Use it for |
89
+ |-------|-------|------------|
90
+ | **Slop Index** | 0–100 | Frontend lint quality (composite) |
91
+ | **Architecture Consistency** | 0–100 | Cross-file pattern duplication |
92
+ | **AI Security Risk** | `low` / `medium` / `high` / `critical` | AI-induced security failures |
93
+ | **Constitution drift** | pass / fail | Imports that violate the declared stack |
94
+ | **Design-token drift** | inline violations | Spacing/radius off declared scales |
95
+ | **Pattern Fragmentation** | 0–100 | How many competing patterns per category (modal / auth / state / api / …) — *the input to `slop_suggest`'s `doNotCreate` list* |
96
+ | **PR Slop Score** | integer | One number per PR, weighted by severity |
97
+
98
+ **Tier 2 — Heuristic (specialised subcommands):**
99
+
100
+ | Score | Shape | Use it for |
101
+ |-------|-------|------------|
102
+ | **Test Quality** | 0–100 | AI test smells |
103
+ | **Business Logic Coherence** | 0–100 | Pricing precision, validation completeness |
104
+ | **Documentation Freshness** | 0–100 | Stale READMEs, drift between docs and code |
105
+ | **Database Health** | 0–100 | Missing indexes, N+1, soft-delete inconsistencies |
106
+
107
+ **Tier 3 — Derived (dashboards):**
108
+
109
+ | Score | Shape | Use it for |
110
+ |-------|-------|------------|
111
+ | **Repository Health** | 0–100 | Weighted average of the 5 buckets |
112
+ | **AI Maintenance Cost** | $/month | $ cost of fixing the issues, given velocity |
113
+ | **AI Debt band** | A / B / C / D / F | Letter grade from the above two |
114
+
115
+ ---
116
+
117
+ ## What's new in 0.7.0
118
+
119
+ > **Repository Constitution Engine for AI Coding Agents.** The moat is the Constitution. Everything else is a score that proves it's being followed.
120
+
121
+ 0.7.0 is the **Constitution-first release** — three new specialised subcommands (`test`, `business-logic`, `patterns`), a one-number-per-PR score (`pr`), the `forbidden` deny-list for explicit "never use this", and the rename from `conventions` to `constitution` everywhere.
122
+
123
+ The 0.6.x series built the foundation. The 0.7.x series turns the Constitution from a config field into a working contract — AI agents that read it via MCP (`slop_suggest`) and humans that enforce it via PR gates.
124
+
125
+ **What landed in 0.7.0:**
126
+
127
+ - `slopbrick pr` — one weighted number per PR, gates on `--threshold`
128
+ - `slopbrick test` — Test Quality score (0–100) + 4 `test/*` rules
129
+ - `slopbrick business-logic` — Business Logic Coherence score (0–100) + 8 rules
130
+ - `slopbrick patterns` — Pattern Fragmentation score (0–100), 8 categories
131
+ - `constitution.forbidden` — explicit deny-list (e.g. `['moment', 'lodash']`)
132
+ - `conventions` → `constitution` rename across config, types, MCP tool names, report columns
133
+
134
+ ### 0.6.0 – 0.6.4 recap (the foundation)
135
+
136
+ 0.6.0 was the engine re-architecture. The 0.6.1 – 0.6.4 patch series shifts the framing from "AI slop detector" to **repository coherence engine** — the same scanner, now with three new scores, MCP tools so AI agents check before they PR, and eight security rules for AI-induced failures.
137
+
138
+ Five orthogonal scores, all in `slopbrick scan`:
139
+
140
+ | Score | Shape | Use it for |
141
+ |-------|-------|------------|
142
+ | **Slop Index** | 0–100 | Frontend lint quality |
143
+ | **Architecture Consistency** | 0–100 | Cross-file pattern duplication *(0.6.3)* |
144
+ | **AI Security Risk** | `low` / `medium` / `high` / `critical` | AI-induced security failures *(0.6.4)* |
145
+ | **Constitution drift** | pass / fail | Imports that violate declared stack *(0.6.2)* |
146
+ | **Design-token drift** | inline violations | Spacing/radius off declared scales *(0.6.3)* |
147
+
148
+ The slop detector is still here — but the bigger lever is *coherence*: one modal system, one state library, one fetch lib, a declared constitution that the AI agent checks before PR.
149
+
150
+ ### What landed in 0.6.1 – 0.6.4
151
+
152
+ **0.6.4 — AI Security Risk (new score) + 8 Tier-1/Tier-2 security rules**
153
+
154
+ NOT a security scanner — Semgrep / GHAS / CodeQL / Gitleaks own that. This is a **categorical** score (`low | medium | high | critical`) for security failures that AI generates disproportionately. Independent of `slopIndex` — security failures do not get diluted into "good slop score" territory.
155
+
156
+ - `security/hardcoded-secret` — provider prefixes (`sk-`, `sk-ant-`, `AKIA`, `ghp_`, `sk_live_`, `AIza`, `xox[abprs]-`) + sensitive-name literals.
157
+ - `security/exposed-env-var` — `NEXT_PUBLIC_*` / `VITE_*` / etc. with secret names — inlined into every browser build.
158
+ - `security/dangerous-cors` — wildcard `Access-Control-Allow-Origin: *` + `cors({ origin: '*' })` + reflective `cors({ origin: true })`.
159
+ - `security/missing-auth-check` — Next.js `route.ts` / `pages/api` / Express handlers with no auth primitive.
160
+ - `security/unsafe-html-render` — `dangerouslySetInnerHTML` fed a non-literal value.
161
+ - `security/fail-open-auth` — `if (NODE_ENV === 'development') return true/next()`.
162
+ - `security/sql-construction` — template-literal / concat SQL queries (use parameterized queries).
163
+ - `security/public-admin-route` — routes under `/admin`, `/internal`, `/debug`, `/staff`, `/manage`, `/private`, etc. without an additional role check.
164
+
165
+ New `slopbrick security [--format pretty|json] [--strict]` subcommand. `--strict` exits 1 on high/critical (CI gate).
166
+
167
+ **0.6.3 — Architecture Consistency Score (the headline metric) + design-token enforcement**
168
+
169
+ One 0–100 number that reflects how consistent a repository's patterns are. Subtracts from 100 for each pattern-duplication finding: `-12` per extra modal system, `-8` per extra button variant, `-10` per extra API client module, `-15` per extra state library (highest), `-10` per extra data-fetching library, `-1` per 5 off-scale spacing values, `-1` per 5 off-scale radius values. A project with 1 modal, 1 button, 1 api client, 1 state lib, 1 fetch lib lands at 100. A project with 3 modal systems + 4 button variants + 2 state libs lands at 37.
170
+
171
+ Two new rules turn design tokens from docs into enforceable contracts:
172
+ - `visual/spacing-scale-violation` — flags `p-[13px]`, `gap-[1.75rem]` etc. off the declared `spacingScale`.
173
+ - `visual/radius-scale-violation` — flags `rounded-[7px]`, `rounded-tl-[2rem]` etc. off the declared `radiusScale`.
174
+
175
+ Both emit auto-fix candidates so `slopbrick scan --fix` rewrites `p-[13px]` → `p-1`.
176
+
177
+ **0.6.2 — Repository governance for AI coding agents**
178
+
179
+ The single feature most projects asked for. New top-level `constitution` field in `slopbrick.config.mjs`:
180
+
181
+ ```js
182
+ export default {
183
+ constitution: {
184
+ stateManagement: ['zustand'],
185
+ dataFetching: ['react-query'],
186
+ uiLibrary: ['shadcn', 'radix'],
187
+ forms: ['react-hook-form', 'zod'],
188
+ styling: ['tailwind'],
189
+ routing: ['next'],
190
+ },
191
+ };
192
+ ```
193
+
194
+ Auto-detected from `package.json` when unset; user declarations always win.
195
+
196
+ - `slopbrick drift` — CLI command, exits 1 on any violation (CI-friendly).
197
+ - `slop_suggest` MCP tool — project-wide inventory of existing patterns; AI agents call before writing new code.
198
+ - `slop_check_constitution` MCP tool — per-file constitution diff.
199
+ - `slop_architecture_score` MCP tool — Architecture Consistency Score via MCP.
200
+
201
+ **0.6.1 — bug fixes + small refinements**
202
+
203
+ - `slopbrick trend --format markdown` now actually emits markdown (the local flag was being shadowed by the global scan `--format`; renamed to `--render`).
204
+ - Calibration test surfaces stderr/stdout on chunk failures instead of swallowing them.
205
+ - v1.x working-tree labels stripped.
206
+
207
+ ### CLI surface summary (post-0.8.0)
208
+
209
+ | Command | Purpose |
210
+ |---------|---------|
211
+ | `slopbrick scan` | Main scan — runs all rules + computes all 8 scores |
212
+ | `slopbrick architecture` | Architecture Consistency Score only |
213
+ | `slopbrick security` | AI Security Risk only |
214
+ | `slopbrick drift` | Constitution-violation scanner |
215
+ | `slopbrick pr` | PR slop score (single weighted number per PR) |
216
+ | `slopbrick test` | Test Quality score (4 `test/*` rules) |
217
+ | `slopbrick business-logic` | Business Logic Coherence score (8 rules) |
218
+ | `slopbrick patterns` | Pattern Fragmentation score (input to `slop_suggest`) |
219
+ | `slopbrick maintenance-cost` | AI Maintenance Cost (categorical low/medium/high/critical + $/month) *(0.8.0)* |
220
+ | `slopbrick docs` | Documentation Freshness (4 `docs/*` rules) *(0.8.0)* |
221
+ | `slopbrick db` | Database Health (6 `db/*` rules, Postgres-only) *(0.8.0)* |
222
+ | `slopbrick mcp` | MCP server (`slop_scan_file`, `slop_explain_rule`, `slop_list_rules`, `slop_suggest`, `slop_check_constitution`, `slop_architecture_score`) |
223
+ | `slopbrick trend` | Slop Index trend over time |
224
+ | `slopbrick flywheel` | Aggregated scan telemetry |
225
+ | `slopbrick init` | Interactive setup wizard |
226
+
227
+ ### What 0.6.x did *not* change
228
+
229
+ - **No new competitor overlap.** We did not add a general security scanner, dependency vulnerability scanner, formatter, type checker, or coverage tool.
230
+ - **No breaking CLI changes.** Existing scan commands, JSON / SARIF / HTML output formats, and public-API exports are unchanged.
231
+
232
+ The full release history is in [CHANGELOG.md](./CHANGELOG.md).
233
+
234
+ ---
235
+
236
+ ## Why this matters (research-backed)
237
+
238
+ The 0.7.0 release sits on top of an industry that's converging fast on AI-generated-code debt. The numbers below are from 2024–2026 studies and explain why the Constitution, not the Slop Index, is the moat.
239
+
240
+ - **AI slows experienced developers.** METR's July 2025 RCT (16 experienced open-source devs, 246 tasks on repos averaging 22k stars / 1M LoC) found AI tools produced a **19% slowdown** — developers had expected a 24% speedup. ([METR, 2025](https://metr.org/blog/2025-07-10-early-2025-ai-experienced-os-dev-study/))
241
+ - **AI-generated code carries 1.7× more issues per PR** (10.83 vs 6.45) and a higher share of critical/major issues. ([CodeRabbit, 2025](https://coderabbit.ai/blog/state-of-ai-vs-human-code-generation-report))
242
+ - **Refactoring is collapsing.** GitClear's 211M-line analysis of Google/Microsoft/Meta repos shows "refactored" lines fell from 25% → <10% and "copy-pasted" lines rose from 8.3% → 12.3% between 2021–2024. ([GitClear, 2025](https://www.gitclear.com/ai_assistant_code_quality_2025_research))
243
+ - **PR size is up 51%, bugs/PR up 28%, incidents/PR up 3×, code churn up 10×** across 22k developers in 2026. ([Faros AI, 2026](https://www.faros.ai/research/ai-acceleration-whiplash))
244
+ - **Trust in AI accuracy dropped from 40% → 29%** in one year; 66% of devs spend *more* time debugging AI output. ([Stack Overflow 2025 Developer Survey](https://survey.stackoverflow.co/2025/ai))
245
+ - **Code-surface ↔ doc-surface staleness is an open hole.** No shipped tool (Docusaurus, Mintlify, GitBook, mkdocstrings, TypeDoc) cross-references `package.json` ↔ README or exported names ↔ markdown inline code. The 2026 state-of-the-art is F1 = 96.73% on a single analog task (description-code inconsistency, [arXiv 2606.04769](https://arxiv.org/html/2606.04769v1)). That's what `slopbrick docs` ships against in 0.8.0.
246
+ - **Schema-quality static analysis is an open hole for Drizzle.** The official `eslint-plugin-drizzle` has exactly 2 rules. Prisma has 8+ Prisma-Lens rules but they target per-file linting, not schema-wide drift. Squawk owns migration safety; nobody owns schema quality. That's the wedge for `slopbrick db` in 0.8.0.
247
+ - **The canonical AI-coding-agent failure is the AWS Kiro outage (Dec 2025).** An agentic coding tool autonomously deleted a production environment; 13-hour outage in a China region. ([Docker blog, 2026](https://www.docker.com/blog/coding-agent-horror-stories-the-13-hour-aws-outage/)) The post-mortem: "predictable given unchecked AI permissions." The preventive: a Constitution the agent checks before it acts, with a `$306,000/yr/MLoC` baseline for what the debt costs when it isn't checked. ([Sonar, 2025](https://www.sonarsource.com/blog/new-research-from-sonar-on-cost-of-technical-debt/))
248
+
249
+ The full research notes for each 0.8.0 phase are in [`docs/research/`](./docs/research/).
250
+
251
+ **Mathematical foundations** — the peer-reviewed methods behind every threshold:
252
+ [`docs/research/math-foundations-for-slopbrick.md`](./docs/research/math-foundations-for-slopbrick.md) maps 8 published results (Halstead 1977, Hindle 2012, Rissanen 1978, Kullback-Leibler 1951, Blondel 2008, Fiedler 1973, McCabe 1976, Adams-MacKay 2007) to the slopbrick rules and composite scores that cite them. v0.9.3+ ships the highest-leverage ones (Halstead, Code Naturalness, MDL composite) to replace heuristic thresholds with closed-form citations.
253
+
254
+ **v0.10 implementation plan** — the credibility-milestone roadmap with dependency graph, effort estimates per phase, and readiness checklist: [`docs/research/v0.10-implementation-plan.md`](./docs/research/v0.10-implementation-plan.md). Phases 1–5 (~4 working days) ship v0.10; Phases 6–11 land the far-horizon graph-theoretic, Repository Memory, `--diff`, `find_similar_function`, BRICK, and SARIF work.
255
+
256
+ ---
257
+
258
+ ## Roadmap
259
+
260
+ | Version | Themes | Status |
261
+ |---------|--------|--------|
262
+ | 0.5.x | Engine re-architecture, Slop Index, framework support | Shipped |
263
+ | 0.6.x | Constitution, Architecture Consistency, AI Security Risk, design-token enforcement | Shipped |
264
+ | 0.7.0 | Constitution rename + `forbidden` deny-list, `pr` subcommand, Test / Business-Logic / Patterns subcommands | Shipped 2026-06-25 |
265
+ | 0.8.0 | `docs` (Doc Drift), `db` (Database Health, Postgres-static), `maintenance-cost` ($/month categorical) | Shipped 2026-07-15 |
266
+ | **0.9.0** | **Repository Coherence Scanner reframe, default-off INVERTED + NOISY rules, expanded `slop_suggest`, new `slop_governance` MCP tool** | **Shipped 2026-08-15** |
267
+ | **0.10** | **Credibility milestone: per-rule P/R/FPR + peer-reviewed thresholds (Halstead, McCabe, Hindle, Rissanen, Kullback-Leibler); MDL composite replaces heuristic weights** | **In flight — see [`docs/research/v0.10-implementation-plan.md`](./docs/research/v0.10-implementation-plan.md)** |
268
+ | 1.0 | Stability commitment — 6+ months post-v0.10 empirical feedback; freezes the surface, no new scores | Far horizon |
269
+
270
+ Per-version research notes:
271
+ - [Phase 6 — Doc Drift](./docs/research/phase-6-doc-drift-internet-2026.md)
272
+ - [Phase 8 — DB Health](./docs/research/phase-8-db-health-internet-2026.md)
273
+ - [Memo #4 — AI Maintenance Cost](./docs/research/phase-memo4-ai-cost-internet-2026.md)
274
+ - [Math foundations — peer-reviewed methods for v0.9.3+ rules](./docs/research/math-foundations-for-slopbrick.md)
275
+ - [v0.10 implementation plan — credibility milestone roadmap](./docs/research/v0.10-implementation-plan.md)
276
+
277
+ ---
278
+
279
+ ## Installation
280
+
281
+ Run once without installing:
282
+
283
+ ```bash
284
+ npx slopbrick
285
+ ```
286
+
287
+ Add to a project as a dev dependency:
288
+
289
+ ```bash
290
+ pnpm add -D slopbrick
291
+ ```
292
+
293
+ ---
294
+
295
+ ## Quick start
296
+
297
+ Initialize a config in the project root:
298
+
299
+ ```bash
300
+ npx slopbrick init
301
+ ```
302
+
303
+ Scan the current workspace:
304
+
305
+ ```bash
306
+ npx slopbrick scan
307
+ ```
308
+
309
+ Or scan specific paths:
310
+
311
+ ```bash
312
+ npx slopbrick scan src app
313
+ ```
314
+
315
+ On first run, `slopbrick` auto-detects your framework, styling solution, UI libraries (Tailwind, Tamagui, shadcn/ui, MUI, etc.), and workspace packages. Framework presets automatically disable or downgrade rules that are idiomatic for React Native, Expo, or Tamagui.
316
+
317
+ ### Don't want to write a config from scratch?
318
+
319
+ Four ready-to-use starter configs live in [`examples/`](./examples):
320
+
321
+ - [`examples/basic/`](./examples/basic) — sensible defaults for most projects
322
+ - [`examples/strict/`](./examples/strict) — CI gating with `noIncrease` baseline
323
+ - [`examples/monorepo/`](./examples/monorepo) — pnpm/turbo workspaces
324
+ - [`examples/ci/`](./examples/ci) — JSON + SARIF output for code-scanning upload
325
+
326
+ ```bash
327
+ cp examples/strict/slopbrick.config.mjs ./slopbrick.config.mjs
328
+ npx slopbrick validate-config # check it before running a scan
329
+ ```
330
+
331
+ See [`examples/README.md`](./examples/README.md) for the full walkthrough.
332
+
333
+ ---
334
+
335
+ ## Configuration
336
+
337
+ Config lives at `slopbrick.config.mjs` in the project root. It is an ES module that exports a default object.
338
+
339
+ ```js
340
+ export default {
341
+ include: ['src/**/*', 'app/**/*', 'pages/**/*', 'components/**/*'],
342
+ exclude: [
343
+ '**/node_modules/**',
344
+ '**/*.test.{ts,tsx,js,jsx}',
345
+ '**/*.stories.{ts,tsx}',
346
+ '**/.next/**',
347
+ '**/dist/**',
348
+ '**/build/**',
349
+ '**/coverage/**',
350
+ ],
351
+
352
+ // Per-category weight multiplier
353
+ categoryWeights: {
354
+ visual: 1.2,
355
+ logic: 1.0,
356
+ perf: 0.8,
357
+ typo: 0.5,
358
+ wcag: 1.0,
359
+ layout: 1.0,
360
+ component: 1.0,
361
+ arch: 1.0,
362
+ security: 1.0,
363
+ },
364
+
365
+ // CI threshold (Phase 2 §10: composite Slop Index only)
366
+ thresholds: {
367
+ meanSlop: 30,
368
+ },
369
+
370
+ // Rule severity overrides.
371
+ // 'auto' keeps the rule's natural severity; 'off' disables it.
372
+ rules: {
373
+ 'visual/inline-style': 'auto',
374
+ 'visual/hardcoded-color': 'low',
375
+ 'logic/style-sheet-avoidance': 'medium',
376
+ },
377
+
378
+ // Boost or reduce scores for specific frameworks
379
+ frameworkMultipliers: {
380
+ astro: 0.8,
381
+ },
382
+
383
+ // Phase 2 §10: brick.config.json import paths. Defaults to common
384
+ // shadcn-style paths. Imports from `@/components/*` not matching
385
+ // these prefixes are flagged by `context/import-path-mismatch`.
386
+ allowedImports: [
387
+ '@/components/ui/',
388
+ '@/components/',
389
+ '@/lib/',
390
+ '@/hooks/',
391
+ ],
392
+ };
393
+ ```
394
+
395
+ ### Key options
396
+
397
+ | Option | What it does |
398
+ |--------|--------------|
399
+ | `include` | File patterns to scan (default: all source files) |
400
+ | `exclude` | File patterns to skip |
401
+ | `categoryWeights` | Make certain issue types count more or less |
402
+ | `thresholds` | CI gates — see "Thresholds" below |
403
+ | `rules` | Turn specific rules off or change their severity |
404
+ | `frameworkMultipliers` | Boost/reduce scores for specific frameworks |
405
+ | `arbitraryValueAllowlist` | Tailwind values that are OK to use |
406
+ | `allowedImports` | brick.config.json import paths (Phase 2 §10) |
407
+ | `wcag` | Accessibility-specific settings |
408
+
409
+ ---
410
+
411
+ ## Composite Slop Index (Phase 2 §10)
412
+
413
+ slopbrick produces a single composite score that prioritizes structural integrity over minor visual escapes:
414
+
415
+ ```
416
+ S = (0.40 × S_boundary) + (0.35 × S_context) + (0.25 × S_visual)
417
+ ```
418
+
419
+ Each subscore is `min(100, severityPoints / componentCount)`, where `severityPoints` is the sum of severity weights for issues in that bucket.
420
+
421
+ **Bucket weights:**
422
+
423
+ | Bucket | Weight | What it measures |
424
+ |--------|-------:|------------------|
425
+ | **Boundary** | 40% | Structural integrity: file-size limits, multiple components per file, direct API calls in UI |
426
+ | **Context** | 35% | Prop correctness, imports, state management |
427
+ | **Visual** | 25% | CSS, layout, typography, accessibility |
428
+
429
+ **Rule → Subscore mapping:**
430
+
431
+ - **Boundary (40%)**: `logic/boundary-violation`, `component/giant-component`, `component/multiple-components-per-file`
432
+ - **Context (35%)**: `component/shadcn-prop-mismatch`, `arch/astro-island-leak`, `context/import-path-mismatch`, most `logic/*`
433
+ - **Visual (25%)**: all `visual/*`, `layout/*`, `typo/*`, `wcag/*`, `perf/*`
434
+
435
+ ---
436
+
437
+ ## CLI reference
438
+
439
+ ```text
440
+ Usage: slopbrick [options] [command]
441
+
442
+ Options:
443
+ -V, --version output the version number
444
+ --framework <name> framework multiplier to apply
445
+ --include <glob> include pattern (repeatable)
446
+ --exclude <glob> exclude pattern (repeatable)
447
+ --ai-only only report AI-specific issues
448
+ --human-only only report human-facing issues
449
+ --ignore-wcag22 ignore WCAG 2.2 related issues
450
+ --format <pretty|json|sarif|html> output format (default: "pretty")
451
+ --threads <n> number of worker threads
452
+ --since <ref> only scan files changed since git ref
453
+ --workspace <path> workspace/project path
454
+ --tighten tighten baseline allowances
455
+ --fix apply auto-fixes
456
+ --dry-run preview fixes without writing any files
457
+ --diff print unified diff of proposed auto-fixes
458
+ --doctor run diagnostics
459
+ --watch watch files and re-run
460
+ --suggest print remediation advice
461
+ --heatmap print migration ROI heatmap
462
+ --quiet suppress non-error output
463
+ --strict exit 2 if any high-severity issue remains
464
+ --no-increase exit 2 if slop index increased since last run
465
+ --auto-disable-noisy-rules downgrade rules whose measured precision < 0.5
466
+ or recall < 0.1 by one severity step
467
+ --baseline save a baseline after this scan
468
+ --trend [n] print a sparkline of the last n runs
469
+ --json [path] write JSON report to path or stdout
470
+ --html [path] write HTML report to path or stdout
471
+ --staged scan only staged files
472
+ --changed scan working-tree changes
473
+ --incremental skip unchanged files via content-hash cache
474
+ --cache-path <path> path to the incremental cache (default: .slop-audit-cache.json)
475
+ --tokens <path> merge tokens.json layout values into the
476
+ arbitrary-value allowlist
477
+ --cache cache parsed AST results locally
478
+ --rule <ruleId> run a single rule by id, skip all others
479
+ -h, --help display help for command
480
+
481
+ Commands:
482
+ init [options] create a slopbrick config file
483
+ install install the git pre-commit hook
484
+ uninstall uninstall the git pre-commit hook
485
+ badge print a shields.io slop-index badge
486
+ suggest print remediation advice
487
+ flywheel [options] summarize aggregated scan telemetry
488
+ scan [paths...] scan files for slop
489
+ explain <ruleId> print rationale, pattern, and remediation for a single rule
490
+ tokens <path> ingest a W3C DTCG tokens.json and summarize it by category
491
+ report <path> re-render a saved JSON report (from --json path.json)
492
+ doctor check your setup, config, and environment for common problems
493
+ rules [--category <name>] [--ai-only] [--json]
494
+ list all built-in rules with descriptions
495
+ mcp run an MCP server (for AI agents)
496
+ help [command] display help for command
497
+ ```
498
+
499
+ ### pr — score a pull request
500
+
501
+ `slopbrick pr` runs the engine over the files changed between two
502
+ git refs and returns a single weighted slop score. The score is
503
+ `sum(SEVERITY_WEIGHTS[issue.severity]) + constitution_violations`
504
+ per file, summed across the diff. With the default threshold of
505
+ `20` (configurable via `prScoreThreshold` or `--threshold`), a PR
506
+ can introduce roughly 4 medium-severity issues before it fails.
507
+
508
+ ```bash
509
+ slopbrick pr [--base <ref>] [--head <ref>]
510
+ [--format text|json|markdown]
511
+ [--threshold <n>] [--max-files <n>]
512
+ ```
513
+
514
+ Defaults: `--base main` (falls back to `master` then the first
515
+ commit), `--head HEAD`, `--format text`, `--threshold 20`,
516
+ `--max-files 500`. The diff is computed with three-dot syntax
517
+ (`git diff --name-only base...head`), which matches GitHub's PR
518
+ view (merge-base comparison).
519
+
520
+ ```text
521
+ $ slopbrick pr
522
+ PR score: 4 (threshold: 20) — PASS
523
+ Base: main Head: HEAD
524
+ Files changed: 1
525
+
526
+ src/store.ts issues=1 constitution=1 score=4
527
+ [medium ] security/public-admin-route — line 1
528
+ [forbidden] Constitution violation: … imports 'redux' (canonical: 'redux').
529
+
530
+ ────────────────────────────────────────────
531
+ PR score: 4 / 20 threshold — PASS
532
+ ```
533
+
534
+ Use it as a CI gate:
535
+
536
+ ```yaml
537
+ - run: npx slopbrick pr --threshold 10
538
+ # exits 1 when PR score > 10
539
+ ```
540
+
541
+ ### Exit codes
542
+
543
+ | Code | Meaning |
544
+ |------|---------|
545
+ | `0` | Composite Slop Index under `meanSlop` threshold |
546
+ | `1` | Composite Slop Index exceeds threshold |
547
+ | `2` | High-severity issues with `--strict`, score regression with `--no-increase`, or hook install failure |
548
+ | `3` | Unexpected scan error (parser crash, worker failure after retries) |
549
+
550
+ ---
551
+
552
+ ## Example terminal output
553
+
554
+ ```text
555
+ $ npx slopbrick scan
556
+ Scanned 312 files, 501 components, 1423 issues (high: 48, medium: 321, low: 1054)
557
+
558
+ Slop Index: 14.2 / 100 [PASS]
559
+ (Phase 2 §10 composite: 0.40 × Boundary + 0.35 × Context + 0.25 × Visual)
560
+ ├─ Boundary Slop: 12.5 (Weighted: 5.0)
561
+ ├─ Context Slop: 4.0 (Weighted: 1.4)
562
+ └─ Visual Slop: 31.0 (Weighted: 7.8)
563
+
564
+ Top offending components
565
+ 72.3 src/app/(tabs)/keepsakes.tsx
566
+ 65.1 src/app/(tabs)/search.tsx
567
+ 58.0 src/app/child/[id]/edit.tsx
568
+ ...
569
+
570
+ Thresholds
571
+
572
+ Composite Slop Index 14.2 ≤ 30 pass
573
+
574
+ All thresholds passed.
575
+
576
+ Issues (1423)
577
+ [HIGH ] logic/boundary-violation · src/app/(tabs)/keepsakes.tsx:91:22
578
+ Data layer mixed with UI component
579
+ → Move fetch/state into a server action or hook.
580
+ ```
581
+
582
+ ---
583
+
584
+ ## How scoring works
585
+
586
+ ### Severity weights
587
+
588
+ | Severity | Weight |
589
+ |----------|-------:|
590
+ | high | 5 |
591
+ | medium | 3 |
592
+ | low | 1 |
593
+
594
+ (The `critical` tier was removed during the scoring-model refactor to prevent scoring inflation.)
595
+
596
+ ### Per-file scoring
597
+
598
+ For each file, the engine:
599
+ 1. Parses the source (SWC for TS/JS, regex for HTML, dedicated parsers for Vue/Svelte/Astro).
600
+ 2. Walks the AST to extract facts: imports, JSX elements, class names, inline styles, hooks, state bindings, etc.
601
+ 3. Runs each of the 42 registered rules against the facts.
602
+ 4. Each rule returns 0+ issues with severity, line, column, and optional fix suggestions.
603
+
604
+ ### Project scoring (Phase 2 §10)
605
+
606
+ 1. **Bucket** every issue into one of three subscores (boundary, context, visual) using the rule-to-bucket map.
607
+ 2. **Sum** severity weights per bucket: `bucketPoints[b] = Σ SEVERITY_WEIGHTS[issue.severity]`.
608
+ 3. **Normalize**: `subscore[b] = min(100, bucketPoints[b] / componentCount × 100)`.
609
+ 4. **Composite**: `slopIndex = 0.40 × boundary + 0.35 × context + 0.25 × visual`.
610
+ 5. **Health**: `assemblyHealth = max(0, 100 - slopIndex)`.
611
+
612
+ ### Threshold
613
+
614
+ A single threshold (`meanSlop`) gates the exit code: `slopIndex > meanSlop` → exit 1.
615
+
616
+ ---
617
+
618
+ ## Architecture
619
+
620
+ ### High-level pipeline
621
+
622
+ ```
623
+ ┌────────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐
624
+ │ CLI bin/ │───▶│ discover │───▶│ parser │───▶│ visitor │───▶│ rules │
625
+ │ slopbrick │ │ discover │ │ engine/ │ │ engine/ │ │ rules/ │
626
+ │ .js │ │ .ts │ │ parser.ts│ │ visitor.ts│ │ *.ts │
627
+ └────────────┘ └──────────┘ └──────────┘ └──────────┘ └──────────┘
628
+
629
+
630
+ ┌────────────┐ ┌──────────────┐ ┌────────────────┐ ┌─────────────────┐
631
+ │ Output │◀───│ aggregate │◀───│ report │◀───│ ProjectReport │
632
+ │ report/ │ │ metrics │ │ ProjectReport│ │ (per-issue) │
633
+ │ *.ts │ │ metrics.ts │ │ │ │ │
634
+ └────────────┘ └──────────────┘ └────────────────┘ └─────────────────┘
635
+ ```
636
+
637
+ ### End-to-end flow (`slopbrick scan`)
638
+
639
+ 1. **CLI entry** (`bin/slopbrick.js`)
640
+
641
+ Loads `dist/index.js` (the bundled CLI), parses command-line flags with Commander, and resolves `cwd` from `--workspace` or `process.cwd()`.
642
+
643
+ 2. **Config loading** (`src/config.ts`)
644
+
645
+ Walks up from cwd looking for `slopbrick.config.{js,mjs,cjs,ts}`, merges the user config with `DEFAULT_CONFIG` (which sets `thresholds`, `rules`, `allowedImports`), and validates the merged result against the schema.
646
+
647
+ 3. **File discovery** (`src/discover.ts`)
648
+
649
+ Uses `globby` to expand `include` patterns and `minimatch` to apply `exclude`. For files without an extension, it reads the first 512 bytes and sniffs the content type (TSX/TS/JSX/JS/Vue/Svelte/Astro/HTML). It de-duplicates by basename when both extension-less and proper-extension versions exist, then filters by `SOURCE_EXTENSIONS` (`.ts`, `.tsx`, `.js`, `.jsx`, `.vue`, `.svelte`, `.astro`, `.html`).
650
+
651
+ 4. **Per-file scanning** (`src/engine/worker.ts`, `src/engine/parser.ts`, `src/engine/visitor.ts`)
652
+
653
+ Runs in worker threads (configurable via `--threads`).
654
+
655
+ The **parser** dispatches based on file extension: SWC for TS/JS, dedicated handlers for Vue/Svelte/Astro, regex for HTML. Extension-less files try TSX → TS → JSX → JS in order.
656
+
657
+ The **visitor** walks the AST and extracts a `ScanFacts` summary, including:
658
+ - `imports[]` — `{source, importedNames, line, column}`
659
+ - `interactiveElements[]` — JSX `<button>`, `<a>`, `<input>`, etc. with attributes
660
+ - `staticClassNames[]` — className string literals
661
+ - `styleProps[]` — inline `style={{...}}` props
662
+ - `componentSizes[]` — per-component line count + JSX branch count
663
+ - `propBindings[]`, `stateBindings[]`, `hooks[]`, `logicalExpressions[]`, etc.
664
+
665
+ **Rule execution** iterates the registered rules (built-ins + user overrides) and calls each rule's `analyze(facts, context)` method, collecting `Issue[]`.
666
+
667
+ 5. **Aggregation** (`src/engine/metrics.ts`)
668
+
669
+ Sums severity points per subscore bucket (boundary / context / visual), normalizes each bucket by component count capped at 100, and computes `slopIndex = 0.40 × boundary + 0.35 × context + 0.25 × visual`. Returns the structured `ProjectReport` with all subscores, severity counts, and per-file scores.
670
+
671
+ 6. **Threshold check** (`src/cli/threshold.ts`)
672
+
673
+ Calls `thresholdExceeded(report, config)`, which compares `report.slopIndex` against `config.thresholds.meanSlop`. Returns true → exit code 1. Also checks per-category thresholds (`categoryThresholds`) if configured.
674
+
675
+ 7. **Output rendering** (`src/report/`)
676
+
677
+ One module per format:
678
+ - `pretty.ts` — human-readable terminal output with the composite breakdown tree
679
+ - `json.ts` — serialized `ProjectReport` (full data)
680
+ - `sarif.ts` — SARIF 2.1.0 for IDE/editor integration
681
+ - `html.ts` — self-contained HTML report with score cards
682
+ - `markdown.ts` — Markdown report for PR comments
683
+ - `heatmap.ts` — migration ROI heatmap (top files by score)
684
+ - `unified-diff.ts` — unified diff of the report
685
+ - `advice.ts` — remediation suggestions
686
+ - `flywheel.ts` — telemetry summary
687
+
688
+ ### File layout
689
+
690
+ ```
691
+ src/
692
+ ├── index.ts # Public facade (re-exports from ./cli/)
693
+ ├── config.ts # Public config facade (re-exports from ./config/)
694
+ ├── config/ # config/{defaults,presets,detect,load,init}
695
+ ├── cli/ # CLI surface (Commander wiring + scan + init engines)
696
+ │ ├── program.ts # runCli — Commander setup, per-command .action() callbacks
697
+ │ ├── scan.ts # runScan, scanProject, watchProject, renderOutput
698
+ │ ├── init.ts # runInitWizard, runDoctor, init prompts
699
+ │ ├── options.ts # CLI option parsers (parseThreads, collectGlob, …)
700
+ │ ├── render.ts # colorForSlop, formatBadge, formatSparkline, …
701
+ │ └── threshold.ts # thresholdExceeded, stagedGating, filterIssues, …
702
+ ├── engine/
703
+ │ ├── parser.ts # SWC/Vue/Svelte/Astro/HTML dispatch + extension-less fallback
704
+ │ ├── visitor.ts # AST walker → ScanFacts extraction (1313 lines — largest file)
705
+ │ ├── worker.ts # Per-file scan worker thread
706
+ │ ├── metrics.ts # Composite Slop Index aggregation
707
+ │ ├── logger.ts # Test-aware logging
708
+ │ ├── pool.ts # WorkerPool with work-stealing + retry
709
+ │ ├── executor.ts # Inline scan path for small file counts
710
+ │ ├── cache.ts # .slop-audit-cache.json + baseline.json
711
+ │ ├── memory.ts # run-history.json (--trend, --no-increase)
712
+ │ ├── telemetry.ts # Flywheel payloads
713
+ │ └── trend.ts # --trend sparkline builder
714
+ ├── rules/ # Rule modules (42 built-in rules across 9 categories)
715
+ │ ├── arch/ # 1 rule — astro-island-leak
716
+ │ ├── component/ # 3 rules — giant-component, multiple-components-per-file,
717
+ │ │ shadcn-prop-mismatch
718
+ │ ├── context/ # 1 rule — import-path-mismatch
719
+ │ ├── layout/ # 4 rules — gap-monopoly, math-element-uniformity,
720
+ │ │ math-grid-uniformity, spacing-grid
721
+ │ ├── logic/ # 11 rules — boundary-violation, ghost-defensive,
722
+ │ │ key-prop-missing, math-any-density,
723
+ │ │ math-console-log-storm, math-gini-class-usage,
724
+ │ │ math-variable-name-entropy, optimistic-no-rollback,
725
+ │ │ qwik-hook-leak, reactive-hook-soup, zombie-state
726
+ │ ├── perf/ # 2 rules — cls-image, css-bloat
727
+ │ ├── typo/ # 5 rules — calc-fontsize, calc-raw-px, clamp-offscale,
728
+ │ │ math-button-label-uniformity, math-cta-vocabulary
729
+ │ ├── visual/ # 11 rules — arbitrary-escape, clamp-soup, generic-centering,
730
+ │ │ inline-style-dominance, math-color-cluster,
731
+ │ │ math-default-font, math-font-entropy,
732
+ │ │ math-gradient-hue-rotation, math-rounded-entropy,
733
+ │ │ math-spacing-entropy
734
+ │ ├── wcag/ # 4 rules — dragging-movements, focus-appearance,
735
+ │ │ focus-obscured, target-size
736
+ │ ├── builtins.ts # Auto-generated registry (pnpm generate:rules)
737
+ │ ├── rule.ts # createRule + RuleDefinition types
738
+ │ ├── registry.ts # RuleRegistry (loadBuiltins, loadProjects)
739
+ │ ├── registry-loader.ts # shadcn/ui registry snapshot cache
740
+ │ ├── project.ts # Project-level rules (runProjectRules)
741
+ │ ├── signal-strength.ts # --show-signal-strength lookup
742
+ │ └── signal-strength.json # Per-rule precision/recall measurements
743
+ ├── report/ # Output formatters (pretty, json, sarif, html, …)
744
+ │ ├── pretty.ts, json.ts, sarif.ts, html.ts, markdown.ts
745
+ │ ├── advice.ts # --suggest output
746
+ │ ├── unified-diff.ts # --diff output
747
+ │ ├── heatmap.ts # --heatmap output
748
+ │ ├── flywheel.ts # flywheel summary
749
+ │ └── html/ # html/{utils,sections,static}.ts
750
+ ├── fix/ # Auto-fix codemods
751
+ │ ├── index.ts # applyFixes orchestrator
752
+ │ ├── visual-codemod.ts # Round-20 visual codemods entry point
753
+ │ └── visual-codemods/ # tailwind.ts, jsx.ts, source.ts
754
+ ├── snippet.ts # AI agent rule snippet generators (facade)
755
+ ├── snippet/ # snippet/{data,render,generators,targets}
756
+ ├── flywheel.ts # Flywheel state machine
757
+ ├── mcp/ # MCP server (src/mcp/server.ts + tools)
758
+ ├── research/ # research/generate, analyze, candidates, calibrate
759
+ ├── config-validation.ts # Static config schema validator
760
+ ├── discover.ts # File discovery + extension sniffing
761
+ ├── git.ts # --staged / --changed / --since git integration
762
+ ├── installer.ts # install/uninstall git pre-commit hook
763
+ ├── explain.ts # `slopbrick explain <ruleId>` output
764
+ ├── tokens.ts # W3C DTCG tokens.json parser
765
+ ├── types.ts # All public types (ProjectReport, ScanFacts, Issue, …)
766
+ └── bin/ # bin/slopbrick.js entry point
767
+ ```
768
+
769
+ ---
770
+
771
+ ## MCP server (for AI agents)
772
+
773
+ slopbrick ships a [Model Context Protocol](https://modelcontextprotocol.io/) server so AI coding agents can call it directly:
774
+
775
+ ```bash
776
+ slopbrick mcp # JSON-RPC 2.0 over stdio
777
+ ```
778
+
779
+ Exposes three tools:
780
+
781
+ | Tool | Args | Returns |
782
+ |------|------|---------|
783
+ | `slop_scan_file` | `{path, framework?}` | issues + Slop Index for one file |
784
+ | `slop_explain_rule` | `{ruleId}` | rule metadata + rationale + file location |
785
+ | `slop_list_rules` | `{category?}` | all rules with category / severity / aiSpecific |
786
+
787
+ Add to your MCP client config:
788
+
789
+ ```json
790
+ {
791
+ "mcpServers": {
792
+ "slopbrick": {
793
+ "command": "npx",
794
+ "args": ["slopbrick", "mcp"],
795
+ "cwd": "/path/to/your/project"
796
+ }
797
+ }
798
+ }
799
+ ```
800
+
801
+ ### AI agent rule snippets
802
+
803
+ Generate directive snippets that teach your AI agent the slop rules BEFORE it writes code:
804
+
805
+ ```bash
806
+ slopbrick init --matrix # print the matrix table
807
+ slopbrick init --yes --agents-md # Codex / opencode / Pi / Cline / Gemini
808
+ slopbrick init --yes --claude-md # Claude Code
809
+ slopbrick init --yes --all # all targets at once
810
+ ```
811
+
812
+ | Flag | File | Agent |
813
+ |------|------|-------|
814
+ | `--cursor` | `.cursor/rules/slopbrick.mdc` | Cursor (new format) |
815
+ | `--cursorrules` | `.cursorrules` | Cursor (legacy format, deprecated) |
816
+ | `--agents-md` | `AGENTS.md` | OpenAI Codex / opencode / Pi / Cline / Continue / Gemini |
817
+ | `--claude-md` | `CLAUDE.md` | Claude Code (takes precedence over AGENTS.md) |
818
+ | `--aider` | `CONVENTIONS.md` | Aider |
819
+ | `--windsurf` | `.windsurfrules` | Windsurf (Cascade) |
820
+ | `--cline` | `.clinerules/AGENTS.md` | Cline (folder-based) |
821
+ | `--gemini` | `.gemini/GEMINI.md` | Gemini CLI |
822
+ | `--copilot` | `.github/copilot-instructions.md` | GitHub Copilot |
823
+
824
+ Content is generated live from the rule registry — always matches what slopbrick actually checks.
825
+
826
+ ---
827
+
828
+ ## Adding new rules
829
+
830
+ Rule modules live in `src/rules/<category>/<rule>.ts`. Each module must export a const ending in `Rule` and a matching default export:
831
+
832
+ ```ts
833
+ import { createRule } from '../rule';
834
+ import type { Issue, Rule, RuleContext, ScanFacts } from '../../types';
835
+
836
+ export const myRule = createRule<RuleContext>({
837
+ id: 'category/my-rule',
838
+ category: 'visual',
839
+ severity: 'medium',
840
+ aiSpecific: true,
841
+ description: 'Short one-line description used in `slopbrick rules` output.',
842
+ create(context) {
843
+ return context;
844
+ },
845
+ analyze(_context, facts: ScanFacts): Issue[] {
846
+ const issues: Issue[] = [];
847
+ // ... analyze facts ...
848
+ return issues;
849
+ },
850
+ });
851
+
852
+ export default myRule satisfies Rule<RuleContext>;
853
+ ```
854
+
855
+ Run `pnpm generate:rules` to regenerate `src/rules/builtins.ts`. This runs automatically before `pnpm build` and `pnpm test`.
856
+
857
+ ---
858
+
859
+ ## Calibration against held-out human code
860
+
861
+ The tool ships with an automated calibration test (`tests/integration/calibration.test.ts`) that scans both corpora and asserts every AI-signal rule has a recall/FP ratio ≥ its threshold. It runs as part of `pnpm test` and exits non-zero on regression.
862
+
863
+ The corpora live at `/Users/cheng/ai-slop-baseline/extracted/`:
864
+ - `positive/` — 6,142 AI-generated samples (vibe-coded React apps).
865
+ - `negative/` — 54,980 human-written samples (shadcn/ui, calcom, dub, mantine, excalidraw, lobehub, etc.).
866
+
867
+ A rule with a recall/FP ratio above 1.0× is a useful AI tell. A ratio below 1.0× is an anti-signal — tighten it, scope-restrict it, or drop it.
868
+
869
+ ---
870
+
871
+ ## Glossary
872
+
873
+ - **Slop Index** — 0–100 composite score per Phase 2 §10. Lower is better. Weighted average of boundary (40%), context (35%), and visual (25%) subscores.
874
+ - **Assembly Health** — Inverse of Slop Index. Higher is better.
875
+ - **Composite Slop Index** — Phase 2 §10's weighted three-bucket formula.
876
+ - **AI-specific rule** — Rule that catches patterns AI defaults to but humans rarely do (e.g. `bg-violet-500`, "Get started today", badge-above-h1 layout).
877
+ - **General rule** — Catches real bugs or code-quality issues regardless of author.
878
+ - **brick.config.json** — Project config (in `slopbrick.config.mjs`) listing allowed import paths for `context/import-path-mismatch`.
879
+ - **RSC / Server component** — React Server Component. Runs on the server, can't use `useState`/`useEffect`. The fix is `'use client'`.
880
+ - **Memoization** — React skips re-renders if inputs haven't changed. Inline handlers break memoization because they're new functions on every render.
881
+ - **Astro island** — Interactive component inside an otherwise static Astro page. Without `client:*` directive, clicks won't fire.
882
+ - **DTCG tokens** — W3C Design Token Community Group JSON format. `slopbrick tokens <path>` reads these.
883
+ - **MCP** — Model Context Protocol. JSON-RPC 2.0 over stdio for AI agent integration.
884
+
885
+ ---
886
+
887
+ ## Development
888
+
889
+ ```bash
890
+ pnpm install
891
+ pnpm typecheck
892
+ pnpm test
893
+ pnpm build
894
+ ```
895
+
896
+ Adding a rule? Update `tests/integration/calibration.test.ts` to add a calibration entry — the corpus test will verify your rule discriminates AI from human code.
897
+
898
+ ---
899
+
900
+ ## License
901
+
902
+ [MIT](./LICENSE)