@yawlabs/ctxlint 0.5.0 → 0.7.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,157 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "title": "AI Agent Session Lint Rules",
4
+ "description": "Machine-readable catalog of lint rules for AI agent session data cross-project consistency",
5
+ "specVersion": "1.0.0-draft",
6
+ "specDate": "2026-04-08",
7
+ "repository": "https://github.com/YawLabs/ctxlint",
8
+ "categories": [
9
+ {
10
+ "id": "session",
11
+ "name": "Session Audit",
12
+ "description": "Cross-project consistency checks using AI agent session data.",
13
+ "scope": "cross-project"
14
+ }
15
+ ],
16
+ "rules": [
17
+ {
18
+ "id": "session/missing-secret",
19
+ "category": "session",
20
+ "severity": "error",
21
+ "description": "GitHub secret set on sibling repos but not this project.",
22
+ "trigger": "gh secret set command found in agent history for 2+ siblings but not current project.",
23
+ "message": "Secret \"{name}\" is set on {count} sibling repos but not this project",
24
+ "fixable": false
25
+ },
26
+ {
27
+ "id": "session/diverged-file",
28
+ "category": "session",
29
+ "severity": "warning",
30
+ "description": "Canonical file has diverged from sibling repos.",
31
+ "trigger": "File exists in current project and siblings with 20-90% line overlap.",
32
+ "message": "\"{file}\" has {overlap}% overlap with {sibling} — may have diverged",
33
+ "fixable": false,
34
+ "canonicalFiles": [
35
+ "release.sh",
36
+ ".github/workflows/ci.yml",
37
+ ".github/workflows/release.yml",
38
+ "biome.json",
39
+ ".prettierrc",
40
+ ".eslintrc.json",
41
+ "tsconfig.json",
42
+ ".gitignore"
43
+ ]
44
+ },
45
+ {
46
+ "id": "session/missing-workflow",
47
+ "category": "session",
48
+ "severity": "warning",
49
+ "description": "GitHub Actions workflow missing from this project.",
50
+ "trigger": "Workflow file exists in 2+ siblings but not current project (which has .github).",
51
+ "message": "Workflow \"{workflow}\" exists in {count} sibling repos but not this project",
52
+ "fixable": false
53
+ },
54
+ {
55
+ "id": "session/stale-memory",
56
+ "category": "session",
57
+ "severity": "info",
58
+ "description": "Memory file references paths that no longer exist.",
59
+ "trigger": "Claude Code memory file contains path references to files that have been deleted or moved.",
60
+ "message": "Memory references \"{path}\" which no longer exists",
61
+ "fixable": false
62
+ },
63
+ {
64
+ "id": "session/duplicate-memory",
65
+ "category": "session",
66
+ "severity": "info",
67
+ "description": "Near-duplicate memory entries across projects.",
68
+ "trigger": "Two memory files from different projects have >60% line overlap.",
69
+ "message": "\"{file1}\" and \"{file2}\" have {overlap}% content overlap",
70
+ "fixable": false
71
+ }
72
+ ],
73
+ "dataSources": [
74
+ {
75
+ "id": "claude-code",
76
+ "name": "Claude Code",
77
+ "provider": "Anthropic",
78
+ "historyLocation": "~/.claude/history.jsonl",
79
+ "historyFormat": "JSONL",
80
+ "memoryLocation": "~/.claude/projects/*/memory/*.md",
81
+ "documented": true
82
+ },
83
+ {
84
+ "id": "codex-cli",
85
+ "name": "Codex CLI",
86
+ "provider": "OpenAI",
87
+ "historyLocation": "~/.codex/history.jsonl",
88
+ "historyFormat": "JSONL",
89
+ "sessionsLocation": "~/.codex/sessions/**/*.jsonl",
90
+ "documented": true
91
+ },
92
+ {
93
+ "id": "aider",
94
+ "name": "Aider",
95
+ "provider": "Paul Gauthier",
96
+ "historyLocation": ".aider.chat.history.md",
97
+ "historyFormat": "Markdown",
98
+ "documented": true,
99
+ "notes": "History file is per-project, stored in the project root."
100
+ },
101
+ {
102
+ "id": "vibe-cli",
103
+ "name": "Vibe CLI",
104
+ "provider": "Mistral",
105
+ "historyLocation": "~/.vibe/sessions/*/messages.jsonl",
106
+ "historyFormat": "JSONL",
107
+ "documented": false,
108
+ "notes": "Partially documented."
109
+ },
110
+ {
111
+ "id": "amazon-q",
112
+ "name": "Amazon Q Developer",
113
+ "provider": "AWS",
114
+ "historyLocation": "~/.aws/amazonq/history/chat-history-*.json",
115
+ "historyFormat": "JSON",
116
+ "documented": false,
117
+ "notes": "Semi-documented; file layout inferred from observation."
118
+ },
119
+ {
120
+ "id": "goose",
121
+ "name": "Goose",
122
+ "provider": "Block",
123
+ "historyLocation": "~/.local/share/goose/sessions/sessions.db",
124
+ "historyFormat": "SQLite",
125
+ "documented": true,
126
+ "notes": "Requires SQLite dependency to read session data."
127
+ },
128
+ {
129
+ "id": "continue",
130
+ "name": "Continue",
131
+ "provider": "Continue.dev",
132
+ "historyLocation": "~/.continue/sessions/*.json",
133
+ "historyFormat": "JSON",
134
+ "documented": false,
135
+ "notes": "Partially documented."
136
+ },
137
+ {
138
+ "id": "windsurf",
139
+ "name": "Windsurf",
140
+ "provider": "Codeium",
141
+ "historyLocation": "~/.windsurf/transcripts/*.jsonl",
142
+ "historyFormat": "JSONL",
143
+ "documented": false,
144
+ "notes": "Partially documented; format marked unstable by vendor."
145
+ }
146
+ ],
147
+ "agents": [
148
+ "claude-code",
149
+ "codex-cli",
150
+ "aider",
151
+ "vibe-cli",
152
+ "amazon-q",
153
+ "goose",
154
+ "continue",
155
+ "windsurf"
156
+ ]
157
+ }
@@ -0,0 +1,415 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "specVersion": "1.0.0-draft",
4
+ "specDate": "2026-04-07",
5
+ "repository": "https://github.com/YawLabs/ctxlint",
6
+ "categories": [
7
+ {
8
+ "id": "paths",
9
+ "name": "File Reference Validation",
10
+ "description": "Validates that file paths referenced in context files exist in the project.",
11
+ "scope": "per-file"
12
+ },
13
+ {
14
+ "id": "commands",
15
+ "name": "Build/Script Validation",
16
+ "description": "Validates that build and test commands referenced in context files match project scripts.",
17
+ "scope": "per-file"
18
+ },
19
+ {
20
+ "id": "staleness",
21
+ "name": "Freshness Detection",
22
+ "description": "Detects context files that haven't been updated while referenced code has changed.",
23
+ "scope": "per-file",
24
+ "requires": "git"
25
+ },
26
+ {
27
+ "id": "tokens",
28
+ "name": "Context Window Budget",
29
+ "description": "Monitors context file size to help teams manage context window consumption.",
30
+ "scope": "per-file and cross-file"
31
+ },
32
+ {
33
+ "id": "redundancy",
34
+ "name": "Inferable Content",
35
+ "description": "Detects content that agents can already infer from project metadata.",
36
+ "scope": "per-file and cross-file"
37
+ },
38
+ {
39
+ "id": "contradictions",
40
+ "name": "Cross-File Conflicts",
41
+ "description": "Detects conflicting directives across multiple context files.",
42
+ "scope": "cross-file"
43
+ },
44
+ {
45
+ "id": "frontmatter",
46
+ "name": "Client Metadata Validation",
47
+ "description": "Validates YAML frontmatter required by specific AI coding clients.",
48
+ "scope": "per-file"
49
+ }
50
+ ],
51
+ "rules": [
52
+ {
53
+ "id": "paths/not-found",
54
+ "category": "paths",
55
+ "severity": "error",
56
+ "description": "Referenced file or directory does not exist at the specified path.",
57
+ "trigger": "Path reference in context file resolves to a non-existent file or directory.",
58
+ "message": "{path} does not exist",
59
+ "fixable": true,
60
+ "fixDescription": "Replace broken path with suggestion from git rename detection or fuzzy matching."
61
+ },
62
+ {
63
+ "id": "paths/glob-no-match",
64
+ "category": "paths",
65
+ "severity": "error",
66
+ "description": "Glob pattern matches zero files in the project.",
67
+ "trigger": "Path contains wildcard characters (*, ?) but matches no files.",
68
+ "message": "{pattern} matches no files",
69
+ "fixable": false
70
+ },
71
+ {
72
+ "id": "paths/directory-not-found",
73
+ "category": "paths",
74
+ "severity": "error",
75
+ "description": "Referenced directory does not exist.",
76
+ "trigger": "Path ending with / does not resolve to an existing directory.",
77
+ "message": "{path} directory does not exist",
78
+ "fixable": false
79
+ },
80
+ {
81
+ "id": "commands/script-not-found",
82
+ "category": "commands",
83
+ "severity": "error",
84
+ "description": "Package manager script name is not found in package.json scripts.",
85
+ "trigger": "npm run, pnpm, yarn, or bun script reference does not match a key in package.json#scripts.",
86
+ "message": "\"{cmd}\" — script \"{name}\" not found in package.json",
87
+ "fixable": false
88
+ },
89
+ {
90
+ "id": "commands/make-target-not-found",
91
+ "category": "commands",
92
+ "severity": "error",
93
+ "description": "Make target is not found in Makefile.",
94
+ "trigger": "make command references a target not declared in the project's Makefile.",
95
+ "message": "\"{cmd}\" — target \"{name}\" not found in Makefile",
96
+ "fixable": false
97
+ },
98
+ {
99
+ "id": "commands/no-makefile",
100
+ "category": "commands",
101
+ "severity": "error",
102
+ "description": "Make command used but no Makefile exists in the project.",
103
+ "trigger": "Context file references a make command but no Makefile is found at the project root.",
104
+ "message": "\"{cmd}\" — no Makefile found in project",
105
+ "fixable": false
106
+ },
107
+ {
108
+ "id": "commands/npx-not-in-deps",
109
+ "category": "commands",
110
+ "severity": "warning",
111
+ "description": "npx package is not in project dependencies.",
112
+ "trigger": "npx package is not in package.json dependencies/devDependencies and not in node_modules/.bin.",
113
+ "message": "\"{cmd}\" — \"{pkg}\" not found in dependencies",
114
+ "fixable": false
115
+ },
116
+ {
117
+ "id": "commands/tool-not-found",
118
+ "category": "commands",
119
+ "severity": "warning",
120
+ "description": "Common development tool is not in project dependencies.",
121
+ "trigger": "Tool name (vitest, jest, eslint, prettier, tsc, etc.) not found in dependencies or node_modules/.bin.",
122
+ "message": "\"{cmd}\" — \"{tool}\" not found in dependencies or node_modules/.bin",
123
+ "fixable": false
124
+ },
125
+ {
126
+ "id": "staleness/stale",
127
+ "category": "staleness",
128
+ "severity": "warning",
129
+ "description": "Context file has not been updated in 30+ days while referenced code has changed.",
130
+ "trigger": "File last modified 30+ days ago AND paths it references have git commits since.",
131
+ "message": "Last updated {days} days ago. {path} has {N} commits since.",
132
+ "fixable": false
133
+ },
134
+ {
135
+ "id": "staleness/aging",
136
+ "category": "staleness",
137
+ "severity": "info",
138
+ "description": "Context file has not been updated in 14-30 days while referenced code has changed.",
139
+ "trigger": "File last modified 14-30 days ago AND paths it references have git commits since.",
140
+ "message": "Last updated {days} days ago. {path} has {N} commits since.",
141
+ "fixable": false
142
+ },
143
+ {
144
+ "id": "tokens/excessive",
145
+ "category": "tokens",
146
+ "severity": "error",
147
+ "description": "Single context file consumes excessive context window space.",
148
+ "trigger": "File uses 8000+ tokens (configurable).",
149
+ "message": "{N} tokens — consumes significant context window space",
150
+ "fixable": false,
151
+ "configurable": true,
152
+ "defaultThreshold": 8000
153
+ },
154
+ {
155
+ "id": "tokens/large",
156
+ "category": "tokens",
157
+ "severity": "warning",
158
+ "description": "Single context file is large.",
159
+ "trigger": "File uses 3000-7999 tokens (configurable).",
160
+ "message": "{N} tokens — large context file",
161
+ "fixable": false,
162
+ "configurable": true,
163
+ "defaultThreshold": 3000
164
+ },
165
+ {
166
+ "id": "tokens/info",
167
+ "category": "tokens",
168
+ "severity": "info",
169
+ "description": "Reports per-file token count.",
170
+ "trigger": "File uses 1000+ tokens (configurable).",
171
+ "message": "Uses ~{N} tokens per session",
172
+ "fixable": false,
173
+ "configurable": true,
174
+ "defaultThreshold": 1000
175
+ },
176
+ {
177
+ "id": "tokens/aggregate",
178
+ "category": "tokens",
179
+ "severity": "warning",
180
+ "description": "Combined context files exceed recommended total token budget.",
181
+ "trigger": "All context files combined use 5000+ tokens (configurable) AND there are multiple files.",
182
+ "message": "{count} context files consume {N} tokens combined",
183
+ "fixable": false,
184
+ "configurable": true,
185
+ "defaultThreshold": 5000
186
+ },
187
+ {
188
+ "id": "redundancy/tech-mention",
189
+ "category": "redundancy",
190
+ "severity": "info",
191
+ "description": "Context file mentions a technology that is already in package.json dependencies.",
192
+ "trigger": "File contains phrases like 'use React' or 'built with Express' and that package is in dependencies.",
193
+ "message": "\"{tech}\" is in package.json {depType} — agent can infer this",
194
+ "fixable": false
195
+ },
196
+ {
197
+ "id": "redundancy/discoverable-dir",
198
+ "category": "redundancy",
199
+ "severity": "info",
200
+ "description": "Context file describes the location of a directory that the agent can discover by listing files.",
201
+ "trigger": "File says files 'are in' or 'go in' a directory that exists in the project.",
202
+ "message": "Directory \"{dir}\" exists and is discoverable — agent can find this by listing files",
203
+ "fixable": false
204
+ },
205
+ {
206
+ "id": "redundancy/duplicate-content",
207
+ "category": "redundancy",
208
+ "severity": "warning",
209
+ "description": "Two context files have significant content overlap.",
210
+ "trigger": "Two files share 60%+ of their lines (by trimmed content, lines >10 chars).",
211
+ "message": "{file1} and {file2} have {N}% content overlap",
212
+ "fixable": false
213
+ },
214
+ {
215
+ "id": "contradictions/conflict",
216
+ "category": "contradictions",
217
+ "severity": "warning",
218
+ "description": "Two context files specify mutually exclusive options in the same category.",
219
+ "trigger": "File A says 'use Jest' while File B says 'use Vitest' (or similar conflicts across 8 categories).",
220
+ "message": "{category} conflict: \"{optionA}\" in {fileA} vs \"{optionB}\" in {fileB}",
221
+ "fixable": false,
222
+ "contradictionCategories": [
223
+ "testing framework",
224
+ "package manager",
225
+ "indentation style",
226
+ "semicolons",
227
+ "quote style",
228
+ "naming convention",
229
+ "CSS approach",
230
+ "state management"
231
+ ]
232
+ },
233
+ {
234
+ "id": "frontmatter/missing",
235
+ "category": "frontmatter",
236
+ "severity": "warning",
237
+ "description": "File format requires frontmatter but none is present.",
238
+ "trigger": "Cursor .mdc, Copilot instruction, or Windsurf rule file has no --- frontmatter block.",
239
+ "message": "{format} file is missing frontmatter",
240
+ "fixable": false,
241
+ "appliesTo": ["cursor-mdc", "copilot-instructions", "windsurf-rules"]
242
+ },
243
+ {
244
+ "id": "frontmatter/missing-field",
245
+ "category": "frontmatter",
246
+ "severity": "warning",
247
+ "description": "A required or recommended frontmatter field is absent.",
248
+ "trigger": "Frontmatter exists but is missing a key field (description for Cursor, applyTo for Copilot, trigger for Windsurf).",
249
+ "message": "Missing \"{field}\" field in {format} frontmatter",
250
+ "fixable": false,
251
+ "appliesTo": ["cursor-mdc", "copilot-instructions", "windsurf-rules"]
252
+ },
253
+ {
254
+ "id": "frontmatter/invalid-value",
255
+ "category": "frontmatter",
256
+ "severity": "error",
257
+ "description": "A frontmatter field has an invalid value.",
258
+ "trigger": "alwaysApply is not true/false, trigger is not a valid enum value, globs doesn't look like a pattern.",
259
+ "message": "Invalid {field} value: \"{value}\"",
260
+ "fixable": false,
261
+ "appliesTo": ["cursor-mdc", "windsurf-rules"]
262
+ },
263
+ {
264
+ "id": "frontmatter/no-activation",
265
+ "category": "frontmatter",
266
+ "severity": "info",
267
+ "description": "File has frontmatter but no activation mechanism.",
268
+ "trigger": "Cursor .mdc has frontmatter with neither globs nor alwaysApply set.",
269
+ "message": "No activation field — rule may not be applied automatically",
270
+ "fixable": false,
271
+ "appliesTo": ["cursor-mdc"]
272
+ }
273
+ ],
274
+ "formats": [
275
+ {
276
+ "id": "claude-code",
277
+ "client": "Claude Code",
278
+ "patterns": ["CLAUDE.md", "CLAUDE.local.md", ".claude/rules/*.md"],
279
+ "type": "markdown",
280
+ "frontmatter": "none",
281
+ "scope": "project-wide and rule-based"
282
+ },
283
+ {
284
+ "id": "aaif",
285
+ "client": "AAIF / Multi-agent standard",
286
+ "patterns": ["AGENTS.md", "AGENT.md", "AGENTS.override.md"],
287
+ "type": "markdown",
288
+ "frontmatter": "none",
289
+ "scope": "project-wide"
290
+ },
291
+ {
292
+ "id": "cursor",
293
+ "client": "Cursor",
294
+ "patterns": [".cursorrules", ".cursor/rules/*.md", ".cursor/rules/*.mdc", ".cursor/rules/*/RULE.md"],
295
+ "type": "markdown",
296
+ "frontmatter": "required for .mdc",
297
+ "frontmatterFields": {
298
+ "description": {"required": true, "type": "string"},
299
+ "globs": {"required": false, "type": "string or string[]"},
300
+ "alwaysApply": {"required": false, "type": "boolean"}
301
+ },
302
+ "scope": "project-wide and rule-based"
303
+ },
304
+ {
305
+ "id": "copilot",
306
+ "client": "GitHub Copilot",
307
+ "patterns": [".github/copilot-instructions.md", ".github/instructions/*.md", ".github/git-commit-instructions.md"],
308
+ "type": "markdown",
309
+ "frontmatter": "optional",
310
+ "frontmatterFields": {
311
+ "applyTo": {"required": false, "type": "string (glob)"}
312
+ },
313
+ "scope": "project-wide and scoped"
314
+ },
315
+ {
316
+ "id": "windsurf",
317
+ "client": "Windsurf",
318
+ "patterns": [".windsurfrules", ".windsurf/rules/*.md"],
319
+ "type": "markdown",
320
+ "frontmatter": "recommended for rules",
321
+ "frontmatterFields": {
322
+ "trigger": {"required": true, "type": "enum", "values": ["always_on", "glob", "manual", "model"]}
323
+ },
324
+ "scope": "project-wide and rule-based"
325
+ },
326
+ {
327
+ "id": "gemini",
328
+ "client": "Gemini CLI",
329
+ "patterns": ["GEMINI.md"],
330
+ "type": "markdown",
331
+ "frontmatter": "none",
332
+ "scope": "project-wide"
333
+ },
334
+ {
335
+ "id": "cline",
336
+ "client": "Cline",
337
+ "patterns": [".clinerules"],
338
+ "type": "plain text",
339
+ "frontmatter": "none",
340
+ "scope": "project-wide"
341
+ },
342
+ {
343
+ "id": "aider",
344
+ "client": "Aider",
345
+ "patterns": [".aiderules"],
346
+ "type": "plain text",
347
+ "frontmatter": "none",
348
+ "scope": "project-wide"
349
+ },
350
+ {
351
+ "id": "aide",
352
+ "client": "Aide / Codestory",
353
+ "patterns": [".aide/rules/*.md"],
354
+ "type": "markdown",
355
+ "frontmatter": "none",
356
+ "scope": "rule-based"
357
+ },
358
+ {
359
+ "id": "amazonq",
360
+ "client": "Amazon Q Developer",
361
+ "patterns": [".amazonq/rules/*.md"],
362
+ "type": "markdown",
363
+ "frontmatter": "none",
364
+ "scope": "rule-based"
365
+ },
366
+ {
367
+ "id": "goose",
368
+ "client": "Goose (Block)",
369
+ "patterns": [".goose/instructions.md", ".goosehints"],
370
+ "type": "markdown",
371
+ "frontmatter": "none",
372
+ "scope": "project-wide"
373
+ },
374
+ {
375
+ "id": "junie",
376
+ "client": "JetBrains Junie",
377
+ "patterns": [".junie/guidelines.md", ".junie/AGENTS.md"],
378
+ "type": "markdown",
379
+ "frontmatter": "none",
380
+ "scope": "project-wide"
381
+ },
382
+ {
383
+ "id": "jetbrains-ai",
384
+ "client": "JetBrains AI Assistant",
385
+ "patterns": [".aiassistant/rules/*.md"],
386
+ "type": "markdown",
387
+ "frontmatter": "none",
388
+ "scope": "rule-based"
389
+ },
390
+ {
391
+ "id": "continue",
392
+ "client": "Continue",
393
+ "patterns": [".continuerules", ".continue/rules/*.md"],
394
+ "type": "markdown",
395
+ "frontmatter": "none",
396
+ "scope": "project-wide and rule-based"
397
+ },
398
+ {
399
+ "id": "zed",
400
+ "client": "Zed",
401
+ "patterns": [".rules"],
402
+ "type": "plain text",
403
+ "frontmatter": "none",
404
+ "scope": "project-wide"
405
+ },
406
+ {
407
+ "id": "replit",
408
+ "client": "Replit",
409
+ "patterns": ["replit.md"],
410
+ "type": "markdown",
411
+ "frontmatter": "none",
412
+ "scope": "project-wide"
413
+ }
414
+ ]
415
+ }