@yawlabs/ctxlint 0.9.0 → 0.9.2
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/AGENT_SESSION_LINT_SPEC.md +27 -0
- package/CONTEXT_LINT_SPEC.md +23 -5
- package/README.md +109 -59
- package/action.yml +1 -1
- package/agent-session-lint-rules.json +10 -0
- package/context-lint-rules.json +40 -0
- package/dist/index.js +2651 -2113
- package/package.json +7 -8
|
@@ -46,6 +46,7 @@ This is the third pillar alongside context file linting (`CLAUDE.md`, `.cursorru
|
|
|
46
46
|
- [2.5 session/duplicate-memory](#25-sessionduplicate-memory)
|
|
47
47
|
- [2.6 session/consecutive-repeat](#26-sessionconsecutive-repeat)
|
|
48
48
|
- [2.7 session/cyclic-pattern](#27-sessioncyclic-pattern)
|
|
49
|
+
- [2.8 session/memory-index-overflow](#28-sessionmemory-index-overflow)
|
|
49
50
|
- [3. Rule Catalog (machine-readable)](#3-rule-catalog-machine-readable)
|
|
50
51
|
- [4. Implementing This Specification](#4-implementing-this-specification)
|
|
51
52
|
- [5. Contributing](#5-contributing)
|
|
@@ -312,6 +313,32 @@ Detects short repeating cycles of commands, indicating an agent stuck in a loop.
|
|
|
312
313
|
|
|
313
314
|
---
|
|
314
315
|
|
|
316
|
+
### 2.8 session/memory-index-overflow
|
|
317
|
+
|
|
318
|
+
Detects when `MEMORY.md` exceeds Claude Code's session-load cap. Claude Code loads the first 200 lines OR 25KB of `MEMORY.md` at session start — whichever comes first. Entries past the cap are silently dropped, so auto-memory pointers beyond that point are effectively invisible to the agent.
|
|
319
|
+
|
|
320
|
+
| Field | Value |
|
|
321
|
+
|---|---|
|
|
322
|
+
| **Rule ID** | `session/memory-index-overflow` |
|
|
323
|
+
| **Severity** | warning |
|
|
324
|
+
| **Trigger** | `~/.claude/projects/<encoded-project>/memory/MEMORY.md` exceeds 200 lines OR 25,600 bytes |
|
|
325
|
+
| **Message (lines)** | `MEMORY.md has <N> lines — only the first 200 are loaded. <excess> line(s) are effectively invisible.` |
|
|
326
|
+
| **Message (bytes)** | `MEMORY.md is <N> bytes — only the first 25,600 bytes are loaded. ~<excess> bytes are effectively invisible.` |
|
|
327
|
+
| **Source** | [code.claude.com/docs/en/memory](https://code.claude.com/docs/en/memory) |
|
|
328
|
+
|
|
329
|
+
**Detection algorithm:**
|
|
330
|
+
|
|
331
|
+
1. Resolve `MEMORY.md` via the Claude-encoded project directory: `~/.claude/projects/<encode(currentProject)>/memory/MEMORY.md`.
|
|
332
|
+
2. If the file doesn't exist, no-op.
|
|
333
|
+
3. Count lines and bytes. Emit a warning for each dimension that exceeds its cap.
|
|
334
|
+
|
|
335
|
+
**Notes:**
|
|
336
|
+
- Each MEMORY.md entry should stay under ~150 characters (one-line pointer, not content).
|
|
337
|
+
- The remediation is to trim older entries, consolidate duplicates, or move detail into the corresponding topic file — topic files stay on-demand and don't count toward the cap.
|
|
338
|
+
- Both line and byte caps can fire independently (a short file with very long lines trips the byte cap first; a long file with short lines trips the line cap first).
|
|
339
|
+
|
|
340
|
+
---
|
|
341
|
+
|
|
315
342
|
## 3. Rule Catalog (machine-readable)
|
|
316
343
|
|
|
317
344
|
A machine-readable JSON catalog of all rules is available at [`agent-session-lint-rules.json`](./agent-session-lint-rules.json).
|
package/CONTEXT_LINT_SPEC.md
CHANGED
|
@@ -380,13 +380,31 @@ Monitors context file size to help teams manage context window consumption.
|
|
|
380
380
|
| `warning` | 3000 | Per-file warning |
|
|
381
381
|
| `error` | 8000 | Per-file error |
|
|
382
382
|
| `aggregate` | 5000 | Cross-file combined warning |
|
|
383
|
+
| `tierBreakdown` | 1000 | Triggers `tier-tokens/section-breakdown` on an always-loaded file |
|
|
384
|
+
| `tierAggregate` | 4000 | Triggers `tier-tokens/aggregate` across always-loaded files |
|
|
385
|
+
|
|
386
|
+
### 3.5 tier-tokens — tier-aware token accounting
|
|
387
|
+
|
|
388
|
+
Reports token cost attributable to the **always-loaded** tier: files Claude Code (and similar agents) load into every session regardless of request. Complements `tokens` by surfacing which sections / files are costing budget every turn — and which inviolable rules need hook-based enforcement to actually bind.
|
|
389
|
+
|
|
390
|
+
"Always-loaded" basenames: `CLAUDE.md`, `CLAUDE.local.md`, `AGENTS.md`, `AGENTS.override.md`, `AGENT.md`, `GEMINI.md`, `.cursorrules`, `.windsurfrules`, `.clinerules`, `.aiderules`, `.continuerules`, `.rules`, `.goosehints`, `replit.md`, `.github/copilot-instructions.md`, `.junie/guidelines.md`, `.goose/instructions.md`. Rules files in `/rules/` directories are classified by frontmatter: if `paths:` is set they're path-scoped on-demand; otherwise they're always-loaded.
|
|
391
|
+
|
|
392
|
+
| Rule ID | Severity | Trigger | Message |
|
|
393
|
+
|---|---|---|---|
|
|
394
|
+
| `tier-tokens/section-breakdown` | info | Always-loaded file exceeds `tierBreakdown` tokens AND has H1/H2 sections | `{N} tokens loaded every session — heaviest top-level section(s): ...` |
|
|
395
|
+
| `tier-tokens/aggregate` | warning | Two or more always-loaded files combined exceed `tierAggregate` tokens | `{count} always-loaded files total {N} tokens — loaded every session` |
|
|
396
|
+
| `tier-tokens/hard-enforcement-missing` | info | Line in an always-loaded file uses inviolable framing (NEVER/ALWAYS/DO NOT/MUST NOT) with a backticked command, and no matching PreToolUse hook or `permissions.deny` entry exists in `.claude/settings.json` or `~/.claude/settings.json` | `Inviolable framing ("{line}") without a hook to back it up` |
|
|
397
|
+
|
|
398
|
+
**Note on overlap with `tokens`:** `tokens/info` and `tier-tokens/section-breakdown` both fire on a large CLAUDE.md. They're complementary — `tokens` is tier-agnostic ("this file is large"), `tier-tokens` adds the always-loaded attribution and demotion guidance. Use `--ignore tokens` or `--ignore tier-tokens` to pick one.
|
|
399
|
+
|
|
400
|
+
**Source:** [Claude Code memory docs](https://code.claude.com/docs/en/memory). Rule behavior is grounded in the documented loading model ("there's no guarantee of strict compliance" → hard-enforcement-missing; section-demotion-to-skills → structurally reduces per-session cost).
|
|
383
401
|
|
|
384
402
|
**Suggestions:**
|
|
385
403
|
- For `excessive`: `Consider splitting into focused sections or removing redundant content.`
|
|
386
404
|
- For `large`: `Consider trimming — research shows diminishing returns past ~300 lines.`
|
|
387
405
|
- For `aggregate`: `Consider consolidating or trimming to reduce per-session context cost.`
|
|
388
406
|
|
|
389
|
-
### 3.
|
|
407
|
+
### 3.6 redundancy — inferable content
|
|
390
408
|
|
|
391
409
|
Detects content that the agent can already infer from project metadata, reducing unnecessary context window consumption.
|
|
392
410
|
|
|
@@ -442,7 +460,7 @@ Implementations should maintain and extend this mapping as the ecosystem evolves
|
|
|
442
460
|
|
|
443
461
|
**Suggestion for `duplicate-content`:** `Consider consolidating into a single context file.`
|
|
444
462
|
|
|
445
|
-
### 3.
|
|
463
|
+
### 3.7 contradictions — cross-file conflicts
|
|
446
464
|
|
|
447
465
|
Detects conflicting directives across multiple context files. This is a cross-file check.
|
|
448
466
|
|
|
@@ -518,7 +536,7 @@ Detects conflicting directives across multiple context files. This is a cross-fi
|
|
|
518
536
|
- Only flag contradictions *across* files. A single file contradicting itself is unusual and likely intentional (e.g., "use camelCase for variables, PascalCase for components").
|
|
519
537
|
- Include the exact line numbers and text from both files in the detail.
|
|
520
538
|
|
|
521
|
-
### 3.
|
|
539
|
+
### 3.8 frontmatter — client metadata validation
|
|
522
540
|
|
|
523
541
|
Validates YAML frontmatter required by specific clients. Only applies to file formats that use frontmatter.
|
|
524
542
|
|
|
@@ -539,7 +557,7 @@ Validates YAML frontmatter required by specific clients. Only applies to file fo
|
|
|
539
557
|
|
|
540
558
|
---
|
|
541
559
|
|
|
542
|
-
### 3.
|
|
560
|
+
### 3.9 ci-coverage — CI workflow documentation
|
|
543
561
|
|
|
544
562
|
Checks that release/deploy CI workflows are documented in context files. When agents encounter a project with CI release workflows but no documentation about how releases work, they guess — often incorrectly.
|
|
545
563
|
|
|
@@ -558,7 +576,7 @@ Checks that release/deploy CI workflows are documented in context files. When ag
|
|
|
558
576
|
|
|
559
577
|
---
|
|
560
578
|
|
|
561
|
-
### 3.
|
|
579
|
+
### 3.10 ci-secrets — CI secrets documentation
|
|
562
580
|
|
|
563
581
|
Checks that secrets referenced in CI workflow files are mentioned in context files. Undocumented secrets are a common source of agent looping — agents try to create new tokens, pull from `.npmrc`, or guess at auth setup.
|
|
564
582
|
|
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
[](https://github.com/YawLabs/ctxlint/actions/workflows/ci.yml)
|
|
7
7
|
[](https://github.com/YawLabs/ctxlint/actions/workflows/release.yml)
|
|
8
8
|
|
|
9
|
-
**Lint your AI agent context files
|
|
9
|
+
**Lint your AI agent context files, MCP server configs, and session data against your actual codebase.** Context linting + MCP config linting + session auditing. 21+ context formats, 8 MCP clients, cross-project consistency, auto-fix. Works as a CLI, CI step, pre-commit hook, or MCP server.
|
|
10
10
|
|
|
11
11
|
Your `CLAUDE.md` is lying to your agent. Your `.mcp.json` has a hardcoded API key. ctxlint catches both.
|
|
12
12
|
|
|
@@ -66,38 +66,44 @@ Useful if you want `ctxlint` available in every project without per-project setu
|
|
|
66
66
|
|
|
67
67
|
## What It Checks
|
|
68
68
|
|
|
69
|
-
| Check
|
|
70
|
-
|
|
71
|
-
| **Broken paths**
|
|
72
|
-
| **Wrong commands**
|
|
73
|
-
| **Stale context**
|
|
74
|
-
| **Token waste**
|
|
75
|
-
| **Redundancy**
|
|
76
|
-
| **Contradictions**
|
|
77
|
-
| **Frontmatter**
|
|
78
|
-
| **CI coverage**
|
|
79
|
-
| **CI secrets**
|
|
69
|
+
| Check | What it finds |
|
|
70
|
+
| --------------------- | --------------------------------------------------------------------------------------------- |
|
|
71
|
+
| **Broken paths** | File references in context that don't exist in your project |
|
|
72
|
+
| **Wrong commands** | Build/test commands that don't match your package.json scripts or Makefile targets |
|
|
73
|
+
| **Stale context** | Context files not updated after recent code changes |
|
|
74
|
+
| **Token waste** | How much context window your files consume per session |
|
|
75
|
+
| **Redundancy** | Content the agent can already infer (e.g. "We use React" when react is in package.json) |
|
|
76
|
+
| **Contradictions** | Conflicting directives across context files (e.g. "use Jest" in one, "use Vitest" in another) |
|
|
77
|
+
| **Frontmatter** | Invalid or missing YAML frontmatter in Cursor .mdc, Copilot instructions, and Windsurf rules |
|
|
78
|
+
| **CI coverage** | Release/deploy workflows in `.github/workflows/` not documented in any context file |
|
|
79
|
+
| **CI secrets** | Secrets used in CI workflows (`${{ secrets.X }}`) not mentioned in context files |
|
|
80
|
+
| **Missing secrets** | GitHub secrets set on sibling repos but missing from current project |
|
|
81
|
+
| **Diverged configs** | Canonical config files (CI, tsconfig, etc.) drifting across sibling projects |
|
|
82
|
+
| **Missing workflows** | GitHub Actions workflows present in 2+ siblings but absent here |
|
|
83
|
+
| **Stale memory** | Claude Code memory entries referencing paths that no longer exist |
|
|
84
|
+
| **Duplicate memory** | Near-duplicate memories across projects (>60% content overlap) |
|
|
85
|
+
| **Loop detection** | Agent stuck in loops — repeated commands or cyclic patterns in session history |
|
|
80
86
|
|
|
81
87
|
## Supported Context Files
|
|
82
88
|
|
|
83
|
-
| File
|
|
84
|
-
|
|
85
|
-
| `CLAUDE.md`, `CLAUDE.local.md`, `.claude/rules/*.md`
|
|
86
|
-
| `AGENTS.md`, `AGENT.md`, `AGENTS.override.md`
|
|
87
|
-
| `.cursorrules`, `.cursor/rules/*.md`, `.cursor/rules/*.mdc`, `.cursor/rules/*/RULE.md`
|
|
88
|
-
| `.github/copilot-instructions.md`, `.github/instructions/*.md`, `.github/git-commit-instructions.md` | GitHub Copilot
|
|
89
|
-
| `.windsurfrules`, `.windsurf/rules/*.md`
|
|
90
|
-
| `GEMINI.md`
|
|
91
|
-
| `.clinerules`
|
|
92
|
-
| `.aiderules`
|
|
93
|
-
| `.aide/rules/*.md`
|
|
94
|
-
| `.amazonq/rules/*.md`
|
|
95
|
-
| `.goose/instructions.md`, `.goosehints`
|
|
96
|
-
| `.junie/guidelines.md`, `.junie/AGENTS.md`
|
|
97
|
-
| `.aiassistant/rules/*.md`
|
|
98
|
-
| `.continuerules`, `.continue/rules/*.md`
|
|
99
|
-
| `.rules`
|
|
100
|
-
| `replit.md`
|
|
89
|
+
| File | Tool |
|
|
90
|
+
| ---------------------------------------------------------------------------------------------------- | --------------------------- |
|
|
91
|
+
| `CLAUDE.md`, `CLAUDE.local.md`, `.claude/rules/*.md` | Claude Code |
|
|
92
|
+
| `AGENTS.md`, `AGENT.md`, `AGENTS.override.md` | AAIF / Multi-agent standard |
|
|
93
|
+
| `.cursorrules`, `.cursor/rules/*.md`, `.cursor/rules/*.mdc`, `.cursor/rules/*/RULE.md` | Cursor |
|
|
94
|
+
| `.github/copilot-instructions.md`, `.github/instructions/*.md`, `.github/git-commit-instructions.md` | GitHub Copilot |
|
|
95
|
+
| `.windsurfrules`, `.windsurf/rules/*.md` | Windsurf |
|
|
96
|
+
| `GEMINI.md` | Gemini CLI |
|
|
97
|
+
| `.clinerules` | Cline |
|
|
98
|
+
| `.aiderules` | Aider |
|
|
99
|
+
| `.aide/rules/*.md` | Aide / Codestory |
|
|
100
|
+
| `.amazonq/rules/*.md` | Amazon Q Developer |
|
|
101
|
+
| `.goose/instructions.md`, `.goosehints` | Goose by Block |
|
|
102
|
+
| `.junie/guidelines.md`, `.junie/AGENTS.md` | JetBrains Junie |
|
|
103
|
+
| `.aiassistant/rules/*.md` | JetBrains AI Assistant |
|
|
104
|
+
| `.continuerules`, `.continue/rules/*.md` | Continue |
|
|
105
|
+
| `.rules` | Zed |
|
|
106
|
+
| `replit.md` | Replit |
|
|
101
107
|
|
|
102
108
|
## MCP Server Config Linting
|
|
103
109
|
|
|
@@ -116,28 +122,28 @@ npx @yawlabs/ctxlint --mcp-global
|
|
|
116
122
|
|
|
117
123
|
### What MCP config files are scanned
|
|
118
124
|
|
|
119
|
-
| File
|
|
120
|
-
|
|
121
|
-
| `.mcp.json`
|
|
122
|
-
| `.cursor/mcp.json`
|
|
123
|
-
| `.vscode/mcp.json`
|
|
124
|
-
| `.amazonq/mcp.json`
|
|
125
|
-
| `.continue/mcpServers/*.json` | Continue
|
|
125
|
+
| File | Client |
|
|
126
|
+
| ----------------------------- | -------------------------------------- |
|
|
127
|
+
| `.mcp.json` | Claude Code (universal project config) |
|
|
128
|
+
| `.cursor/mcp.json` | Cursor |
|
|
129
|
+
| `.vscode/mcp.json` | VS Code / GitHub Copilot |
|
|
130
|
+
| `.amazonq/mcp.json` | Amazon Q Developer |
|
|
131
|
+
| `.continue/mcpServers/*.json` | Continue |
|
|
126
132
|
|
|
127
133
|
With `--mcp-global`, also scans Claude Desktop, Cursor, Windsurf, and Amazon Q global configs.
|
|
128
134
|
|
|
129
135
|
### What MCP config checks catch
|
|
130
136
|
|
|
131
|
-
| Check
|
|
132
|
-
|
|
133
|
-
| **Schema**
|
|
134
|
-
| **Security**
|
|
135
|
-
| **Commands**
|
|
136
|
-
| **Deprecated**
|
|
137
|
-
| **Env vars**
|
|
138
|
-
| **URLs**
|
|
139
|
-
| **Consistency** | Same server configured differently across client configs
|
|
140
|
-
| **Redundancy**
|
|
137
|
+
| Check | What it finds |
|
|
138
|
+
| --------------- | -------------------------------------------------------------------------------------- |
|
|
139
|
+
| **Schema** | Invalid JSON, wrong root key (`servers` vs `mcpServers`), missing required fields |
|
|
140
|
+
| **Security** | Hardcoded API keys and Bearer tokens in git-tracked config files |
|
|
141
|
+
| **Commands** | Missing `cmd /c` wrapper for npx on Windows, broken file paths in args |
|
|
142
|
+
| **Deprecated** | SSE transport usage (deprecated March 2025, use Streamable HTTP) |
|
|
143
|
+
| **Env vars** | Wrong env var syntax for the client (`${VAR}` vs `${env:VAR}` vs `${{ secrets.VAR }}`) |
|
|
144
|
+
| **URLs** | Malformed URLs, localhost in project configs, missing path component |
|
|
145
|
+
| **Consistency** | Same server configured differently across client configs |
|
|
146
|
+
| **Redundancy** | Disabled servers, identical configs at multiple scopes |
|
|
141
147
|
|
|
142
148
|
### Example MCP config output
|
|
143
149
|
|
|
@@ -168,10 +174,47 @@ The full specification for MCP config linting rules, the cross-client config lan
|
|
|
168
174
|
- **[`MCP_CONFIG_LINT_SPEC.md`](./MCP_CONFIG_LINT_SPEC.md)** — 23 lint rules across 8 categories, the complete client/format reference, and implementation guidance. Tool-agnostic — any linter can implement it.
|
|
169
175
|
- **[`mcp-config-lint-rules.json`](./mcp-config-lint-rules.json)** — Machine-readable rule catalog for programmatic consumption by AI agents, CI systems, and other tools.
|
|
170
176
|
|
|
177
|
+
## Session Linting
|
|
178
|
+
|
|
179
|
+
ctxlint can audit AI agent session data — history files and memory entries — for cross-project consistency. Session checks compare your current project against sibling repos to catch drift and missing setup.
|
|
180
|
+
|
|
181
|
+
```bash
|
|
182
|
+
# Lint context files + session data
|
|
183
|
+
npx @yawlabs/ctxlint --session
|
|
184
|
+
|
|
185
|
+
# Lint only session data
|
|
186
|
+
npx @yawlabs/ctxlint --session-only
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
Session checks are **opt-in** because they access files outside the project directory (agent history in your home directory, sibling repos in the parent directory).
|
|
190
|
+
|
|
191
|
+
### What session files are scanned
|
|
192
|
+
|
|
193
|
+
| Agent | History | Memory |
|
|
194
|
+
| ----------- | ------------------------- | ---------------------------------- |
|
|
195
|
+
| Claude Code | `~/.claude/history.jsonl` | `~/.claude/projects/*/memory/*.md` |
|
|
196
|
+
| Codex CLI | `~/.codex/history.jsonl` | — |
|
|
197
|
+
|
|
198
|
+
### What session checks catch
|
|
199
|
+
|
|
200
|
+
| Check | What it finds |
|
|
201
|
+
| --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
202
|
+
| **Missing secrets** | `gh secret set` ran on 2+ sibling repos but not this one |
|
|
203
|
+
| **Diverged configs** | Shared config files (CI workflows, tsconfig, .prettierrc, etc.) with 20-90% line overlap — enough to be related, different enough to be drifting |
|
|
204
|
+
| **Missing workflows** | GitHub Actions workflows in 2+ siblings but absent from this project |
|
|
205
|
+
| **Stale memory** | Memory entries referencing file paths that no longer exist |
|
|
206
|
+
| **Duplicate memory** | Near-duplicate memory entries across projects (>60% overlap) |
|
|
207
|
+
| **Loop detection** | Agent stuck in a loop — 3+ consecutive identical commands, or cyclic A,B,A,B patterns |
|
|
208
|
+
|
|
209
|
+
### Session Linting Specification
|
|
210
|
+
|
|
211
|
+
- **[`AGENT_SESSION_LINT_SPEC.md`](./AGENT_SESSION_LINT_SPEC.md)** — 7 lint rules, the agent session data landscape across 8 agents, sibling detection strategy, and implementation guidance.
|
|
212
|
+
- **[`agent-session-lint-rules.json`](./agent-session-lint-rules.json)** — Machine-readable rule catalog.
|
|
213
|
+
|
|
171
214
|
## Example Output
|
|
172
215
|
|
|
173
216
|
```
|
|
174
|
-
ctxlint v0.
|
|
217
|
+
ctxlint v0.9.0
|
|
175
218
|
|
|
176
219
|
Scanning /Users/you/my-app...
|
|
177
220
|
|
|
@@ -214,6 +257,8 @@ Options:
|
|
|
214
257
|
--mcp Enable MCP config linting alongside context file checks
|
|
215
258
|
--mcp-only Run only MCP config checks, skip context file checks
|
|
216
259
|
--mcp-global Also scan user/global MCP config files (implies --mcp)
|
|
260
|
+
--session Enable session audit checks (cross-project consistency)
|
|
261
|
+
--session-only Run only session checks, skip context and MCP checks
|
|
217
262
|
--mcp-server Start the MCP server (for IDE/agent integration)
|
|
218
263
|
--watch Re-lint on context file changes
|
|
219
264
|
-V, --version Output the version number
|
|
@@ -223,9 +268,9 @@ Commands:
|
|
|
223
268
|
init Set up a git pre-commit hook
|
|
224
269
|
```
|
|
225
270
|
|
|
226
|
-
**Available checks:** `paths`, `commands`, `staleness`, `tokens`, `redundancy`, `contradictions`, `frontmatter`, `ci-coverage`, `ci-secrets`, `mcp-schema`, `mcp-security`, `mcp-commands`, `mcp-deprecated`, `mcp-env`, `mcp-urls`, `mcp-consistency`, `mcp-redundancy`
|
|
271
|
+
**Available checks:** `paths`, `commands`, `staleness`, `tokens`, `tier-tokens`, `redundancy`, `contradictions`, `frontmatter`, `ci-coverage`, `ci-secrets`, `mcp-schema`, `mcp-security`, `mcp-commands`, `mcp-deprecated`, `mcp-env`, `mcp-urls`, `mcp-consistency`, `mcp-redundancy`, `session-missing-secret`, `session-diverged-file`, `session-missing-workflow`, `session-stale-memory`, `session-duplicate-memory`, `session-loop-detection`, `session-memory-index-overflow`
|
|
227
272
|
|
|
228
|
-
Passing any `mcp-*` check name implies `--mcp`.
|
|
273
|
+
Passing any `mcp-*` check name implies `--mcp`. Passing any `session-*` check name implies `--session`.
|
|
229
274
|
|
|
230
275
|
## Watch Mode
|
|
231
276
|
|
|
@@ -297,7 +342,7 @@ Add to your `.pre-commit-config.yaml`:
|
|
|
297
342
|
```yaml
|
|
298
343
|
repos:
|
|
299
344
|
- repo: https://github.com/yawlabs/ctxlint
|
|
300
|
-
rev: v0.
|
|
345
|
+
rev: v0.9.0
|
|
301
346
|
hooks:
|
|
302
347
|
- id: ctxlint
|
|
303
348
|
```
|
|
@@ -315,7 +360,9 @@ Create a `.ctxlintrc` or `.ctxlintrc.json` in your project root:
|
|
|
315
360
|
"info": 500,
|
|
316
361
|
"warning": 2000,
|
|
317
362
|
"error": 5000,
|
|
318
|
-
"aggregate": 4000
|
|
363
|
+
"aggregate": 4000,
|
|
364
|
+
"tierBreakdown": 1000,
|
|
365
|
+
"tierAggregate": 4000
|
|
319
366
|
},
|
|
320
367
|
"contextFiles": ["CONVENTIONS.md", "docs/ai-rules.md"]
|
|
321
368
|
}
|
|
@@ -327,7 +374,7 @@ CLI flags override config file settings. Use `--config <path>` to load a config
|
|
|
327
374
|
|
|
328
375
|
## Use as MCP Server
|
|
329
376
|
|
|
330
|
-
ctxlint ships with an MCP server that exposes
|
|
377
|
+
ctxlint ships with an MCP server that exposes six tools (`ctxlint_audit`, `ctxlint_mcp_audit`, `ctxlint_session_audit`, `ctxlint_validate_path`, `ctxlint_token_report`, `ctxlint_fix`). All read-only tools declare annotations so MCP clients can skip confirmation dialogs.
|
|
331
378
|
|
|
332
379
|
### With Claude Code
|
|
333
380
|
|
|
@@ -407,16 +454,19 @@ Returns structured JSON with all file results, issues, and summary — useful fo
|
|
|
407
454
|
|
|
408
455
|
## Specifications
|
|
409
456
|
|
|
410
|
-
ctxlint is the reference implementation of
|
|
457
|
+
ctxlint is the reference implementation of three open specifications for linting AI agent interfaces. These specs are tool-agnostic — any linter, IDE extension, or CI system can implement them.
|
|
458
|
+
|
|
459
|
+
| Spec | What it covers |
|
|
460
|
+
| -------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
461
|
+
| **[AI Context File Linting Spec](./CONTEXT_LINT_SPEC.md)** | 19 rules for validating context files (CLAUDE.md, .cursorrules, AGENTS.md, etc.) across 17 clients. Covers file formats, frontmatter schemas, path/command validation, staleness, token budgets, redundancy, and contradictions. |
|
|
462
|
+
| **[MCP Config Linting Spec](./MCP_CONFIG_LINT_SPEC.md)** | 23 rules for validating MCP server configs (.mcp.json, .cursor/mcp.json, .vscode/mcp.json, etc.) across 8 clients. Covers schema validation, hardcoded secrets, env var syntax, deprecated transports, and cross-file consistency. |
|
|
463
|
+
| **[Agent Session Linting Spec](./AGENT_SESSION_LINT_SPEC.md)** | 7 rules for auditing agent session data (history, memory) across 8 agents. Covers cross-project secret consistency, config drift, stale memory, and loop detection. |
|
|
411
464
|
|
|
412
|
-
|
|
413
|
-
|------|---------------|
|
|
414
|
-
| **[AI Context File Linting Spec](./CONTEXT_LINT_SPEC.md)** | 19 rules for validating context files (CLAUDE.md, .cursorrules, AGENTS.md, etc.) across 17 clients. Covers file formats, frontmatter schemas, path/command validation, staleness, token budgets, redundancy, and contradictions. |
|
|
415
|
-
| **[MCP Config Linting Spec](./MCP_CONFIG_LINT_SPEC.md)** | 23 rules for validating MCP server configs (.mcp.json, .cursor/mcp.json, .vscode/mcp.json, etc.) across 8 clients. Covers schema validation, hardcoded secrets, env var syntax, deprecated transports, and cross-file consistency. |
|
|
465
|
+
All specs include machine-readable rule catalogs for programmatic consumption:
|
|
416
466
|
|
|
417
|
-
Both specs include machine-readable rule catalogs for programmatic consumption:
|
|
418
467
|
- [`context-lint-rules.json`](./context-lint-rules.json) — context file rules and 16 supported format definitions
|
|
419
468
|
- [`mcp-config-lint-rules.json`](./mcp-config-lint-rules.json) — MCP config rules and 8 client definitions
|
|
469
|
+
- [`agent-session-lint-rules.json`](./agent-session-lint-rules.json) — session lint rules and 8 agent data source definitions
|
|
420
470
|
|
|
421
471
|
## Also By Yaw Labs
|
|
422
472
|
|
package/action.yml
CHANGED
|
@@ -86,6 +86,16 @@
|
|
|
86
86
|
"trigger": "Agent history shows a repeating sequence of 2-3 commands (e.g. A,B,A,B) repeated 2+ times.",
|
|
87
87
|
"message": "Cyclic pattern repeated {count} times: {cycle}",
|
|
88
88
|
"fixable": false
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
"id": "session/memory-index-overflow",
|
|
92
|
+
"category": "session",
|
|
93
|
+
"severity": "warning",
|
|
94
|
+
"description": "MEMORY.md exceeds Claude Code's session-load cap. The first 200 lines / 25KB are loaded every session; anything beyond is effectively invisible to the agent.",
|
|
95
|
+
"trigger": "~/.claude/projects/<encoded-project>/memory/MEMORY.md exceeds 200 lines OR 25,600 bytes.",
|
|
96
|
+
"message": "MEMORY.md has {N} lines — only the first 200 are loaded. {excess} lines are effectively invisible.",
|
|
97
|
+
"fixable": false,
|
|
98
|
+
"source": "code.claude.com/docs/en/memory"
|
|
89
99
|
}
|
|
90
100
|
],
|
|
91
101
|
"dataSources": [
|
package/context-lint-rules.json
CHANGED
|
@@ -29,6 +29,12 @@
|
|
|
29
29
|
"description": "Monitors context file size to help teams manage context window consumption.",
|
|
30
30
|
"scope": "per-file and cross-file"
|
|
31
31
|
},
|
|
32
|
+
{
|
|
33
|
+
"id": "tier-tokens",
|
|
34
|
+
"name": "Tier-Aware Token Accounting",
|
|
35
|
+
"description": "Reports per-section token cost for always-loaded context files and flags demotion candidates for on-demand tiers (skills, subagents, memory).",
|
|
36
|
+
"scope": "per-file"
|
|
37
|
+
},
|
|
32
38
|
{
|
|
33
39
|
"id": "redundancy",
|
|
34
40
|
"name": "Inferable Content",
|
|
@@ -196,6 +202,40 @@
|
|
|
196
202
|
"configurable": true,
|
|
197
203
|
"defaultThreshold": 5000
|
|
198
204
|
},
|
|
205
|
+
{
|
|
206
|
+
"id": "tier-tokens/section-breakdown",
|
|
207
|
+
"category": "tier-tokens",
|
|
208
|
+
"severity": "info",
|
|
209
|
+
"description": "Reports the heaviest top-level sections in an always-loaded context file and suggests demoting the largest to an on-demand tier (skill, subagent, or memory).",
|
|
210
|
+
"trigger": "An always-loaded context file (CLAUDE.md, AGENTS.md, .cursorrules, etc. — excluding path-scoped rules files) exceeds the tierBreakdown threshold (default 1000 tokens) and contains H1 or H2 sections.",
|
|
211
|
+
"message": "{N} tokens loaded every session — heaviest top-level section(s): ...",
|
|
212
|
+
"fixable": false,
|
|
213
|
+
"configurable": true,
|
|
214
|
+
"configKey": "tokenThresholds.tierBreakdown",
|
|
215
|
+
"defaultThreshold": 1000
|
|
216
|
+
},
|
|
217
|
+
{
|
|
218
|
+
"id": "tier-tokens/aggregate",
|
|
219
|
+
"category": "tier-tokens",
|
|
220
|
+
"severity": "warning",
|
|
221
|
+
"description": "Combined token cost of always-loaded context files exceeds the recommended budget.",
|
|
222
|
+
"trigger": "Two or more always-loaded files total more than the tierAggregate threshold (default 4000 tokens).",
|
|
223
|
+
"message": "{count} always-loaded files total {N} tokens — loaded every session",
|
|
224
|
+
"fixable": false,
|
|
225
|
+
"configurable": true,
|
|
226
|
+
"configKey": "tokenThresholds.tierAggregate",
|
|
227
|
+
"defaultThreshold": 4000
|
|
228
|
+
},
|
|
229
|
+
{
|
|
230
|
+
"id": "tier-tokens/hard-enforcement-missing",
|
|
231
|
+
"category": "tier-tokens",
|
|
232
|
+
"severity": "info",
|
|
233
|
+
"description": "An always-loaded file uses inviolable framing (NEVER / ALWAYS / DO NOT / MUST NOT) paired with a concrete command, but no corresponding PreToolUse hook or permissions.deny entry exists in settings.json. Rules in always-loaded files are advisory — without a hook the agent may still run the command.",
|
|
234
|
+
"trigger": "Line in an always-loaded file matches NEVER|ALWAYS|DO NOT|MUST NOT with a backticked command, and .claude/settings.json / ~/.claude/settings.json does not contain a matching PreToolUse hook or permissions.deny entry.",
|
|
235
|
+
"message": "Inviolable framing without a hook to back it up",
|
|
236
|
+
"fixable": false,
|
|
237
|
+
"source": "code.claude.com/docs/en/hooks-guide"
|
|
238
|
+
},
|
|
199
239
|
{
|
|
200
240
|
"id": "redundancy/tech-mention",
|
|
201
241
|
"category": "redundancy",
|