@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.
@@ -0,0 +1,8 @@
1
+ - id: ctxlint
2
+ name: ctxlint
3
+ description: Lint AI agent context files against your actual codebase
4
+ entry: npx @yawlabs/ctxlint --strict
5
+ language: node
6
+ always_run: true
7
+ pass_filenames: false
8
+ types: [file]
@@ -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