@yawlabs/ctxlint 0.4.0 → 0.6.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/.pre-commit-hooks.yaml +8 -0
- package/CONTEXT_LINT_SPEC.md +613 -0
- package/MCP_CONFIG_LINT_SPEC.md +396 -0
- package/README.md +159 -18
- package/context-lint-rules.json +415 -0
- package/dist/{chunk-WEYNMCAH.js → chunk-PLYBGRJD.js} +1049 -57
- package/dist/chunk-ZXMDA7VB.js +16 -0
- package/dist/{cli-VYWAONGX.js → cli-XQVUFK2D.js} +120 -25
- package/dist/index.js +3 -3
- package/dist/mcp/chunk-MCKGQKYU.js +15 -0
- package/dist/mcp/server.js +1100 -65
- package/dist/mcp/tiktoken-MWTCLHI2.js +465 -0
- package/dist/{server-7C2IQ7VV.js → server-4SC5VMA7.js} +49 -3
- package/dist/tiktoken-CCNRJMFQ.js +466 -0
- package/mcp-config-lint-rules.json +413 -0
- package/package.json +38 -16
|
@@ -0,0 +1,613 @@
|
|
|
1
|
+
# AI Context File Linting Specification
|
|
2
|
+
|
|
3
|
+
**Version:** 1.0.0-draft
|
|
4
|
+
**Date:** 2026-04-07
|
|
5
|
+
**Maintained by:** [Yaw Labs](https://yaw.sh) / [ctxlint](https://github.com/YawLabs/ctxlint)
|
|
6
|
+
**License:** CC BY 4.0
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## What is this?
|
|
11
|
+
|
|
12
|
+
AI coding agents are guided by context files — markdown documents like `CLAUDE.md`, `.cursorrules`, and `AGENTS.md` that tell the agent how a project works. These files reference source paths, build commands, frameworks, and conventions. When the code changes and the context files don't, the agent follows stale instructions and fails.
|
|
13
|
+
|
|
14
|
+
This specification defines a standard set of lint rules for validating AI agent context files across all major AI coding clients. It is tool-agnostic: any linter, IDE extension, CI check, or AI agent can implement these rules.
|
|
15
|
+
|
|
16
|
+
The specification includes:
|
|
17
|
+
- A complete reference of context file formats across 17 AI coding clients (21+ file patterns)
|
|
18
|
+
- 19 lint rules organized into 7 categories with defined severities
|
|
19
|
+
- A machine-readable rule and format catalog ([`context-lint-rules.json`](./context-lint-rules.json))
|
|
20
|
+
- Auto-fix definitions for rules that support automated correction
|
|
21
|
+
- Frontmatter schema requirements per client
|
|
22
|
+
|
|
23
|
+
**Companion specification:** [MCP Server Configuration Linting Specification](./MCP_CONFIG_LINT_SPEC.md) — covers linting for MCP server config files (`.mcp.json`, etc.), the tool-configuration counterpart to instruction-based context files.
|
|
24
|
+
|
|
25
|
+
**Reference implementation:** [ctxlint](https://github.com/YawLabs/ctxlint) (v0.3.0+)
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## Table of contents
|
|
30
|
+
|
|
31
|
+
- [1. Context File Landscape Reference](#1-context-file-landscape-reference)
|
|
32
|
+
- [1.1 What are context files?](#11-what-are-context-files)
|
|
33
|
+
- [1.2 Supported formats by client](#12-supported-formats-by-client)
|
|
34
|
+
- [1.3 Scoping and precedence](#13-scoping-and-precedence)
|
|
35
|
+
- [1.4 Frontmatter schemas](#14-frontmatter-schemas)
|
|
36
|
+
- [2. Content Extraction](#2-content-extraction)
|
|
37
|
+
- [2.1 Path reference detection](#21-path-reference-detection)
|
|
38
|
+
- [2.2 Command reference detection](#22-command-reference-detection)
|
|
39
|
+
- [2.3 Token counting](#23-token-counting)
|
|
40
|
+
- [3. Lint Rules](#3-lint-rules)
|
|
41
|
+
- [3.1 paths — file reference validation](#31-paths--file-reference-validation)
|
|
42
|
+
- [3.2 commands — build/script validation](#32-commands--buildscript-validation)
|
|
43
|
+
- [3.3 staleness — freshness detection](#33-staleness--freshness-detection)
|
|
44
|
+
- [3.4 tokens — context window budget](#34-tokens--context-window-budget)
|
|
45
|
+
- [3.5 redundancy — inferable content](#35-redundancy--inferable-content)
|
|
46
|
+
- [3.6 contradictions — cross-file conflicts](#36-contradictions--cross-file-conflicts)
|
|
47
|
+
- [3.7 frontmatter — client metadata validation](#37-frontmatter--client-metadata-validation)
|
|
48
|
+
- [4. Rule Catalog (machine-readable)](#4-rule-catalog-machine-readable)
|
|
49
|
+
- [5. Implementing This Specification](#5-implementing-this-specification)
|
|
50
|
+
- [6. Contributing](#6-contributing)
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## 1. Context File Landscape Reference
|
|
55
|
+
|
|
56
|
+
### 1.1 What are context files?
|
|
57
|
+
|
|
58
|
+
Context files are markdown documents placed in a project repository that provide instructions to AI coding agents. They typically contain:
|
|
59
|
+
|
|
60
|
+
- **Project structure** — what files are where, how the codebase is organized
|
|
61
|
+
- **Build and test commands** — how to run, build, and test the project
|
|
62
|
+
- **Conventions** — coding style, naming patterns, architectural decisions
|
|
63
|
+
- **Constraints** — what to avoid, what not to change, security requirements
|
|
64
|
+
|
|
65
|
+
Every major AI coding client reads one or more context file formats. Some clients support scoped rules (applied only when certain files are open), frontmatter-driven activation, and override hierarchies.
|
|
66
|
+
|
|
67
|
+
### 1.2 Supported formats by client
|
|
68
|
+
|
|
69
|
+
#### Claude Code
|
|
70
|
+
|
|
71
|
+
| File pattern | Scope | Notes |
|
|
72
|
+
|---|---|---|
|
|
73
|
+
| `CLAUDE.md` | Project root | Primary context file. Loaded automatically. |
|
|
74
|
+
| `CLAUDE.local.md` | Project root | Personal overrides. Not committed to git. |
|
|
75
|
+
| `.claude/rules/*.md` | Rule-based | Individual rule files loaded by Claude Code. |
|
|
76
|
+
|
|
77
|
+
**Hierarchy:** `CLAUDE.local.md` overrides `CLAUDE.md`. Rules in `.claude/rules/` are additive.
|
|
78
|
+
|
|
79
|
+
#### AAIF / Multi-agent standard
|
|
80
|
+
|
|
81
|
+
| File pattern | Scope | Notes |
|
|
82
|
+
|---|---|---|
|
|
83
|
+
| `AGENTS.md` | Project root | Linux Foundation AAIF standard. Recognized by multiple clients. |
|
|
84
|
+
| `AGENT.md` | Project root | Singular variant. |
|
|
85
|
+
| `AGENTS.override.md` | Project root | Override layer. |
|
|
86
|
+
|
|
87
|
+
#### Cursor
|
|
88
|
+
|
|
89
|
+
| File pattern | Scope | Notes |
|
|
90
|
+
|---|---|---|
|
|
91
|
+
| `.cursorrules` | Project root | Legacy format. Plain text, no frontmatter. |
|
|
92
|
+
| `.cursor/rules/*.md` | Rule-based | Markdown rules. No frontmatter required. |
|
|
93
|
+
| `.cursor/rules/*.mdc` | Rule-based | MDC format. Requires YAML frontmatter. |
|
|
94
|
+
| `.cursor/rules/*/RULE.md` | Rule-based | Nested rule directory pattern. |
|
|
95
|
+
|
|
96
|
+
**MDC frontmatter fields:** `description` (required), `globs` (file targeting), `alwaysApply` (boolean).
|
|
97
|
+
|
|
98
|
+
#### GitHub Copilot
|
|
99
|
+
|
|
100
|
+
| File pattern | Scope | Notes |
|
|
101
|
+
|---|---|---|
|
|
102
|
+
| `.github/copilot-instructions.md` | Project-wide | Main instructions file. |
|
|
103
|
+
| `.github/instructions/*.md` | Scoped | Per-topic instruction files. Support `applyTo` frontmatter. |
|
|
104
|
+
| `.github/git-commit-instructions.md` | Commit scope | Instructions specific to commit message generation. |
|
|
105
|
+
|
|
106
|
+
**Frontmatter fields:** `applyTo` (glob pattern targeting specific files).
|
|
107
|
+
|
|
108
|
+
#### Windsurf
|
|
109
|
+
|
|
110
|
+
| File pattern | Scope | Notes |
|
|
111
|
+
|---|---|---|
|
|
112
|
+
| `.windsurfrules` | Project root | Legacy format. Plain text. |
|
|
113
|
+
| `.windsurf/rules/*.md` | Rule-based | Markdown rules with frontmatter. |
|
|
114
|
+
|
|
115
|
+
**Frontmatter fields:** `trigger` (required, one of: `always_on`, `glob`, `manual`, `model`).
|
|
116
|
+
|
|
117
|
+
#### Gemini CLI
|
|
118
|
+
|
|
119
|
+
| File pattern | Scope | Notes |
|
|
120
|
+
|---|---|---|
|
|
121
|
+
| `GEMINI.md` | Project root | Loaded automatically by Gemini CLI. |
|
|
122
|
+
|
|
123
|
+
#### Cline
|
|
124
|
+
|
|
125
|
+
| File pattern | Scope | Notes |
|
|
126
|
+
|---|---|---|
|
|
127
|
+
| `.clinerules` | Project root | Plain text context file. |
|
|
128
|
+
|
|
129
|
+
#### Aider
|
|
130
|
+
|
|
131
|
+
| File pattern | Scope | Notes |
|
|
132
|
+
|---|---|---|
|
|
133
|
+
| `.aiderules` | Project root | No file extension. Plain text. |
|
|
134
|
+
|
|
135
|
+
#### Aide / Codestory
|
|
136
|
+
|
|
137
|
+
| File pattern | Scope | Notes |
|
|
138
|
+
|---|---|---|
|
|
139
|
+
| `.aide/rules/*.md` | Rule-based | Markdown rules in a dedicated directory. |
|
|
140
|
+
|
|
141
|
+
#### Amazon Q Developer
|
|
142
|
+
|
|
143
|
+
| File pattern | Scope | Notes |
|
|
144
|
+
|---|---|---|
|
|
145
|
+
| `.amazonq/rules/*.md` | Rule-based | Markdown rules in a dedicated directory. |
|
|
146
|
+
|
|
147
|
+
#### Goose (Block)
|
|
148
|
+
|
|
149
|
+
| File pattern | Scope | Notes |
|
|
150
|
+
|---|---|---|
|
|
151
|
+
| `.goose/instructions.md` | Project-wide | Main instructions file. |
|
|
152
|
+
| `.goosehints` | Project root | Legacy hint file format. |
|
|
153
|
+
|
|
154
|
+
#### JetBrains Junie
|
|
155
|
+
|
|
156
|
+
| File pattern | Scope | Notes |
|
|
157
|
+
|---|---|---|
|
|
158
|
+
| `.junie/guidelines.md` | Project-wide | Main guidelines file. |
|
|
159
|
+
| `.junie/AGENTS.md` | Project-wide | AAIF-compatible agent instructions. |
|
|
160
|
+
|
|
161
|
+
#### JetBrains AI Assistant
|
|
162
|
+
|
|
163
|
+
| File pattern | Scope | Notes |
|
|
164
|
+
|---|---|---|
|
|
165
|
+
| `.aiassistant/rules/*.md` | Rule-based | Markdown rules. |
|
|
166
|
+
|
|
167
|
+
#### Continue
|
|
168
|
+
|
|
169
|
+
| File pattern | Scope | Notes |
|
|
170
|
+
|---|---|---|
|
|
171
|
+
| `.continuerules` | Project root | Legacy format. |
|
|
172
|
+
| `.continue/rules/*.md` | Rule-based | Markdown rules. |
|
|
173
|
+
|
|
174
|
+
#### Zed
|
|
175
|
+
|
|
176
|
+
| File pattern | Scope | Notes |
|
|
177
|
+
|---|---|---|
|
|
178
|
+
| `.rules` | Project root | Plain text. No extension. |
|
|
179
|
+
|
|
180
|
+
#### Replit
|
|
181
|
+
|
|
182
|
+
| File pattern | Scope | Notes |
|
|
183
|
+
|---|---|---|
|
|
184
|
+
| `replit.md` | Project root | Context for Replit's AI assistant. |
|
|
185
|
+
|
|
186
|
+
### 1.3 Scoping and precedence
|
|
187
|
+
|
|
188
|
+
Context files operate at different scopes depending on the client:
|
|
189
|
+
|
|
190
|
+
**Project-wide** — loaded for every conversation. Examples: `CLAUDE.md`, `.cursorrules`, `GEMINI.md`. The agent always sees these.
|
|
191
|
+
|
|
192
|
+
**Rule-based** — loaded individually based on rules or file patterns. Examples: `.cursor/rules/*.mdc` (loaded when `globs` match the active file), `.github/instructions/*.md` (loaded when `applyTo` matches).
|
|
193
|
+
|
|
194
|
+
**Override** — layers over the base context. Examples: `CLAUDE.local.md` overrides `CLAUDE.md`, `AGENTS.override.md` overrides `AGENTS.md`.
|
|
195
|
+
|
|
196
|
+
**Precedence (when applicable):**
|
|
197
|
+
- Personal/local overrides project-wide defaults
|
|
198
|
+
- More specific rules override less specific ones
|
|
199
|
+
- Multiple context files are typically concatenated (additive), not replaced
|
|
200
|
+
|
|
201
|
+
### 1.4 Frontmatter schemas
|
|
202
|
+
|
|
203
|
+
Some context file formats require or support YAML frontmatter (delimited by `---`). This metadata controls when and how the file is activated by the client.
|
|
204
|
+
|
|
205
|
+
#### Cursor `.mdc` files
|
|
206
|
+
|
|
207
|
+
```yaml
|
|
208
|
+
---
|
|
209
|
+
description: Brief description of when this rule applies
|
|
210
|
+
globs: "src/**/*.ts"
|
|
211
|
+
alwaysApply: false
|
|
212
|
+
---
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
| Field | Required | Type | Description |
|
|
216
|
+
|---|---|---|---|
|
|
217
|
+
| `description` | Yes | string | Tells Cursor when to apply this rule. |
|
|
218
|
+
| `globs` | No | string or string[] | File patterns that trigger this rule. e.g., `"src/**/*.ts"` or `["*.ts", "*.tsx"]` |
|
|
219
|
+
| `alwaysApply` | No | boolean | If `true`, rule is always active regardless of globs. |
|
|
220
|
+
|
|
221
|
+
If neither `globs` nor `alwaysApply` is set, the rule may not be applied automatically.
|
|
222
|
+
|
|
223
|
+
#### GitHub Copilot instruction files
|
|
224
|
+
|
|
225
|
+
```yaml
|
|
226
|
+
---
|
|
227
|
+
applyTo: "src/**/*.ts"
|
|
228
|
+
---
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
| Field | Required | Type | Description |
|
|
232
|
+
|---|---|---|---|
|
|
233
|
+
| `applyTo` | Recommended | string | Glob pattern specifying which files this instruction applies to. |
|
|
234
|
+
|
|
235
|
+
#### Windsurf rule files
|
|
236
|
+
|
|
237
|
+
```yaml
|
|
238
|
+
---
|
|
239
|
+
trigger: always_on
|
|
240
|
+
---
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
| Field | Required | Type | Description |
|
|
244
|
+
|---|---|---|---|
|
|
245
|
+
| `trigger` | Yes | enum | When the rule activates. One of: `always_on`, `glob`, `manual`, `model`. |
|
|
246
|
+
|
|
247
|
+
---
|
|
248
|
+
|
|
249
|
+
## 2. Content Extraction
|
|
250
|
+
|
|
251
|
+
Before lint rules can run, implementors must extract structured references from context file content. This section defines what to extract and how.
|
|
252
|
+
|
|
253
|
+
### 2.1 Path reference detection
|
|
254
|
+
|
|
255
|
+
Context files reference source paths (e.g., `src/auth/middleware.ts`, `config/*.yaml`). Implementors should extract these for validation.
|
|
256
|
+
|
|
257
|
+
**What counts as a path reference:**
|
|
258
|
+
- Forward-slash-separated segments with at least one directory separator: `src/utils/helper.ts`
|
|
259
|
+
- Relative paths: `./scripts/build.sh`, `../shared/types.ts`
|
|
260
|
+
- Glob patterns: `src/**/*.test.ts`
|
|
261
|
+
- Directory references: `src/components/`
|
|
262
|
+
|
|
263
|
+
**What to exclude:**
|
|
264
|
+
- URLs: `https://example.com/path`
|
|
265
|
+
- Version patterns: `v2.0/api`
|
|
266
|
+
- Common abbreviations: `n/a`, `I/O`, `e.g.`, `w/o`
|
|
267
|
+
- Archive extensions: `.deb/`, `.rpm/`, `.tar/`, `.zip/`
|
|
268
|
+
- Code inside language-tagged code blocks (```js, ```python, etc.) — these are examples, not project references
|
|
269
|
+
|
|
270
|
+
**Track per reference:** the path string, line number, column, and parent section heading (if any).
|
|
271
|
+
|
|
272
|
+
### 2.2 Command reference detection
|
|
273
|
+
|
|
274
|
+
Context files reference build and test commands (e.g., `npm run build`, `make test`). Implementors should extract these for validation.
|
|
275
|
+
|
|
276
|
+
**What counts as a command reference:**
|
|
277
|
+
- Lines prefixed with `$` or `>` followed by a command: `$ npm test`
|
|
278
|
+
- Content inside bash/shell/sh/zsh code blocks (or code blocks with no language specified)
|
|
279
|
+
- Inline backtick commands matching common command patterns
|
|
280
|
+
|
|
281
|
+
**Common command patterns to recognize:**
|
|
282
|
+
- Package manager scripts: `npm run`, `pnpm`, `yarn`, `bun`
|
|
283
|
+
- Build tools: `make`, `cargo`, `go build`, `go test`
|
|
284
|
+
- Test runners: `vitest`, `jest`, `pytest`, `mocha`
|
|
285
|
+
- Other tools: `npx`, `python`, `tsc`, `eslint`, `prettier`, `deno`
|
|
286
|
+
|
|
287
|
+
**Track per reference:** the command string, line number, column, and parent section heading.
|
|
288
|
+
|
|
289
|
+
### 2.3 Token counting
|
|
290
|
+
|
|
291
|
+
Context files consume an agent's context window. Counting tokens helps teams understand and optimize their context budget.
|
|
292
|
+
|
|
293
|
+
**Recommended approach:** Use the `cl100k_base` tokenizer (GPT-4 family). If unavailable, estimate at ~4 characters per token.
|
|
294
|
+
|
|
295
|
+
**Track per file:** total token count and total line count.
|
|
296
|
+
|
|
297
|
+
---
|
|
298
|
+
|
|
299
|
+
## 3. Lint Rules
|
|
300
|
+
|
|
301
|
+
19 rules organized into 7 categories.
|
|
302
|
+
|
|
303
|
+
Severity levels:
|
|
304
|
+
- **error** — the context file has a verifiably incorrect reference or invalid metadata. Should fail CI.
|
|
305
|
+
- **warning** — the context file has a likely problem worth investigating. May fail CI in strict mode.
|
|
306
|
+
- **info** — the context file has a potential improvement. Never fails CI.
|
|
307
|
+
|
|
308
|
+
### 3.1 paths — file reference validation
|
|
309
|
+
|
|
310
|
+
Validates that file paths referenced in context files exist in the project.
|
|
311
|
+
|
|
312
|
+
| Rule ID | Severity | Trigger | Message |
|
|
313
|
+
|---|---|---|---|
|
|
314
|
+
| `paths/not-found` | error | Referenced file or directory does not exist at the specified path | `{path} does not exist` |
|
|
315
|
+
| `paths/glob-no-match` | error | Glob pattern matches zero files | `{pattern} matches no files` |
|
|
316
|
+
| `paths/directory-not-found` | error | Referenced directory (path ending with `/`) does not exist | `{path} directory does not exist` |
|
|
317
|
+
|
|
318
|
+
**Suggestions:** When a path doesn't exist, implementors should:
|
|
319
|
+
1. Check git history for recent renames of the file (e.g., last 10 commits). If found: `Did you mean {newPath}? (renamed {N} days ago)`
|
|
320
|
+
2. Use fuzzy matching (Levenshtein distance) against existing project files. Threshold: `max(pathLength * 0.4, 5)`. If a match is found: `Did you mean {closestMatch}?`
|
|
321
|
+
|
|
322
|
+
**Auto-fixable:** `paths/not-found` — when a suggestion is available (via git rename or fuzzy match), replace the broken path with the suggested correction.
|
|
323
|
+
|
|
324
|
+
### 3.2 commands — build/script validation
|
|
325
|
+
|
|
326
|
+
Validates that commands referenced in context files are actually available in the project.
|
|
327
|
+
|
|
328
|
+
| Rule ID | Severity | Trigger | Message |
|
|
329
|
+
|---|---|---|---|
|
|
330
|
+
| `commands/script-not-found` | error | `npm run`, `pnpm`, `yarn`, or `bun` script name is not in `package.json#scripts` | `"{cmd}" — script "{name}" not found in package.json` |
|
|
331
|
+
| `commands/make-target-not-found` | error | `make` target is not in Makefile | `"{cmd}" — target "{name}" not found in Makefile` |
|
|
332
|
+
| `commands/no-makefile` | error | `make` command used but no Makefile exists | `"{cmd}" — no Makefile found in project` |
|
|
333
|
+
| `commands/npx-not-in-deps` | warning | `npx` package is not in dependencies or `node_modules/.bin` | `"{cmd}" — "{pkg}" not found in dependencies` |
|
|
334
|
+
| `commands/tool-not-found` | warning | Common tool (`vitest`, `jest`, `eslint`, etc.) is not in dependencies or `node_modules/.bin` | `"{cmd}" — "{tool}" not found in dependencies or node_modules/.bin` |
|
|
335
|
+
|
|
336
|
+
**Notes:**
|
|
337
|
+
- For `script-not-found`, include available scripts in the suggestion when possible.
|
|
338
|
+
- For `npx-not-in-deps`, suggest adding to `devDependencies`.
|
|
339
|
+
- Shorthand commands (`npm test`, `pnpm build`) should be validated against scripts as well.
|
|
340
|
+
|
|
341
|
+
### 3.3 staleness — freshness detection
|
|
342
|
+
|
|
343
|
+
Detects context files that haven't been updated while their referenced code has changed. Requires git.
|
|
344
|
+
|
|
345
|
+
| Rule ID | Severity | Trigger | Message |
|
|
346
|
+
|---|---|---|---|
|
|
347
|
+
| `staleness/stale` | warning | Context file not updated in 30+ days AND referenced paths have commits since last update | `Last updated {days} days ago. {path} has {N} commits since.` |
|
|
348
|
+
| `staleness/aging` | info | Context file not updated in 14-30 days AND referenced paths have commits | Same format as above |
|
|
349
|
+
|
|
350
|
+
**Algorithm:**
|
|
351
|
+
1. Get the context file's last modification date from git history
|
|
352
|
+
2. For each path referenced in the file, count commits to that path since the file's last update
|
|
353
|
+
3. If there are commits to referenced paths and the file is old enough, flag it
|
|
354
|
+
|
|
355
|
+
**Thresholds:**
|
|
356
|
+
- Skip entirely if file was updated within 14 days
|
|
357
|
+
- `info` at 14-30 days with referenced path activity
|
|
358
|
+
- `warning` at 30+ days with referenced path activity
|
|
359
|
+
|
|
360
|
+
**Suggestion:** `Review and update this context file to reflect recent changes.`
|
|
361
|
+
|
|
362
|
+
### 3.4 tokens — context window budget
|
|
363
|
+
|
|
364
|
+
Monitors context file size to help teams manage context window consumption.
|
|
365
|
+
|
|
366
|
+
| Rule ID | Severity | Trigger | Message |
|
|
367
|
+
|---|---|---|---|
|
|
368
|
+
| `tokens/excessive` | error | Single file uses 8000+ tokens | `{N} tokens — consumes significant context window space` |
|
|
369
|
+
| `tokens/large` | warning | Single file uses 3000-7999 tokens | `{N} tokens — large context file` |
|
|
370
|
+
| `tokens/info` | info | Single file uses 1000-2999 tokens | `Uses ~{N} tokens per session` |
|
|
371
|
+
| `tokens/aggregate` | warning | All context files combined use 5000+ tokens AND there are multiple files | `{count} context files consume {N} tokens combined` |
|
|
372
|
+
|
|
373
|
+
**Default thresholds (configurable):**
|
|
374
|
+
|
|
375
|
+
| Threshold | Default | Description |
|
|
376
|
+
|---|---|---|
|
|
377
|
+
| `info` | 1000 | Per-file informational |
|
|
378
|
+
| `warning` | 3000 | Per-file warning |
|
|
379
|
+
| `error` | 8000 | Per-file error |
|
|
380
|
+
| `aggregate` | 5000 | Cross-file combined warning |
|
|
381
|
+
|
|
382
|
+
**Suggestions:**
|
|
383
|
+
- For `excessive`: `Consider splitting into focused sections or removing redundant content.`
|
|
384
|
+
- For `large`: `Consider trimming — research shows diminishing returns past ~300 lines.`
|
|
385
|
+
- For `aggregate`: `Consider consolidating or trimming to reduce per-session context cost.`
|
|
386
|
+
|
|
387
|
+
### 3.5 redundancy — inferable content
|
|
388
|
+
|
|
389
|
+
Detects content that the agent can already infer from project metadata, reducing unnecessary context window consumption.
|
|
390
|
+
|
|
391
|
+
| Rule ID | Severity | Trigger | Message |
|
|
392
|
+
|---|---|---|---|
|
|
393
|
+
| `redundancy/tech-mention` | info | Context file explicitly mentions a technology that is already in `package.json` dependencies | `"{tech}" is in package.json {depType} — agent can infer this` |
|
|
394
|
+
| `redundancy/discoverable-dir` | info | Context file describes the location of a directory that exists and is trivially discoverable | `Directory "{dir}" exists and is discoverable — agent can find this by listing files` |
|
|
395
|
+
| `redundancy/duplicate-content` | warning | Two context files have 60%+ content overlap (by line) | `{file1} and {file2} have {N}% content overlap` |
|
|
396
|
+
|
|
397
|
+
**Technology detection patterns:**
|
|
398
|
+
|
|
399
|
+
When a package is in `dependencies` or `devDependencies`, flag context that explicitly states the project uses it. Match phrases like:
|
|
400
|
+
- `"use {tech}"`, `"using {tech}"`, `"built with {tech}"`
|
|
401
|
+
- `"we use {tech}"`, `"This is a {tech} project"`
|
|
402
|
+
- `"{tech} project"`, `"{tech} application"`
|
|
403
|
+
|
|
404
|
+
**Known package-to-technology mappings (partial list):**
|
|
405
|
+
|
|
406
|
+
| Package | Technology names to flag |
|
|
407
|
+
|---|---|
|
|
408
|
+
| `react` | React |
|
|
409
|
+
| `next` | Next.js, NextJS |
|
|
410
|
+
| `express` | Express |
|
|
411
|
+
| `fastify` | Fastify |
|
|
412
|
+
| `typescript` | TypeScript |
|
|
413
|
+
| `vue` | Vue, Vue.js |
|
|
414
|
+
| `angular` | Angular |
|
|
415
|
+
| `svelte` | Svelte, SvelteKit |
|
|
416
|
+
| `tailwindcss` | Tailwind, TailwindCSS |
|
|
417
|
+
| `prisma` | Prisma |
|
|
418
|
+
| `drizzle-orm` | Drizzle |
|
|
419
|
+
| `jest` | Jest |
|
|
420
|
+
| `vitest` | Vitest |
|
|
421
|
+
| `vite` | Vite |
|
|
422
|
+
| `webpack` | Webpack |
|
|
423
|
+
| `eslint` | ESLint |
|
|
424
|
+
| `prettier` | Prettier |
|
|
425
|
+
| `graphql` | GraphQL |
|
|
426
|
+
| `pg`, `postgres` | PostgreSQL, Postgres |
|
|
427
|
+
| `mysql2` | MySQL |
|
|
428
|
+
| `sqlite3`, `better-sqlite3` | SQLite |
|
|
429
|
+
| `redis`, `ioredis` | Redis |
|
|
430
|
+
| `mongoose` | Mongoose |
|
|
431
|
+
| `zod` | Zod |
|
|
432
|
+
| `axios` | Axios |
|
|
433
|
+
| `playwright` | Playwright |
|
|
434
|
+
| `cypress` | Cypress |
|
|
435
|
+
| `storybook` | Storybook |
|
|
436
|
+
|
|
437
|
+
Implementations should maintain and extend this mapping as the ecosystem evolves.
|
|
438
|
+
|
|
439
|
+
**Suggestion for `tech-mention`:** `~{N} tokens could be saved` (estimate tokens on the matching line).
|
|
440
|
+
|
|
441
|
+
**Suggestion for `duplicate-content`:** `Consider consolidating into a single context file.`
|
|
442
|
+
|
|
443
|
+
### 3.6 contradictions — cross-file conflicts
|
|
444
|
+
|
|
445
|
+
Detects conflicting directives across multiple context files. This is a cross-file check.
|
|
446
|
+
|
|
447
|
+
| Rule ID | Severity | Trigger | Message |
|
|
448
|
+
|---|---|---|---|
|
|
449
|
+
| `contradictions/conflict` | warning | Two context files specify different, mutually exclusive options in the same category | `{category} conflict: "{optionA}" in {fileA} vs "{optionB}" in {fileB}` |
|
|
450
|
+
|
|
451
|
+
**Contradiction categories and their mutually exclusive options:**
|
|
452
|
+
|
|
453
|
+
#### Testing framework
|
|
454
|
+
| Option | Example directives |
|
|
455
|
+
|---|---|
|
|
456
|
+
| Jest | "use Jest", "Jest for testing", "test with Jest" |
|
|
457
|
+
| Vitest | "use Vitest", "Vitest for testing", "test with Vitest" |
|
|
458
|
+
| Mocha | "use Mocha", "Mocha for testing" |
|
|
459
|
+
| pytest | "use pytest", "pytest for testing" |
|
|
460
|
+
| Playwright | "use Playwright", "Playwright for e2e" |
|
|
461
|
+
| Cypress | "use Cypress", "Cypress for e2e" |
|
|
462
|
+
|
|
463
|
+
#### Package manager
|
|
464
|
+
| Option | Example directives |
|
|
465
|
+
|---|---|
|
|
466
|
+
| npm | "use npm", "npm as the package manager", "always use npm" |
|
|
467
|
+
| pnpm | "use pnpm", "pnpm as the package manager" |
|
|
468
|
+
| yarn | "use yarn", "yarn as the package manager" |
|
|
469
|
+
| bun | "use bun", "bun as the package manager" |
|
|
470
|
+
|
|
471
|
+
#### Indentation style
|
|
472
|
+
| Option | Example directives |
|
|
473
|
+
|---|---|
|
|
474
|
+
| tabs | "use tabs", "tab indentation", "indent with tabs" |
|
|
475
|
+
| 2 spaces | "2-space indent", "indent with 2 spaces" |
|
|
476
|
+
| 4 spaces | "4-space indent", "indent with 4 spaces" |
|
|
477
|
+
|
|
478
|
+
#### Semicolons
|
|
479
|
+
| Option | Example directives |
|
|
480
|
+
|---|---|
|
|
481
|
+
| semicolons | "use semicolons", "always semicolons" |
|
|
482
|
+
| no semicolons | "no semicolons", "avoid semicolons", "omit semicolons" |
|
|
483
|
+
|
|
484
|
+
#### Quote style
|
|
485
|
+
| Option | Example directives |
|
|
486
|
+
|---|---|
|
|
487
|
+
| single quotes | "single quotes", "prefer single quotes" |
|
|
488
|
+
| double quotes | "double quotes", "prefer double quotes" |
|
|
489
|
+
|
|
490
|
+
#### Naming convention
|
|
491
|
+
| Option | Example directives |
|
|
492
|
+
|---|---|
|
|
493
|
+
| camelCase | "camelCase", "camel case for naming" |
|
|
494
|
+
| snake_case | "snake_case", "snake case for naming" |
|
|
495
|
+
| PascalCase | "PascalCase", "pascal case for naming" |
|
|
496
|
+
| kebab-case | "kebab-case", "kebab case for naming" |
|
|
497
|
+
|
|
498
|
+
#### CSS approach
|
|
499
|
+
| Option | Example directives |
|
|
500
|
+
|---|---|
|
|
501
|
+
| Tailwind | "use Tailwind", "Tailwind for styling" |
|
|
502
|
+
| CSS Modules | "use CSS Modules", "CSS Modules for styling" |
|
|
503
|
+
| styled-components | "use styled-components" |
|
|
504
|
+
| CSS-in-JS | "use CSS-in-JS" |
|
|
505
|
+
|
|
506
|
+
#### State management
|
|
507
|
+
| Option | Example directives |
|
|
508
|
+
|---|---|
|
|
509
|
+
| Redux | "use Redux", "Redux for state" |
|
|
510
|
+
| Zustand | "use Zustand", "Zustand for state" |
|
|
511
|
+
| MobX | "use MobX", "MobX for state" |
|
|
512
|
+
| Jotai | "use Jotai", "Jotai for state" |
|
|
513
|
+
| Recoil | "use Recoil", "Recoil for state" |
|
|
514
|
+
|
|
515
|
+
**Notes:**
|
|
516
|
+
- Only flag contradictions *across* files. A single file contradicting itself is unusual and likely intentional (e.g., "use camelCase for variables, PascalCase for components").
|
|
517
|
+
- Include the exact line numbers and text from both files in the detail.
|
|
518
|
+
|
|
519
|
+
### 3.7 frontmatter — client metadata validation
|
|
520
|
+
|
|
521
|
+
Validates YAML frontmatter required by specific clients. Only applies to file formats that use frontmatter.
|
|
522
|
+
|
|
523
|
+
| Rule ID | Severity | Trigger | Message |
|
|
524
|
+
|---|---|---|---|
|
|
525
|
+
| `frontmatter/missing` | warning | File format requires frontmatter but none is present | `{format} file is missing frontmatter` |
|
|
526
|
+
| `frontmatter/missing-field` | warning | A required or recommended field is absent | `Missing "{field}" field in {format} frontmatter` |
|
|
527
|
+
| `frontmatter/invalid-value` | error | A field has an invalid value | `Invalid {field} value: "{value}"` |
|
|
528
|
+
| `frontmatter/no-activation` | info | File has frontmatter but no activation mechanism (no globs/alwaysApply/trigger) | `No activation field — rule may not be applied automatically` |
|
|
529
|
+
|
|
530
|
+
**Validation per format:**
|
|
531
|
+
|
|
532
|
+
| File type | Validated fields | Valid values |
|
|
533
|
+
|---|---|---|
|
|
534
|
+
| Cursor `.mdc` | `description` (required), `alwaysApply` (boolean), `globs` (pattern) | `alwaysApply`: `true` or `false` |
|
|
535
|
+
| Copilot `instructions/*.md` | `applyTo` (recommended) | Any glob pattern |
|
|
536
|
+
| Windsurf `rules/*.md` | `trigger` (required) | `always_on`, `glob`, `manual`, `model` |
|
|
537
|
+
|
|
538
|
+
---
|
|
539
|
+
|
|
540
|
+
## 4. Rule Catalog (machine-readable)
|
|
541
|
+
|
|
542
|
+
A machine-readable JSON catalog of all rules and supported context file formats is available at [`context-lint-rules.json`](./context-lint-rules.json).
|
|
543
|
+
|
|
544
|
+
The catalog enables:
|
|
545
|
+
- AI agents to understand what context files exist in a project and what rules apply
|
|
546
|
+
- Tool authors to import rule definitions and format definitions programmatically
|
|
547
|
+
- CI systems to configure which rules to enable/disable
|
|
548
|
+
- Documentation generators to stay in sync with the rule set
|
|
549
|
+
|
|
550
|
+
See the JSON file for the full schema.
|
|
551
|
+
|
|
552
|
+
---
|
|
553
|
+
|
|
554
|
+
## 5. Implementing This Specification
|
|
555
|
+
|
|
556
|
+
### Discovery
|
|
557
|
+
|
|
558
|
+
Scan the project root (and optionally subdirectories up to a configurable depth) for the file patterns listed in [Section 1.2](#12-supported-formats-by-client). Skip `node_modules`, `.git`, `dist`, `build`, and `vendor` directories.
|
|
559
|
+
|
|
560
|
+
Support custom additional patterns via configuration for project-specific files (e.g., `CONVENTIONS.md`).
|
|
561
|
+
|
|
562
|
+
### Parsing
|
|
563
|
+
|
|
564
|
+
For each discovered file:
|
|
565
|
+
1. Read the file content
|
|
566
|
+
2. Parse markdown headings into a section tree
|
|
567
|
+
3. Extract path references and command references (see [Section 2](#2-content-extraction))
|
|
568
|
+
4. Count tokens
|
|
569
|
+
5. Parse frontmatter if the format requires it
|
|
570
|
+
|
|
571
|
+
### Checking
|
|
572
|
+
|
|
573
|
+
Run per-file checks (paths, commands, staleness, tokens, redundancy, frontmatter) independently per file. These can be parallelized.
|
|
574
|
+
|
|
575
|
+
Run cross-file checks (aggregate tokens, duplicate content, contradictions) after all per-file parsing is complete. These need the full set of parsed files.
|
|
576
|
+
|
|
577
|
+
### Reporting
|
|
578
|
+
|
|
579
|
+
Rules use the `category/rule-id` naming convention (e.g., `paths/not-found`, `contradictions/conflict`). For SARIF output, map to rule IDs as `ctxlint/paths`, `ctxlint/commands`, etc.
|
|
580
|
+
|
|
581
|
+
Severity mapping for SARIF: `error` → `error`, `warning` → `warning`, `info` → `note`.
|
|
582
|
+
|
|
583
|
+
### Fixing
|
|
584
|
+
|
|
585
|
+
The only auto-fixable rule category is `paths/not-found` (when a suggestion is available). Apply surgical string replacements on the affected line without reformatting the rest of the file.
|
|
586
|
+
|
|
587
|
+
---
|
|
588
|
+
|
|
589
|
+
## 6. Contributing
|
|
590
|
+
|
|
591
|
+
This specification is maintained at [github.com/YawLabs/ctxlint](https://github.com/YawLabs/ctxlint).
|
|
592
|
+
|
|
593
|
+
To propose changes:
|
|
594
|
+
- **New rules:** Open an issue describing the rule, its severity, trigger condition, and rationale.
|
|
595
|
+
- **New context file formats:** As new AI clients emerge, submit a PR adding their file patterns, scoping behavior, and any frontmatter requirements to Section 1.
|
|
596
|
+
- **New contradiction categories:** Submit a PR with the category name, mutually exclusive options, and example directives.
|
|
597
|
+
- **Corrections:** Open an issue with evidence (client docs, source code, or reproduction).
|
|
598
|
+
|
|
599
|
+
### Versioning
|
|
600
|
+
|
|
601
|
+
This specification follows semver:
|
|
602
|
+
- **Patch** (1.0.x): Typo fixes, clarifications, no rule changes
|
|
603
|
+
- **Minor** (1.x.0): New rules, new formats, new contradiction categories
|
|
604
|
+
- **Major** (x.0.0): Rules removed or semantics changed in breaking ways
|
|
605
|
+
|
|
606
|
+
### Related specifications and tools
|
|
607
|
+
|
|
608
|
+
- [AAIF AGENTS.md](https://github.com/anthropics/agents-spec) — Linux Foundation standard for multi-agent context files
|
|
609
|
+
- [Model Context Protocol Specification](https://spec.modelcontextprotocol.io/) — the protocol that MCP server configs serve
|
|
610
|
+
- [MCP Server Configuration Linting Specification](./MCP_CONFIG_LINT_SPEC.md) — companion spec for linting MCP server configs
|
|
611
|
+
- [ctxlint](https://github.com/YawLabs/ctxlint) — reference implementation of both specifications
|
|
612
|
+
- [mcp-compliance](https://github.com/YawLabs/mcp-compliance) — tests MCP server behavior against the protocol spec
|
|
613
|
+
- [mcp.hosting](https://mcp.hosting) — managed MCP server hosting
|