@nerviq/cli 1.10.0 → 1.12.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/README.md +176 -47
- package/bin/cli.js +842 -287
- package/package.json +2 -2
- package/src/activity.js +225 -59
- package/src/adoption-advisor.js +299 -0
- package/src/aider/freshness.js +28 -25
- package/src/aider/techniques.js +16 -11
- package/src/analyze.js +131 -1
- package/src/anti-patterns.js +17 -2
- package/src/audit.js +197 -96
- package/src/behavioral-drift.js +801 -0
- package/src/benchmark.js +15 -10
- package/src/continuous-ops.js +681 -0
- package/src/cost-tracking.js +61 -0
- package/src/cursor/techniques.js +17 -12
- package/src/deep-review.js +83 -0
- package/src/diff-only.js +280 -0
- package/src/doctor.js +118 -55
- package/src/governance.js +72 -50
- package/src/hook-validation.js +342 -0
- package/src/index.js +7 -1
- package/src/integrations.js +144 -60
- package/src/mcp-validation.js +337 -0
- package/src/opencode/techniques.js +12 -7
- package/src/operating-profile.js +574 -0
- package/src/org.js +97 -13
- package/src/permission-rules.js +218 -0
- package/src/plans.js +192 -8
- package/src/platform-change-manifest.js +86 -0
- package/src/policy-layers.js +210 -0
- package/src/profiles.js +4 -1
- package/src/prompt-injection.js +74 -0
- package/src/repo-archetype.js +386 -0
- package/src/secret-patterns.js +9 -0
- package/src/server.js +398 -3
- package/src/setup.js +36 -2
- package/src/source-urls.js +132 -132
- package/src/supplemental-checks.js +13 -12
- package/src/techniques/api.js +407 -0
- package/src/techniques/automation.js +316 -0
- package/src/techniques/compliance.js +257 -0
- package/src/techniques/hygiene.js +294 -0
- package/src/techniques/instructions.js +243 -0
- package/src/techniques/observability.js +226 -0
- package/src/techniques/optimization.js +142 -0
- package/src/techniques/quality.js +317 -0
- package/src/techniques/security.js +237 -0
- package/src/techniques/shared.js +443 -0
- package/src/techniques/stacks.js +2294 -0
- package/src/techniques/tools.js +106 -0
- package/src/techniques/workflow.js +413 -0
- package/src/techniques.js +78 -5611
- package/src/terminology.js +73 -0
- package/src/token-estimate.js +35 -0
- package/src/watch.js +18 -0
- package/src/windsurf/techniques.js +17 -12
- package/src/workspace.js +105 -8
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hygiene technique fragments.
|
|
3
|
+
* Generated mechanically from the legacy techniques.js monolith during HR-09.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const {
|
|
7
|
+
hasFrontendSignals,
|
|
8
|
+
hasProjectFile,
|
|
9
|
+
readProjectFiles,
|
|
10
|
+
isGoProject,
|
|
11
|
+
containsEmbeddedSecret,
|
|
12
|
+
} = require('./shared');
|
|
13
|
+
|
|
14
|
+
module.exports = {
|
|
15
|
+
gitIgnoreClaudeTracked: {
|
|
16
|
+
id: 976,
|
|
17
|
+
name: '.claude/ tracked in git',
|
|
18
|
+
check: (ctx) => {
|
|
19
|
+
if (!ctx.fileContent('.gitignore')) return true; // no gitignore = ok
|
|
20
|
+
const lines = ctx.fileContent('.gitignore')
|
|
21
|
+
.split(/\r?\n/)
|
|
22
|
+
.map(line => line.trim())
|
|
23
|
+
.filter(line => line && !line.startsWith('#'));
|
|
24
|
+
const ignoresClaudeDir = lines.some(line => /^(\/|\*\*\/)?\.claude\/?$/.test(line));
|
|
25
|
+
const unignoresClaudeDir = lines.some(line => /^!(\/)?\.claude(\/|\*\*)?$/.test(line));
|
|
26
|
+
return !ignoresClaudeDir || unignoresClaudeDir;
|
|
27
|
+
},
|
|
28
|
+
impact: 'high',
|
|
29
|
+
rating: 4,
|
|
30
|
+
category: 'git',
|
|
31
|
+
fix: 'Remove .claude/ from .gitignore (keep .claude/settings.local.json ignored).',
|
|
32
|
+
template: null
|
|
33
|
+
},
|
|
34
|
+
|
|
35
|
+
gitIgnoreEnv: {
|
|
36
|
+
id: 917,
|
|
37
|
+
name: '.gitignore blocks .env files',
|
|
38
|
+
check: (ctx) => {
|
|
39
|
+
const gitignore = ctx.fileContent('.gitignore') || '';
|
|
40
|
+
return gitignore.includes('.env');
|
|
41
|
+
},
|
|
42
|
+
impact: 'critical',
|
|
43
|
+
rating: 5,
|
|
44
|
+
category: 'git',
|
|
45
|
+
fix: 'Add .env to .gitignore to prevent leaking secrets.',
|
|
46
|
+
template: null
|
|
47
|
+
},
|
|
48
|
+
|
|
49
|
+
gitIgnoreNodeModules: {
|
|
50
|
+
id: 91701,
|
|
51
|
+
name: '.gitignore blocks node_modules',
|
|
52
|
+
check: (ctx) => {
|
|
53
|
+
const hasNodeSignals = ctx.files.includes('package.json') ||
|
|
54
|
+
ctx.files.includes('tsconfig.json') ||
|
|
55
|
+
ctx.files.some(f => /package-lock\.json|pnpm-lock\.yaml|yarn\.lock|next\.config|vite\.config/i.test(f));
|
|
56
|
+
if (!hasNodeSignals) return null;
|
|
57
|
+
const gitignore = ctx.fileContent('.gitignore') || '';
|
|
58
|
+
return gitignore.includes('node_modules');
|
|
59
|
+
},
|
|
60
|
+
impact: 'high',
|
|
61
|
+
rating: 4,
|
|
62
|
+
category: 'git',
|
|
63
|
+
fix: 'Add node_modules/ to .gitignore.',
|
|
64
|
+
template: null
|
|
65
|
+
},
|
|
66
|
+
|
|
67
|
+
noSecretsInClaude: {
|
|
68
|
+
id: 1039,
|
|
69
|
+
name: 'CLAUDE.md has no embedded secrets',
|
|
70
|
+
check: (ctx) => {
|
|
71
|
+
const md = ctx.claudeMdContent() || '';
|
|
72
|
+
return !containsEmbeddedSecret(md);
|
|
73
|
+
},
|
|
74
|
+
impact: 'critical',
|
|
75
|
+
rating: 5,
|
|
76
|
+
category: 'git',
|
|
77
|
+
fix: 'Remove hardcoded secrets, tokens, private keys, and connection strings from CLAUDE.md. Use environment variables or external secret stores instead.',
|
|
78
|
+
template: null
|
|
79
|
+
},
|
|
80
|
+
|
|
81
|
+
readme: {
|
|
82
|
+
id: 416,
|
|
83
|
+
name: 'Has README.md',
|
|
84
|
+
check: (ctx) => ctx.files.some(f => /^readme\.md$/i.test(f)),
|
|
85
|
+
impact: 'high',
|
|
86
|
+
rating: 4,
|
|
87
|
+
category: 'hygiene',
|
|
88
|
+
fix: 'Add a README.md with project overview, setup instructions, and usage.',
|
|
89
|
+
template: null
|
|
90
|
+
},
|
|
91
|
+
|
|
92
|
+
changelog: {
|
|
93
|
+
id: 417,
|
|
94
|
+
name: 'Has CHANGELOG.md',
|
|
95
|
+
check: (ctx) => ctx.files.some(f => /^changelog\.md$/i.test(f)),
|
|
96
|
+
impact: 'low',
|
|
97
|
+
rating: 3,
|
|
98
|
+
category: 'hygiene',
|
|
99
|
+
fix: 'Add a CHANGELOG.md to track notable changes across versions.',
|
|
100
|
+
template: null
|
|
101
|
+
},
|
|
102
|
+
|
|
103
|
+
contributing: {
|
|
104
|
+
id: 418,
|
|
105
|
+
name: 'Has CONTRIBUTING.md',
|
|
106
|
+
check: (ctx) => ctx.files.some(f => /^contributing\.md$/i.test(f)),
|
|
107
|
+
impact: 'low',
|
|
108
|
+
rating: 3,
|
|
109
|
+
category: 'hygiene',
|
|
110
|
+
fix: 'Add a CONTRIBUTING.md with contribution guidelines and code standards.',
|
|
111
|
+
template: null
|
|
112
|
+
},
|
|
113
|
+
|
|
114
|
+
license: {
|
|
115
|
+
id: 434,
|
|
116
|
+
name: 'Has LICENSE file',
|
|
117
|
+
check: (ctx) => ctx.files.some(f => /^license/i.test(f)),
|
|
118
|
+
impact: 'low',
|
|
119
|
+
rating: 3,
|
|
120
|
+
category: 'hygiene',
|
|
121
|
+
fix: 'Add a LICENSE file to clarify usage rights.',
|
|
122
|
+
template: null
|
|
123
|
+
},
|
|
124
|
+
|
|
125
|
+
editorconfig: {
|
|
126
|
+
id: 5001,
|
|
127
|
+
name: 'Has .editorconfig',
|
|
128
|
+
check: (ctx) => ctx.files.includes('.editorconfig'),
|
|
129
|
+
impact: 'low',
|
|
130
|
+
rating: 3,
|
|
131
|
+
category: 'hygiene',
|
|
132
|
+
fix: 'Add .editorconfig for consistent formatting across editors and Claude.',
|
|
133
|
+
template: null
|
|
134
|
+
},
|
|
135
|
+
|
|
136
|
+
nvmrc: {
|
|
137
|
+
id: 5002,
|
|
138
|
+
name: 'Node version pinned',
|
|
139
|
+
check: (ctx) => {
|
|
140
|
+
const hasNodeSignals = ctx.files.includes('package.json') ||
|
|
141
|
+
ctx.files.includes('tsconfig.json') ||
|
|
142
|
+
ctx.files.some(f => /package-lock\.json|pnpm-lock\.yaml|yarn\.lock|next\.config|vite\.config/i.test(f));
|
|
143
|
+
if (!hasNodeSignals) return null;
|
|
144
|
+
if (ctx.files.includes('.nvmrc') || ctx.files.includes('.node-version')) return true;
|
|
145
|
+
const pkg = ctx.jsonFile('package.json');
|
|
146
|
+
return !!(pkg && pkg.engines && pkg.engines.node);
|
|
147
|
+
},
|
|
148
|
+
impact: 'low',
|
|
149
|
+
rating: 3,
|
|
150
|
+
category: 'hygiene',
|
|
151
|
+
fix: 'Add .nvmrc, .node-version, or engines.node in package.json to pin Node version.',
|
|
152
|
+
template: null
|
|
153
|
+
},
|
|
154
|
+
|
|
155
|
+
gitAttributionDecision: {
|
|
156
|
+
id: 2015,
|
|
157
|
+
name: 'Git attribution configured',
|
|
158
|
+
check: (ctx) => {
|
|
159
|
+
const shared = ctx.jsonFile('.claude/settings.json') || {};
|
|
160
|
+
const local = ctx.jsonFile('.claude/settings.local.json') || {};
|
|
161
|
+
return shared.attribution !== undefined || local.attribution !== undefined ||
|
|
162
|
+
shared.includeCoAuthoredBy !== undefined || local.includeCoAuthoredBy !== undefined;
|
|
163
|
+
},
|
|
164
|
+
impact: 'low', rating: 3, category: 'git',
|
|
165
|
+
fix: 'Decide on git attribution: set attribution.commit or includeCoAuthoredBy in settings.',
|
|
166
|
+
template: null
|
|
167
|
+
},
|
|
168
|
+
|
|
169
|
+
gitIgnoreClaudeLocal: {
|
|
170
|
+
id: 2028,
|
|
171
|
+
name: '.gitignore excludes settings.local.json',
|
|
172
|
+
check: (ctx) => {
|
|
173
|
+
const gitignore = ctx.fileContent('.gitignore') || '';
|
|
174
|
+
return /settings\.local\.json|settings\.local/i.test(gitignore);
|
|
175
|
+
},
|
|
176
|
+
impact: 'medium', rating: 4, category: 'git',
|
|
177
|
+
fix: 'Add .claude/settings.local.json to .gitignore. Personal overrides should not be committed.',
|
|
178
|
+
template: null
|
|
179
|
+
},
|
|
180
|
+
|
|
181
|
+
envExampleExists: {
|
|
182
|
+
id: 2029,
|
|
183
|
+
name: '.env.example or .env.template exists',
|
|
184
|
+
check: (ctx) => {
|
|
185
|
+
return !!(ctx.fileContent('.env.example') || ctx.fileContent('.env.template') || ctx.fileContent('.env.sample'));
|
|
186
|
+
},
|
|
187
|
+
impact: 'low', rating: 3, category: 'hygiene',
|
|
188
|
+
fix: 'Add .env.example so new developers know which environment variables are needed.',
|
|
189
|
+
template: null
|
|
190
|
+
},
|
|
191
|
+
|
|
192
|
+
packageJsonHasScripts: {
|
|
193
|
+
id: 2030,
|
|
194
|
+
name: 'package.json has dev/test/build scripts',
|
|
195
|
+
check: (ctx) => {
|
|
196
|
+
const pkg = ctx.jsonFile('package.json');
|
|
197
|
+
if (!pkg) return null;
|
|
198
|
+
const scripts = pkg.scripts || {};
|
|
199
|
+
const has = (k) => !!scripts[k];
|
|
200
|
+
return has('test') || has('dev') || has('build') || has('start');
|
|
201
|
+
},
|
|
202
|
+
impact: 'medium', rating: 3, category: 'hygiene',
|
|
203
|
+
fix: 'Add scripts to package.json (test, dev, build). Claude uses these for verification.',
|
|
204
|
+
template: null
|
|
205
|
+
},
|
|
206
|
+
|
|
207
|
+
gitignoreClaudeLocal: {
|
|
208
|
+
id: 2036,
|
|
209
|
+
name: 'CLAUDE.local.md in .gitignore',
|
|
210
|
+
check: (ctx) => {
|
|
211
|
+
const gitignore = ctx.fileContent('.gitignore') || '';
|
|
212
|
+
return /CLAUDE\.local\.md/i.test(gitignore);
|
|
213
|
+
},
|
|
214
|
+
impact: 'medium',
|
|
215
|
+
rating: 3,
|
|
216
|
+
category: 'git',
|
|
217
|
+
fix: 'Add CLAUDE.local.md to .gitignore — it contains personal overrides that should not be committed.',
|
|
218
|
+
template: null
|
|
219
|
+
},
|
|
220
|
+
|
|
221
|
+
readmeQuality: {
|
|
222
|
+
id: 130151,
|
|
223
|
+
name: 'README has installation, usage, and contributing sections',
|
|
224
|
+
check: (ctx) => {
|
|
225
|
+
const readme = ctx.fileContent('README.md') || '';
|
|
226
|
+
if (!readme) return false;
|
|
227
|
+
return /install/i.test(readme) && /usage/i.test(readme) && /contribut/i.test(readme);
|
|
228
|
+
},
|
|
229
|
+
impact: 'medium',
|
|
230
|
+
category: 'docs-quality',
|
|
231
|
+
fix: 'Ensure README.md includes installation, usage, and contributing sections for developer onboarding.',
|
|
232
|
+
confidence: 0.7,
|
|
233
|
+
},
|
|
234
|
+
|
|
235
|
+
contributingGuide: {
|
|
236
|
+
id: 130152,
|
|
237
|
+
name: 'CONTRIBUTING.md exists',
|
|
238
|
+
check: (ctx) => ctx.files.some(f => /^contributing\.md$/i.test(f)),
|
|
239
|
+
impact: 'low',
|
|
240
|
+
category: 'docs-quality',
|
|
241
|
+
fix: 'Add CONTRIBUTING.md with contribution guidelines, code standards, and PR process.',
|
|
242
|
+
confidence: 0.7,
|
|
243
|
+
},
|
|
244
|
+
|
|
245
|
+
apiDocsGenerated: {
|
|
246
|
+
id: 130153,
|
|
247
|
+
name: 'API documentation generator configured',
|
|
248
|
+
check: (ctx) => {
|
|
249
|
+
const pkg = ctx.fileContent('package.json') || '';
|
|
250
|
+
if (/typedoc|jsdoc|apidoc|compodoc/i.test(pkg)) return true;
|
|
251
|
+
const py = readProjectFiles(ctx, /(^|\/)pyproject\.toml$/i) + readProjectFiles(ctx, /(^|\/)requirements[^/]*\.txt$/i);
|
|
252
|
+
if (/sphinx|pdoc|mkdocstrings/i.test(py)) return true;
|
|
253
|
+
if (isGoProject(ctx) && hasProjectFile(ctx, /(^|\/)doc\.go$/i)) return true;
|
|
254
|
+
return false;
|
|
255
|
+
},
|
|
256
|
+
impact: 'low',
|
|
257
|
+
category: 'docs-quality',
|
|
258
|
+
fix: 'Add an API documentation generator (typedoc, jsdoc, sphinx, godoc) for auto-generated docs.',
|
|
259
|
+
confidence: 0.7,
|
|
260
|
+
},
|
|
261
|
+
|
|
262
|
+
storybookConfigured: {
|
|
263
|
+
id: 130154,
|
|
264
|
+
name: 'Storybook configured for component docs',
|
|
265
|
+
check: (ctx) => {
|
|
266
|
+
if (!hasFrontendSignals(ctx)) return null;
|
|
267
|
+
return ctx.hasDir('.storybook') || hasProjectFile(ctx, /(^|\/)\.storybook\//i);
|
|
268
|
+
},
|
|
269
|
+
impact: 'low',
|
|
270
|
+
category: 'docs-quality',
|
|
271
|
+
fix: 'Add Storybook (.storybook/) for interactive component documentation and visual testing.',
|
|
272
|
+
confidence: 0.7,
|
|
273
|
+
},
|
|
274
|
+
|
|
275
|
+
codeOfConduct: {
|
|
276
|
+
id: 130155,
|
|
277
|
+
name: 'CODE_OF_CONDUCT.md exists',
|
|
278
|
+
check: (ctx) => ctx.files.some(f => /^code.of.conduct\.md$/i.test(f)),
|
|
279
|
+
impact: 'low',
|
|
280
|
+
category: 'docs-quality',
|
|
281
|
+
fix: 'Add CODE_OF_CONDUCT.md to set community standards and expectations.',
|
|
282
|
+
confidence: 0.7,
|
|
283
|
+
},
|
|
284
|
+
|
|
285
|
+
licenseDeclared: {
|
|
286
|
+
id: 130156,
|
|
287
|
+
name: 'LICENSE file exists',
|
|
288
|
+
check: (ctx) => ctx.files.some(f => /^license/i.test(f)),
|
|
289
|
+
impact: 'low',
|
|
290
|
+
category: 'docs-quality',
|
|
291
|
+
fix: 'Add a LICENSE file to clarify usage rights and legal terms.',
|
|
292
|
+
confidence: 0.7,
|
|
293
|
+
},
|
|
294
|
+
};
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Instructions technique fragments.
|
|
3
|
+
* Generated mechanically from the legacy techniques.js monolith during HR-09.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const {
|
|
7
|
+
path,
|
|
8
|
+
getClaudeHookContents,
|
|
9
|
+
} = require('./shared');
|
|
10
|
+
|
|
11
|
+
module.exports = {
|
|
12
|
+
claudeMd: {
|
|
13
|
+
id: 1,
|
|
14
|
+
name: 'CLAUDE.md project instructions',
|
|
15
|
+
check: (ctx) => ctx.files.includes('CLAUDE.md') || ctx.files.includes('.claude/CLAUDE.md'),
|
|
16
|
+
impact: 'critical',
|
|
17
|
+
rating: 5,
|
|
18
|
+
category: 'memory',
|
|
19
|
+
fix: 'Create CLAUDE.md with project-specific instructions, build commands, and coding conventions.',
|
|
20
|
+
template: 'claude-md'
|
|
21
|
+
},
|
|
22
|
+
|
|
23
|
+
mermaidArchitecture: {
|
|
24
|
+
id: 51,
|
|
25
|
+
name: 'Mermaid architecture diagram',
|
|
26
|
+
check: (ctx) => {
|
|
27
|
+
const md = ctx.claudeMdContent() || '';
|
|
28
|
+
return md.includes('mermaid') || md.includes('graph ') || md.includes('flowchart ');
|
|
29
|
+
},
|
|
30
|
+
impact: 'high',
|
|
31
|
+
rating: 5,
|
|
32
|
+
category: 'memory',
|
|
33
|
+
fix: 'Add a Mermaid diagram to CLAUDE.md showing project architecture. Saves 73% tokens vs prose.',
|
|
34
|
+
template: 'mermaid'
|
|
35
|
+
},
|
|
36
|
+
|
|
37
|
+
pathRules: {
|
|
38
|
+
id: 3,
|
|
39
|
+
name: 'Path-specific rules',
|
|
40
|
+
check: (ctx) => ctx.hasDir('.claude/rules') && ctx.dirFiles('.claude/rules').length > 0,
|
|
41
|
+
impact: 'medium',
|
|
42
|
+
rating: 4,
|
|
43
|
+
category: 'memory',
|
|
44
|
+
fix: 'Add rules for different file types (frontend vs backend conventions).',
|
|
45
|
+
template: 'rules'
|
|
46
|
+
},
|
|
47
|
+
|
|
48
|
+
importSyntax: {
|
|
49
|
+
id: 763,
|
|
50
|
+
name: 'CLAUDE.md uses @path imports for modularity',
|
|
51
|
+
check: (ctx) => {
|
|
52
|
+
const md = ctx.claudeMdContent() || '';
|
|
53
|
+
// Current syntax is @path/to/file (no "import" keyword)
|
|
54
|
+
return /@\S+\.(md|txt|json|yml|yaml|toml)/i.test(md) || /@\w+\//.test(md);
|
|
55
|
+
},
|
|
56
|
+
impact: 'medium',
|
|
57
|
+
rating: 4,
|
|
58
|
+
category: 'memory',
|
|
59
|
+
fix: 'Use @path syntax in CLAUDE.md to split instructions into focused modules (e.g. @docs/coding-style.md). You can also use .claude/rules/ for path-specific rules.',
|
|
60
|
+
template: null
|
|
61
|
+
},
|
|
62
|
+
|
|
63
|
+
underlines200: {
|
|
64
|
+
id: 681,
|
|
65
|
+
name: 'CLAUDE.md under 200 lines (concise)',
|
|
66
|
+
check: (ctx) => {
|
|
67
|
+
const md = ctx.claudeMdContent() || '';
|
|
68
|
+
return md.split('\n').length <= 200;
|
|
69
|
+
},
|
|
70
|
+
impact: 'medium',
|
|
71
|
+
rating: 4,
|
|
72
|
+
category: 'memory',
|
|
73
|
+
fix: 'Keep CLAUDE.md under 200 lines. Use @import or .claude/rules/ to split large instructions.',
|
|
74
|
+
template: null
|
|
75
|
+
},
|
|
76
|
+
|
|
77
|
+
xmlTags: {
|
|
78
|
+
id: 96,
|
|
79
|
+
name: 'XML tags for structured prompts',
|
|
80
|
+
check: (ctx) => {
|
|
81
|
+
const md = ctx.claudeMdContent() || '';
|
|
82
|
+
// Give credit for XML tags OR well-structured markdown with clear sections
|
|
83
|
+
const hasXml = md.includes('<constraints') || md.includes('<rules') ||
|
|
84
|
+
md.includes('<validation') || md.includes('<instructions');
|
|
85
|
+
const hasStructuredMd = (md.includes('## Rules') || md.includes('## Constraints') ||
|
|
86
|
+
md.includes('## Do not') || md.includes('## Never') || md.includes('## Important')) &&
|
|
87
|
+
md.split('\n').length > 20;
|
|
88
|
+
return hasXml || hasStructuredMd;
|
|
89
|
+
},
|
|
90
|
+
impact: 'medium',
|
|
91
|
+
rating: 4,
|
|
92
|
+
category: 'prompting',
|
|
93
|
+
fix: 'Add clear rules sections to CLAUDE.md. XML tags (<constraints>) are optional but improve clarity.',
|
|
94
|
+
template: null
|
|
95
|
+
},
|
|
96
|
+
|
|
97
|
+
fewShotExamples: {
|
|
98
|
+
id: 9,
|
|
99
|
+
name: 'CLAUDE.md contains code examples',
|
|
100
|
+
check: (ctx) => {
|
|
101
|
+
const md = ctx.claudeMdContent() || '';
|
|
102
|
+
return (md.match(/```/g) || []).length >= 2;
|
|
103
|
+
},
|
|
104
|
+
impact: 'high',
|
|
105
|
+
rating: 5,
|
|
106
|
+
category: 'prompting',
|
|
107
|
+
fix: 'Add code examples (few-shot) in CLAUDE.md to show preferred patterns and conventions.',
|
|
108
|
+
template: null
|
|
109
|
+
},
|
|
110
|
+
|
|
111
|
+
roleDefinition: {
|
|
112
|
+
id: 10,
|
|
113
|
+
name: 'CLAUDE.md defines a role or persona',
|
|
114
|
+
check: (ctx) => {
|
|
115
|
+
const md = ctx.claudeMdContent() || '';
|
|
116
|
+
return /^you are a |^your role is|^act as a |persona:|behave as a /im.test(md);
|
|
117
|
+
},
|
|
118
|
+
impact: 'medium',
|
|
119
|
+
rating: 4,
|
|
120
|
+
category: 'prompting',
|
|
121
|
+
fix: 'Define a role or persona in CLAUDE.md (e.g. "You are a senior backend engineer...").',
|
|
122
|
+
template: null
|
|
123
|
+
},
|
|
124
|
+
|
|
125
|
+
constraintBlocks: {
|
|
126
|
+
id: 9601,
|
|
127
|
+
name: 'XML constraint blocks in CLAUDE.md',
|
|
128
|
+
check: (ctx) => {
|
|
129
|
+
const md = ctx.claudeMdContent() || '';
|
|
130
|
+
return /<constraints|<rules|<requirements|<boundaries/i.test(md);
|
|
131
|
+
},
|
|
132
|
+
impact: 'high',
|
|
133
|
+
rating: 5,
|
|
134
|
+
category: 'prompting',
|
|
135
|
+
fix: 'Wrap critical rules in <constraints> XML blocks for 40% better adherence.',
|
|
136
|
+
template: null
|
|
137
|
+
},
|
|
138
|
+
|
|
139
|
+
claudeLocalMd: {
|
|
140
|
+
id: 2002,
|
|
141
|
+
name: 'CLAUDE.local.md for personal overrides',
|
|
142
|
+
check: (ctx) => {
|
|
143
|
+
// CLAUDE.local.md is for personal, non-committed overrides
|
|
144
|
+
return ctx.files.includes('CLAUDE.local.md') || ctx.files.includes('.claude/CLAUDE.local.md');
|
|
145
|
+
},
|
|
146
|
+
impact: 'low',
|
|
147
|
+
rating: 2,
|
|
148
|
+
category: 'memory',
|
|
149
|
+
fix: 'Create CLAUDE.local.md for personal preferences that should not be committed (add to .gitignore).',
|
|
150
|
+
template: null
|
|
151
|
+
},
|
|
152
|
+
|
|
153
|
+
autoMemoryAwareness: {
|
|
154
|
+
id: 2012,
|
|
155
|
+
name: 'Auto-memory or memory management mentioned',
|
|
156
|
+
check: (ctx) => {
|
|
157
|
+
const md = ctx.claudeMdContent() || '';
|
|
158
|
+
return /auto.?memory|memory.*manage|remember|persistent.*context/i.test(md);
|
|
159
|
+
},
|
|
160
|
+
impact: 'low', rating: 3, category: 'memory',
|
|
161
|
+
fix: 'Claude Code supports auto-memory for cross-session learning. Mention your memory strategy if relevant.',
|
|
162
|
+
template: null
|
|
163
|
+
},
|
|
164
|
+
|
|
165
|
+
negativeInstructions: {
|
|
166
|
+
id: 2019,
|
|
167
|
+
name: 'CLAUDE.md includes "do not" instructions',
|
|
168
|
+
check: (ctx) => {
|
|
169
|
+
const md = ctx.claudeMdContent() || '';
|
|
170
|
+
return /do not|don't|never|avoid|must not/i.test(md);
|
|
171
|
+
},
|
|
172
|
+
impact: 'medium', rating: 4, category: 'prompting',
|
|
173
|
+
fix: 'Add explicit "do not" rules to CLAUDE.md. Negative constraints reduce common mistakes.',
|
|
174
|
+
template: null
|
|
175
|
+
},
|
|
176
|
+
|
|
177
|
+
outputStyleGuidance: {
|
|
178
|
+
id: 2020,
|
|
179
|
+
name: 'CLAUDE.md includes output or style guidance',
|
|
180
|
+
check: (ctx) => {
|
|
181
|
+
const md = ctx.claudeMdContent() || '';
|
|
182
|
+
return /coding style|naming convention|code style|style guide|formatting rules|\bprefer\b.*\b(single|double|tabs|spaces|camel|snake|kebab|named|default|const|let|arrow|function)\b/i.test(md);
|
|
183
|
+
},
|
|
184
|
+
impact: 'medium', rating: 3, category: 'prompting',
|
|
185
|
+
fix: 'Add coding style and naming conventions to CLAUDE.md so Claude matches your project patterns.',
|
|
186
|
+
template: null
|
|
187
|
+
},
|
|
188
|
+
|
|
189
|
+
projectDescriptionInClaudeMd: {
|
|
190
|
+
id: 2022,
|
|
191
|
+
name: 'CLAUDE.md describes what the project does',
|
|
192
|
+
check: (ctx) => {
|
|
193
|
+
const md = ctx.claudeMdContent() || '';
|
|
194
|
+
return /what.*does|overview|purpose|about|description|project.*is/i.test(md) && md.length > 100;
|
|
195
|
+
},
|
|
196
|
+
impact: 'high', rating: 4, category: 'memory',
|
|
197
|
+
fix: 'Start CLAUDE.md with a clear project description. Claude needs to know what your project does.',
|
|
198
|
+
template: null
|
|
199
|
+
},
|
|
200
|
+
|
|
201
|
+
directoryStructureInClaudeMd: {
|
|
202
|
+
id: 2023,
|
|
203
|
+
name: 'CLAUDE.md documents directory structure',
|
|
204
|
+
check: (ctx) => {
|
|
205
|
+
const md = ctx.claudeMdContent() || '';
|
|
206
|
+
return /src\/|app\/|lib\/|structure|director|folder/i.test(md);
|
|
207
|
+
},
|
|
208
|
+
impact: 'medium', rating: 4, category: 'memory',
|
|
209
|
+
fix: 'Document your directory structure in CLAUDE.md so Claude navigates your codebase efficiently.',
|
|
210
|
+
template: null
|
|
211
|
+
},
|
|
212
|
+
|
|
213
|
+
hookExitCodesDefined: {
|
|
214
|
+
id: 110003,
|
|
215
|
+
name: 'Hook scripts handle exit codes correctly',
|
|
216
|
+
check: (ctx) => {
|
|
217
|
+
const hookContents = getClaudeHookContents(ctx);
|
|
218
|
+
if (hookContents.length === 0) return null;
|
|
219
|
+
return hookContents.some(content => /process\.exit|exit\s+[012]|sys\.exit|return\s+[012]/i.test(content));
|
|
220
|
+
},
|
|
221
|
+
impact: 'low', rating: 3, category: 'governance',
|
|
222
|
+
fix: 'Hooks should use explicit exit codes: 0=success, 1=warning, 2=block. See Claude Code docs.',
|
|
223
|
+
template: null,
|
|
224
|
+
confidence: 0.7,
|
|
225
|
+
},
|
|
226
|
+
|
|
227
|
+
loopSafetyBoundaries: {
|
|
228
|
+
id: 110004,
|
|
229
|
+
name: 'Loop safety boundaries configured',
|
|
230
|
+
check: (ctx) => {
|
|
231
|
+
const md = ctx.claudeMdContent() || '';
|
|
232
|
+
const settings = ctx.fileContent('.claude/settings.json') || '';
|
|
233
|
+
const hookContents = getClaudeHookContents(ctx).join('\n');
|
|
234
|
+
const loopSafetyConfig = [md, settings, hookContents].filter(Boolean).join('\n');
|
|
235
|
+
|
|
236
|
+
return /max[-_ ]?turns|maxTurns|max[-_ ]?tokens|maxTokens|loop(?:[-_ ]?(?:limit|limits|safety|guard|budget|boundary|boundaries))|iteration(?:[-_ ]?(?:limit|limits|guard|budget|cap|caps|count|max(?:imum)?))/i.test(loopSafetyConfig);
|
|
237
|
+
},
|
|
238
|
+
impact: 'medium', rating: 4, category: 'governance',
|
|
239
|
+
fix: 'Document loop safety limits such as maxTurns, maxTokens, or iteration caps in CLAUDE.md, settings, or hook guards.',
|
|
240
|
+
template: null,
|
|
241
|
+
confidence: 0.8,
|
|
242
|
+
},
|
|
243
|
+
};
|