instrlint 0.2.3 → 0.2.4

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/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "instrlint",
3
- "version": "0.2.3",
3
+ "version": "0.2.4",
4
4
  "description": "Lint and optimize your CLAUDE.md / AGENTS.md — find dead rules, token waste, and structural issues",
5
5
  "type": "module",
6
6
  "bin": {
7
- "instrlint": "./dist/cli.js"
7
+ "instrlint": "dist/cli.js"
8
8
  },
9
9
  "main": "./dist/index.js",
10
10
  "exports": {
@@ -26,7 +26,7 @@
26
26
  "author": "Jed Lin",
27
27
  "repository": {
28
28
  "type": "git",
29
- "url": "https://github.com/jed1978/instrlint"
29
+ "url": "git+https://github.com/jed1978/instrlint.git"
30
30
  },
31
31
  "homepage": "https://github.com/jed1978/instrlint#readme",
32
32
  "bugs": {
@@ -0,0 +1,63 @@
1
+ ---
2
+ name: instrlint
3
+ description: Lint and optimize agent instruction files. Use when the user wants to lint, audit, refactor, or optimize their CLAUDE.md, AGENTS.md, .cursorrules, or related instruction files — finds dead rules, token waste, duplicates, contradictions, and stale references. Produces a scored health report (0–100) with auto-fix and host-orchestrated LLM verification.
4
+ ---
5
+
6
+ # instrlint
7
+
8
+ Lint and optimize agent instruction files. Produces a scored health report across three dimensions: token budget, dead rules, and structure.
9
+
10
+ ## Command Resolution Protocol
11
+
12
+ When the user runs `/instrlint [args]`:
13
+
14
+ 1. **Detect language** — identify conversation language → output: locale
15
+ - 繁體中文 → `zh-TW`
16
+ - English or any other → `en`
17
+
18
+ 2. **Check `--verify`** — if args contain `--verify` → jump to LLM Verification Protocol below. Otherwise continue.
19
+
20
+ 3. **Map command** — parse user args against this table → output: base command
21
+
22
+ | User args | Base command |
23
+ |-----------|-------------|
24
+ | _(none)_ | `npx instrlint@latest` |
25
+ | `budget` | `npx instrlint@latest budget` |
26
+ | `deadrules` | `npx instrlint@latest deadrules` |
27
+ | `structure` | `npx instrlint@latest structure` |
28
+ | `--fix` | `npx instrlint@latest --fix` |
29
+ | `ci --fail-on warning` | `npx instrlint@latest ci --fail-on warning` |
30
+
31
+ 4. **Build final command** — append flags from steps 1 and 3:
32
+ `{base command} --format markdown --lang {locale}`
33
+ Exception: `--fix` omits `--format markdown` (output is a fix summary, not a report).
34
+
35
+ 5. **Execute and present** — run the command → present the markdown output directly to the user. Never summarize or paraphrase.
36
+
37
+ ## LLM Verification Protocol (`--verify`)
38
+
39
+ contradiction / duplicate / structure detectors are text heuristics and may produce false positives. You (the host agent) can judge these semantically.
40
+
41
+ **Protocol:** instrlint never calls an LLM API. It writes suspicious findings as `candidates.json`, you judge them and write `verdicts.json`, then instrlint merges the results back into the report.
42
+
43
+ ### Quick steps
44
+
45
+ 1. `npx instrlint@latest --emit-candidates instrlint-candidates.json --skip-report --lang <detected>`
46
+ 2. Read `instrlint-candidates.json` and judge each candidate using criteria from [references/judgment-framework.md](references/judgment-framework.md) (`confirmed` / `rejected` / `uncertain`)
47
+ 3. Write `instrlint-verdicts.json` with your verdicts (`id` must match 12-char hex from candidates)
48
+ 4. `npx instrlint@latest --apply-verdicts instrlint-verdicts.json --format markdown --lang <detected>`
49
+
50
+ ## Splitting Guidance
51
+
52
+ When instrlint reports either of these conditions, **do not paste the suggestion text directly** — run the splitting decision walkthrough instead:
53
+
54
+ - Budget warning: root instruction file exceeds recommended line count (> 200 lines)
55
+ - Structure findings contain path-scope suggestions (`messageKey: structure.scopePathScoped`)
56
+
57
+ ### Walkthrough flow
58
+
59
+ 1. **Read** the file, list major sections (heading + line count)
60
+ 2. **Classify each section** using the 4-bucket framework (see [references/judgment-framework.md](references/judgment-framework.md))
61
+ 3. **Present a decision table** to the user (section / lines / recommended action / reason)
62
+ 4. **Ask** the user: "Minimum split (bucket 1 only) / Full split (buckets 1+2+3) / Custom"
63
+ 5. **Execute**: bucket 1 → extract to rules directory with `paths:` / `globs:` frontmatter; bucket 2 → extract without path-scope; bucket 3 → replace with one-line pointer
@@ -0,0 +1,130 @@
1
+ # LLM Verification — Judgment Framework
2
+
3
+ Reference document for `/instrlint --verify`. The host agent uses this framework when judging candidates.
4
+
5
+ ## --verify Four-Step Protocol
6
+
7
+ **Step 1** — Emit candidates:
8
+
9
+ ```bash
10
+ npx instrlint@latest --emit-candidates instrlint-candidates.json --skip-report --lang <detected>
11
+ ```
12
+
13
+ **Step 2** — Read and judge:
14
+
15
+ Use the Read tool to read `instrlint-candidates.json`. For each candidate, apply the judgment criteria below.
16
+
17
+ **Step 3** — Write verdicts to `instrlint-verdicts.json`:
18
+
19
+ ```json
20
+ {
21
+ "version": 1,
22
+ "verdicts": [
23
+ { "id": "a3f1c9e2b4d6", "verdict": "rejected", "reason": "兩條規則 context 無關" }
24
+ ]
25
+ }
26
+ ```
27
+
28
+ Each verdict's `id` must exactly match the `id` in candidates.json (12-char hex). `verdict` is `confirmed` / `rejected` / `uncertain`. `reason` ≤ 500 chars.
29
+
30
+ **Step 4** — Apply verdicts and render report:
31
+
32
+ ```bash
33
+ npx instrlint@latest --apply-verdicts instrlint-verdicts.json --format markdown --lang <detected>
34
+ ```
35
+
36
+ Present the output markdown as-is to the user.
37
+
38
+ ## candidates.json Format
39
+
40
+ ```json
41
+ {
42
+ "version": 1,
43
+ "generatedAt": "2026-04-07T12:00:00.000Z",
44
+ "projectRoot": "/absolute/path/to/project",
45
+ "candidates": [
46
+ {
47
+ "id": "a3f1c9e2b4d6",
48
+ "category": "contradiction",
49
+ "question": "Do rules A and B actually contradict each other in practice?...",
50
+ "context": {
51
+ "type": "contradiction",
52
+ "ruleA": { "file": "CLAUDE.md", "line": 10, "text": "Use exceptions for error handling." },
53
+ "ruleB": { "file": "CLAUDE.md", "line": 20, "text": "Never throw exceptions, use Result<T> instead." }
54
+ },
55
+ "originalFinding": { "severity": "critical", "category": "contradiction", "file": "CLAUDE.md", "line": 20 }
56
+ }
57
+ ]
58
+ }
59
+ ```
60
+
61
+ ## Judgment Criteria
62
+
63
+ ### contradiction
64
+
65
+ - **confirmed**: A developer following both ruleA and ruleB simultaneously would face a real conflict in some scenario
66
+ - **rejected**: The rules address different contexts, or the negation is only superficial (false positive)
67
+ - **uncertain**: Semantically ambiguous; cannot judge from available context
68
+
69
+ ### duplicate
70
+
71
+ - **confirmed**: Both rules say the same thing in different words — removing one loses no information
72
+ - **rejected**: Surface similarity but actually covers different details, scope, or exceptions
73
+ - **uncertain**: Cannot determine
74
+
75
+ ### structure
76
+
77
+ - **confirmed**: This rule is genuinely better enforced by a git hook or path-scoped rule file; keeping it in the root instruction file is redundant
78
+ - **rejected**: This rule is an architectural decision, general principle, or context requiring human judgment (e.g. "LLM verification must be host-orchestrated" is a design principle, not something a git hook can enforce)
79
+ - **uncertain**: Cannot determine without more context
80
+
81
+ ### General rules
82
+
83
+ - For structure: read `candidate.context.rule.text` and `candidate.context.suggestion` first
84
+ - For contradiction / duplicate: read `candidate.context.ruleA.text` / `ruleB.text` first
85
+ - Use the Read tool to view surrounding context in the file when needed
86
+ - `reason` can be ≤ 20 chars in practice (max 500 chars — instrlint validates)
87
+ - Candidates with no verdict don't need to appear in verdicts.json (instrlint leaves them unchanged)
88
+ - `rejected` findings are filtered from the final report; `confirmed` and `uncertain` appear with your reason
89
+
90
+ ---
91
+
92
+ ## CLAUDE.md / AGENTS.md Refactoring — 4-Bucket Framework
93
+
94
+ ### Walkthrough Flow
95
+
96
+ 1. **Read** the file, list major sections (heading + line count)
97
+ 2. **Classify each section** using the 4-bucket framework below; if a section spans multiple buckets, use the primary body and note it in the decision table
98
+ 3. **Present a decision table** to the user (section name / line count / recommended action / reason)
99
+ 4. **Ask** the user: "Minimum split (bucket 1 only) / Full split (buckets 1+2+3) / Custom"
100
+ 5. **Execute the chosen actions**:
101
+ - bucket 1 → extract to rules directory with `paths:` / `globs:` frontmatter
102
+ - Claude Code: `.claude/rules/`
103
+ - Codex: `.agents/rules/`
104
+ - bucket 2 → extract without path-scope frontmatter
105
+ - bucket 3 → replace with a one-line pointer
106
+
107
+ ### 4-Bucket Classification
108
+
109
+ | Bucket | Condition | Action |
110
+ |---|---|---|
111
+ | **1. Real savings** | Tied to specific files/modules, most conversations don't need it (< 30% load rate) | Extract + `paths:` / `globs:` frontmatter |
112
+ | **2. Extractable, no savings** | Global, loaded in nearly every conversation (> 80% load rate) | Extract to shorten file — total tokens unchanged |
113
+ | **3. Delete, not move** | Duplicates source code (e.g. type definitions already in `src/types.ts`) | Replace with a one-line pointer |
114
+ | **4. Stay in root file** | Cross-conversation decisions / commands / state | Don't move |
115
+
116
+ **Load rate heuristic:** Ask yourself "In what fraction of real conversations would this scope be loaded?"
117
+ - > 80% → bucket 2 or 4 (path-scoping gives no benefit)
118
+ - 30–80% → decide based on maintenance cost
119
+ - < 30% → bucket 1 (real savings)
120
+
121
+ ### Examples
122
+
123
+ | Section | Bucket | Reason |
124
+ |---|---|---|
125
+ | Module-specific gotchas | 1 — Real savings | Only needed when editing that module; scope to the relevant `src/` path |
126
+ | Coding conventions | 2 — Extractable, no savings | Loaded for any .ts file; splitting doesn't change total tokens |
127
+ | Key types (type definitions, **identical to source file with no extra commentary**) | 3 — Delete, not move | Duplicate info; keep one line: `see src/types.ts` |
128
+ | Architecture decisions | 4 — Stay in root file | Cross-file design principles needed every conversation |
129
+
130
+ > **Principle:** The purpose of path-scoping is "don't load this in conversations that don't need it." If it would be loaded in almost every conversation anyway, it's bucket 2, not bucket 1.
@@ -1,203 +0,0 @@
1
- ---
2
- name: instrlint
3
- description: Health check your CLAUDE.md and rule files — find dead rules, token waste, duplicates, contradictions, and stale references. Produces a scored health report (0-100) with auto-fix support.
4
- command: /instrlint
5
- argument-hint: "[budget|deadrules|structure|ci] [--fix] [--verify] [--lang zh-TW]"
6
- ---
7
-
8
- # instrlint
9
-
10
- Lint and optimize agent instruction files. Produces a scored health report across three dimensions: token budget, dead rules, and structure.
11
-
12
- ## How to run
13
-
14
- **Always run with `--format markdown`** so the report renders properly in Claude Code. Never use the default terminal format — it uses ANSI colors and box-drawing characters that don't display correctly here.
15
-
16
- Then **present the markdown report directly to the user** — do not summarize or paraphrase it.
17
-
18
- ## Language detection
19
-
20
- **Always detect the language of the current conversation before running:**
21
-
22
- - 繁體中文 conversation → add `--lang zh-TW`
23
- - English conversation → add `--lang en`
24
- - Any other language → fall back to `--lang en`
25
-
26
- ## Command mapping
27
-
28
- When the user runs `/instrlint [args]`, translate to:
29
-
30
- | User input | Command to run |
31
- |------------|---------------|
32
- | `/instrlint` | `npx instrlint@latest --format markdown --lang <detected>` |
33
- | `/instrlint budget` | `npx instrlint@latest budget --format markdown --lang <detected>` |
34
- | `/instrlint deadrules` | `npx instrlint@latest deadrules --format markdown --lang <detected>` |
35
- | `/instrlint structure` | `npx instrlint@latest structure --format markdown --lang <detected>` |
36
- | `/instrlint --fix` | `npx instrlint@latest --fix --lang <detected>` then present the fix summary as-is |
37
- | `/instrlint ci --fail-on warning` | `npx instrlint@latest ci --format markdown --fail-on warning --lang <detected>` |
38
- | `/instrlint --verify` | 執行下方「LLM 驗證流程」四步驟 |
39
- | `/instrlint structure --verify` | 同上,但僅對 structure 類別的 findings 進行 LLM 複核 |
40
-
41
- ## LLM 驗證流程(--verify)
42
-
43
- contradiction / duplicate / structure detector 是純文字啟發式,可能產生 false positive。你(host agent)能讀懂語意,可以複核這些 findings。
44
-
45
- **協議概念:** instrlint 不會自己呼叫 LLM API。它把可疑 findings 寫成 `candidates.json`,由你判斷後寫 `verdicts.json`,再由 instrlint merge 回報告。
46
-
47
- ### 四步驟
48
-
49
- **Step 1** — 產出 candidates:
50
-
51
- ```bash
52
- npx instrlint@latest --emit-candidates instrlint-candidates.json --skip-report --lang <detected>
53
- ```
54
-
55
- **Step 2** — 讀取並判斷:
56
-
57
- 用 Read tool 讀 `instrlint-candidates.json`。對每個 candidate,根據下方「判斷框架」做出 verdict。
58
-
59
- **Step 3** — 寫出 verdicts:
60
-
61
- 用 Write tool 寫 `instrlint-verdicts.json`:
62
-
63
- ```json
64
- {
65
- "version": 1,
66
- "verdicts": [
67
- { "id": "a3f1c9e2b4d6", "verdict": "rejected", "reason": "兩條規則 context 無關" }
68
- ]
69
- }
70
- ```
71
-
72
- 每個 verdict 的 `id` 必須與 candidates.json 中的 `id` 完全對應(12-char hex)。`verdict` 為 `confirmed` / `rejected` / `uncertain`,`reason` ≤ 500 字元。
73
-
74
- **Step 4** — 套用 verdicts 並呈現報告:
75
-
76
- ```bash
77
- npx instrlint@latest --apply-verdicts instrlint-verdicts.json --format markdown --lang <detected>
78
- ```
79
-
80
- 把輸出的 markdown 報告原樣呈現給使用者,不要摘要或改寫。
81
-
82
- ### candidates.json 格式
83
-
84
- ```json
85
- {
86
- "version": 1,
87
- "generatedAt": "2026-04-07T12:00:00.000Z",
88
- "projectRoot": "/absolute/path/to/project",
89
- "candidates": [
90
- {
91
- "id": "a3f1c9e2b4d6",
92
- "category": "contradiction",
93
- "question": "Do rules A and B actually contradict each other in practice?...",
94
- "context": {
95
- "type": "contradiction",
96
- "ruleA": { "file": "CLAUDE.md", "line": 10, "text": "Use exceptions for error handling." },
97
- "ruleB": { "file": "CLAUDE.md", "line": 20, "text": "Never throw exceptions, use Result<T> instead." }
98
- },
99
- "originalFinding": { "severity": "critical", "category": "contradiction", "file": "CLAUDE.md", "line": 20, "..." }
100
- }
101
- ]
102
- }
103
- ```
104
-
105
- ## 判斷框架(host agent 用)
106
-
107
- ### contradiction
108
-
109
- - **confirmed**:開發者同時遵守 ruleA 和 ruleB 在某些情境下做不到(真實衝突)
110
- - **rejected**:兩條規則各做各的、context 不同、或只是字面上有否定詞(false positive)
111
- - **uncertain**:語意模糊,無法從現有 context 判斷
112
-
113
- ### duplicate
114
-
115
- - **confirmed**:兩條規則用不同措辭說同一件事,刪掉一條沒有任何資訊損失
116
- - **rejected**:表面相似但實際說的是不同的細節 / 範圍 / 例外
117
- - **uncertain**:判不出來
118
-
119
- ### structure
120
-
121
- - **confirmed**:這條規則確實更適合由 git hook 或 path-scoped rule file 自動執行,放在 CLAUDE.md 中是多餘的
122
- - **rejected**:這條規則是架構決策說明、一般性原則、或需要人工判斷的 context,不適合用工具強制執行(例:「LLM 驗證必須由 host orchestrate」是設計原則,不是 git hook 能攔的)
123
- - **uncertain**:無法判斷,需要看更多 context
124
-
125
- ### 通則
126
-
127
- - structure:先讀 `candidate.context.rule.text` 和 `candidate.context.suggestion`
128
- - contradiction / duplicate:先讀 `candidate.context.ruleA.text` / `ruleB.text`
129
- - 必要時用 Read tool 看該 file 的上下文
130
- - `reason` 實務上寫 ≤ 20 字即可(上限 500 字元,instrlint 會驗證)
131
- - 沒有 verdict 的 candidate 不需要寫進 verdicts.json(instrlint 會保留它不動)
132
- - `rejected` findings 在最終報告中會被過濾掉;`confirmed` 和 `uncertain` 會附上你的 reason 顯示
133
-
134
- ## CLAUDE.md 拆分引導
135
-
136
- 當 instrlint 報告出現以下任一情況時,**不要直接貼建議文字**,改走「拆分決策 walkthrough」:
137
-
138
- - Budget 警告:根指令檔超過建議行數(> 200 行)
139
- - Structure findings 含 path-scope 建議(`messageKey: structure.scopePathScoped`)
140
-
141
- ### Walkthrough 流程
142
-
143
- 1. **Read** 該檔,列出主要段落(標題 + 行數)
144
- 2. **逐段分類**,套用下方 4-bucket 框架;若一個段落混合多個 bucket,以主體為準並在決策表中標注
145
- 3. **呈現決策表**給 user(段落名稱 / 行數 / 建議動作 / 原因)
146
- 4. **詢問** user:「最小拆(只處理 bucket 1)/ 全拆(bucket 1 + 2 + 3 均處理)/ 自選」
147
- 5. **對選定段落執行對應行動**:bucket 1 → 抽出到 `.claude/rules/` 並引導寫 `paths:` / `globs:` frontmatter;bucket 2 → 抽出但**不加** path-scope frontmatter;bucket 3 → 替換成一行指標
148
-
149
- ### 4-bucket 分類框架
150
-
151
- | Bucket | 條件 | 行動 |
152
- |---|---|---|
153
- | **1. 實質節省** | 綁特定檔案/模組,多數對話用不到(< 30% 載入率)| 抽出 + `paths:` / `globs:` frontmatter |
154
- | **2. 可抽出但不節省** | 全域通用,任何任務都會載入(> 80% 載入率)| 可純抽出讓 CLAUDE.md 變短,總 token 不變 |
155
- | **3. 該刪不是該搬** | 跟 source code 重複(例:型別定義已在 `src/types.ts`)| 替換成一行指標 |
156
- | **4. 留在 CLAUDE.md** | 跨對話必需的決策 / commands / 狀態 | 不動 |
157
-
158
- **載入頻率判斷標準:** 問自己「多少比例的對話會載入這個 scope?」
159
- - > 80% → bucket 2 或 4(path-scope 無效,不值得拆)
160
- - 30–80% → 視維護成本決定
161
- - < 30% → bucket 1(實質節省)
162
-
163
- ### 範例
164
-
165
- | 段落 | Bucket | 理由 |
166
- |---|---|---|
167
- | 特定模組的 gotchas | 1 — 實質節省 | 只在改該模組時需要,scope 到對應 `src/` 路徑 |
168
- | Coding conventions | 2 — 可抽出但不節省 | 寫任何 .ts 都會載入,拆不拆總 token 相同 |
169
- | Key types(型別定義,**與 source file 完全一致無額外說明**)| 3 — 該刪不是該搬 | 重複資訊,留一行 `see src/types.ts` 即可 |
170
- | Architecture decisions | 4 — 留在 CLAUDE.md | 跨檔設計原則,每次對話都需要 |
171
-
172
- > **原則:** path-scope 的目的是「在不需要這段規則的對話中完全不載入」。如果 scope 後還是幾乎每次都載入,就是 bucket 2,不是 bucket 1。
173
-
174
- ## What it checks
175
-
176
- - **Budget** — token consumption across all instruction files and MCP servers. Flags files > 200 lines, baselines > 25% of context window.
177
- - **Dead rules** — rules already enforced by tsconfig, prettier, eslint, commitlint, editorconfig, and more. ~15 overlap patterns.
178
- - **Structure** — contradictions between rules, stale file references, duplicates, and path-scoping opportunities.
179
-
180
- ## Auto-fix (--fix)
181
-
182
- Auto-applied (safe, deterministic):
183
- - Rules already enforced by config files (dead rules)
184
- - References to non-existent files (stale refs)
185
- - Exact duplicate rules
186
-
187
- Actionable suggestions shown after fix (requires human judgment):
188
- - Git hook suggestions — copy-paste `.claude/settings.json` snippet
189
- - Path-scoped rule file suggestions — ready-to-create file content
190
-
191
- ## Score and grade
192
-
193
- | Grade | Score | Meaning |
194
- |-------|-------|---------|
195
- | A | 90–100 | Excellent — minor issues only |
196
- | B | 80–89 | Good — a few improvements possible |
197
- | C | 70–79 | Fair — some issues to address |
198
- | D | 60–69 | Poor — significant problems |
199
- | F | < 60 | Critical — needs immediate attention |
200
-
201
- ## Supported tools
202
-
203
- Claude Code, Codex, Cursor — auto-detected from project structure.
@@ -1,162 +0,0 @@
1
- ---
2
- name: instrlint
3
- description: Health check your AGENTS.md and rule files — find dead rules, token waste, duplicates, contradictions, and stale references.
4
- command: /instrlint
5
- argument-hint: "[budget|deadrules|structure|ci] [--fix] [--format json|markdown|sarif]"
6
- ---
7
-
8
- # instrlint
9
-
10
- Lint and optimize agent instruction files. Produces a scored health report across three dimensions: token budget, dead rules, and structure.
11
-
12
- ## Language detection
13
-
14
- **Always detect the language of the current conversation before running instrlint:**
15
-
16
- - If the user is conversing in **Traditional Chinese (繁體中文)**: run with `--lang zh-TW`
17
- - If the user is conversing in **English**: run with `--lang en`
18
- - For any other language instrlint does not support: fall back to `--lang en`
19
-
20
- ## Usage
21
-
22
- ```
23
- /instrlint # Full health check (score + grade)
24
- /instrlint budget # Token budget analysis only
25
- /instrlint deadrules # Dead rule detection only
26
- /instrlint structure # Structural analysis only
27
- /instrlint ci --fail-on warning # CI mode: exit 1 if warnings found
28
- /instrlint --fix # Auto-fix safe issues + show actionable suggestions
29
- /instrlint --format json # JSON output for CI
30
- /instrlint --format markdown # Markdown output for PR comments
31
- /instrlint install --codex # Install skill into .agents/skills/
32
- /instrlint --verify # LLM-assisted two-pass verification (see below)
33
- ```
34
-
35
- ## LLM 驗證流程(--verify)
36
-
37
- contradiction / duplicate detector 是純文字啟發式,可能產生 false positive。你(host agent)能讀懂語意,可以複核這些 findings。
38
-
39
- **協議概念:** instrlint 不會自己呼叫 LLM API。它把可疑 findings 寫成 `candidates.json`,由你判斷後寫 `verdicts.json`,再由 instrlint merge 回報告。
40
-
41
- ### 四步驟
42
-
43
- **Step 1** — 產出 candidates:
44
-
45
- ```bash
46
- npx instrlint@latest --emit-candidates instrlint-candidates.json --skip-report --lang <detected>
47
- ```
48
-
49
- **Step 2** — 讀取並判斷:
50
-
51
- 讀 `instrlint-candidates.json`。對每個 candidate,根據下方「判斷框架」做出 verdict。
52
-
53
- **Step 3** — 寫出 verdicts:
54
-
55
- 寫 `instrlint-verdicts.json`:
56
-
57
- ```json
58
- {
59
- "version": 1,
60
- "verdicts": [
61
- { "id": "a3f1c9e2b4d6", "verdict": "rejected", "reason": "兩條規則 context 無關" }
62
- ]
63
- }
64
- ```
65
-
66
- 每個 verdict 的 `id` 必須與 candidates.json 中的 `id` 完全對應(12-char hex)。`verdict` 為 `confirmed` / `rejected` / `uncertain`,`reason` ≤ 500 字元。
67
-
68
- **Step 4** — 套用 verdicts 並呈現報告:
69
-
70
- ```bash
71
- npx instrlint@latest --apply-verdicts instrlint-verdicts.json --format markdown --lang <detected>
72
- ```
73
-
74
- ### candidates.json 格式
75
-
76
- ```json
77
- {
78
- "version": 1,
79
- "generatedAt": "2026-04-07T12:00:00.000Z",
80
- "projectRoot": "/absolute/path/to/project",
81
- "candidates": [
82
- {
83
- "id": "a3f1c9e2b4d6",
84
- "category": "contradiction",
85
- "question": "Do rules A and B actually contradict each other in practice?...",
86
- "context": {
87
- "type": "contradiction",
88
- "ruleA": { "file": "CLAUDE.md", "line": 10, "text": "Use exceptions for error handling." },
89
- "ruleB": { "file": "CLAUDE.md", "line": 20, "text": "Never throw exceptions, use Result<T> instead." }
90
- },
91
- "originalFinding": { "severity": "critical", "category": "contradiction", "file": "CLAUDE.md", "line": 20, "..." }
92
- }
93
- ]
94
- }
95
- ```
96
-
97
- ## 判斷框架(host agent 用)
98
-
99
- ### contradiction
100
-
101
- - **confirmed**:開發者同時遵守 ruleA 和 ruleB 在某些情境下做不到(真實衝突)
102
- - **rejected**:兩條規則各做各的、context 不同、或只是字面上有否定詞(false positive)
103
- - **uncertain**:語意模糊,無法從現有 context 判斷
104
-
105
- ### duplicate
106
-
107
- - **confirmed**:兩條規則用不同措辭說同一件事,刪掉一條沒有任何資訊損失
108
- - **rejected**:表面相似但實際說的是不同的細節 / 範圍 / 例外
109
- - **uncertain**:判不出來
110
-
111
- ### 通則
112
-
113
- - 先讀 `candidate.context.ruleA.text` / `ruleB.text`,必要時看該 file 的上下文
114
- - `reason` 實務上寫 ≤ 20 字即可(上限 500 字元,instrlint 會驗證)
115
- - 沒有 verdict 的 candidate 不需要寫進 verdicts.json(instrlint 會保留它不動)
116
- - `rejected` findings 在最終報告中會被過濾掉;`confirmed` 和 `uncertain` 會附上你的 reason 顯示
117
-
118
- ## AGENTS.md 拆分引導
119
-
120
- 當 instrlint 報告出現以下任一情況時,**不要直接貼建議文字**,改走「拆分決策 walkthrough」:
121
-
122
- - Budget 警告:根指令檔超過建議行數(> 200 行)
123
- - Structure findings 含 path-scope 建議(`messageKey: structure.scopePathScoped`)
124
-
125
- ### Walkthrough 流程
126
-
127
- 1. **Read** 該檔,列出主要段落(標題 + 行數)
128
- 2. **逐段分類**,套用下方 4-bucket 框架;若一個段落混合多個 bucket,以主體為準並在決策表中標注
129
- 3. **呈現決策表**給 user(段落名稱 / 行數 / 建議動作 / 原因)
130
- 4. **詢問** user:「最小拆(只處理 bucket 1)/ 全拆(bucket 1 + 2 + 3 均處理)/ 自選」
131
- 5. **對選定段落執行對應行動**:bucket 1 → 抽出到 `.agents/rules/` 並引導寫 `paths:` / `globs:` frontmatter;bucket 2 → 抽出但**不加** path-scope frontmatter;bucket 3 → 替換成一行指標
132
-
133
- ### 4-bucket 分類框架
134
-
135
- | Bucket | 條件 | 行動 |
136
- |---|---|---|
137
- | **1. 實質節省** | 綁特定檔案/模組,多數對話用不到(< 30% 載入率)| 抽出到 `.agents/rules/` + `paths:` / `globs:` frontmatter |
138
- | **2. 可抽出但不節省** | 全域通用,任何任務都會載入(> 80% 載入率)| 可純抽出讓 AGENTS.md 變短,總 token 不變 |
139
- | **3. 該刪不是該搬** | 跟 source code 重複(例:型別定義已在原始檔中)| 替換成一行指標 |
140
- | **4. 留在 AGENTS.md** | 跨對話必需的決策 / commands / 狀態 | 不動 |
141
-
142
- **載入頻率判斷標準:** 問自己「多少比例的對話會載入這個 scope?」
143
- - > 80% → bucket 2 或 4(path-scope 無效,不值得拆)
144
- - 30–80% → 視維護成本決定
145
- - < 30% → bucket 1(實質節省)
146
-
147
- ### 範例
148
-
149
- | 段落 | Bucket | 理由 |
150
- |---|---|---|
151
- | 特定模組的 gotchas | 1 — 實質節省 | 只在改該模組時需要,scope 到對應 `src/` 路徑 |
152
- | Coding conventions | 2 — 可抽出但不節省 | 寫任何 .ts 都會載入,拆不拆總 token 相同 |
153
- | Key types(型別定義,**與 source file 完全一致無額外說明**)| 3 — 該刪不是該搬 | 重複資訊,留一行 source file 指標即可 |
154
- | Architecture decisions | 4 — 留在 AGENTS.md | 跨檔設計原則,每次對話都需要 |
155
-
156
- > **原則:** path-scope 的目的是「在不需要這段規則的對話中完全不載入」。如果 scope 後還是幾乎每次都載入,就是 bucket 2,不是 bucket 1。
157
-
158
- ## What it checks
159
-
160
- - **Budget** — token consumption across AGENTS.md, skills, and MCP servers.
161
- - **Dead rules** — rules already enforced by tsconfig, prettier, eslint, and other config files.
162
- - **Structure** — contradictions, stale file references, duplicates, and path-scoping opportunities.