instrlint 0.2.2 → 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/README.md +56 -103
- package/README.zh-TW.md +55 -102
- package/dist/cli.cjs +49 -25
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +53 -29
- package/dist/cli.js.map +1 -1
- package/package.json +3 -3
- package/skills/instrlint/SKILL.md +63 -0
- package/skills/instrlint/references/judgment-framework.md +130 -0
- package/skills/claude-code/SKILL.md +0 -163
- package/skills/codex/SKILL.md +0 -122
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "instrlint",
|
|
3
|
-
"version": "0.2.
|
|
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": "
|
|
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,163 +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
|
-
## What it checks
|
|
135
|
-
|
|
136
|
-
- **Budget** — token consumption across all instruction files and MCP servers. Flags files > 200 lines, baselines > 25% of context window.
|
|
137
|
-
- **Dead rules** — rules already enforced by tsconfig, prettier, eslint, commitlint, editorconfig, and more. ~15 overlap patterns.
|
|
138
|
-
- **Structure** — contradictions between rules, stale file references, duplicates, and path-scoping opportunities.
|
|
139
|
-
|
|
140
|
-
## Auto-fix (--fix)
|
|
141
|
-
|
|
142
|
-
Auto-applied (safe, deterministic):
|
|
143
|
-
- Rules already enforced by config files (dead rules)
|
|
144
|
-
- References to non-existent files (stale refs)
|
|
145
|
-
- Exact duplicate rules
|
|
146
|
-
|
|
147
|
-
Actionable suggestions shown after fix (requires human judgment):
|
|
148
|
-
- Git hook suggestions — copy-paste `.claude/settings.json` snippet
|
|
149
|
-
- Path-scoped rule file suggestions — ready-to-create file content
|
|
150
|
-
|
|
151
|
-
## Score and grade
|
|
152
|
-
|
|
153
|
-
| Grade | Score | Meaning |
|
|
154
|
-
|-------|-------|---------|
|
|
155
|
-
| A | 90–100 | Excellent — minor issues only |
|
|
156
|
-
| B | 80–89 | Good — a few improvements possible |
|
|
157
|
-
| C | 70–79 | Fair — some issues to address |
|
|
158
|
-
| D | 60–69 | Poor — significant problems |
|
|
159
|
-
| F | < 60 | Critical — needs immediate attention |
|
|
160
|
-
|
|
161
|
-
## Supported tools
|
|
162
|
-
|
|
163
|
-
Claude Code, Codex, Cursor — auto-detected from project structure.
|
package/skills/codex/SKILL.md
DELETED
|
@@ -1,122 +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
|
-
## What it checks
|
|
119
|
-
|
|
120
|
-
- **Budget** — token consumption across AGENTS.md, skills, and MCP servers.
|
|
121
|
-
- **Dead rules** — rules already enforced by tsconfig, prettier, eslint, and other config files.
|
|
122
|
-
- **Structure** — contradictions, stale file references, duplicates, and path-scoping opportunities.
|