start-vibing 2.0.7 → 2.0.9

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "start-vibing",
3
- "version": "2.0.7",
3
+ "version": "2.0.9",
4
4
  "description": "Setup Claude Code agents, skills, and hooks in your project. Smart copy that preserves your custom domains and configurations.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -4,19 +4,62 @@ This file provides context for all agents. For user-facing rules, see `/CLAUDE.m
4
4
 
5
5
  ---
6
6
 
7
+ ## CLAUDE.md Validation (STOP HOOK ENFORCED)
8
+
9
+ The stop hook validates `/CLAUDE.md` before allowing task completion:
10
+
11
+ | Check | Requirement |
12
+ |-------|-------------|
13
+ | Character limit | Max 40,000 chars |
14
+ | Required sections | Last Change, 30s Overview, Stack, Architecture |
15
+ | Last Change | Must be updated with session info (branch, date, summary) |
16
+ | No stacking | Only ONE Last Change section (latest only) |
17
+ | Branch | Must be on main (PR merged) |
18
+ | Git tree | Must be clean (no uncommitted changes) |
19
+
20
+ **If CLAUDE.md exceeds 40k chars:** Compact it by removing verbose explanations, keeping critical sections.
21
+
22
+ **If not on main:** Complete PR workflow (commit, push, PR, merge, checkout main).
23
+
24
+ ---
25
+
7
26
  ## System Architecture
8
27
 
9
28
  ```
10
29
  .claude/
11
- ├── agents/ # 11 specialized agents (READ before acting)
12
- ├── skills/ # 8 skill systems with cache
30
+ ├── agents/ # 82 specialized agents in 14 categories
31
+ ├── skills/ # 22 skill systems with cache
32
+ ├── scripts/ # Validation scripts (validate-claude-md.ts)
13
33
  ├── config/ # Project-specific configuration
14
34
  ├── commands/ # Slash commands
15
- └── hooks/ # Security hooks
35
+ └── hooks/ # stop-validator.ts, user-prompt-submit.ts
16
36
  ```
17
37
 
18
38
  ---
19
39
 
40
+ ## MCP Servers (MANDATORY FOR AGENTS)
41
+
42
+ All agents MUST use these MCP servers when applicable:
43
+
44
+ | Server | Purpose | Use In Agents |
45
+ | ------------------- | ----------------------------------------- | ---------------------------------------- |
46
+ | `context7` | Up-to-date library documentation | research, analyzer, tester |
47
+ | `sequential-thinking` | Complex problem-solving | orchestrator, analyzer, final-validator |
48
+ | `memory` | Persistent knowledge graph | domain-updater, commit-manager |
49
+ | `playwright` | Browser automation and E2E testing | tester, ui-ux-reviewer |
50
+ | `nextjs-devtools` | Next.js specific development tools | analyzer (Next.js projects) |
51
+ | `mongodb` | MongoDB database operations | tester, security-auditor |
52
+
53
+ ### Agent MCP Usage Rules
54
+
55
+ - **research agent**: MUST use `context7` for library docs before recommending patterns
56
+ - **tester agent**: MUST use `playwright` for E2E tests
57
+ - **analyzer agent**: SHOULD use `context7` to verify current API patterns
58
+ - **domain-updater**: SHOULD use `memory` to persist patterns across sessions
59
+ - **ui-ux-reviewer**: MUST use `playwright` to verify UI implementations
60
+
61
+ ---
62
+
20
63
  ## Configuration Files
21
64
 
22
65
  Project-specific settings are in `.claude/config/`:
@@ -1,19 +1,31 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
- * Stop Validator Hook - TypeScript version (fallback when Python not available)
3
+ * Stop Validator Hook - Complete Validation System
4
4
  *
5
- * VALIDATES:
6
- * 1. NOT on main branch (unless no source changes)
7
- * 2. All modified files are documented
8
- * 3. Documenter agent was executed for source changes
5
+ * THIS HOOK BLOCKS TASK COMPLETION IF ANY OF THESE CONDITIONS FAIL:
9
6
  *
10
- * BLOCKS completion if validations fail.
7
+ * 1. BRANCH CHECK: Must be on 'main' branch (PR must be merged)
8
+ * 2. GIT TREE CHECK: Working tree must be clean (no uncommitted changes)
9
+ * 3. CLAUDE.MD CHECK: Must be updated with session changes
10
+ * 4. CLAUDE.MD STRUCTURE: Must have required sections
11
+ * 5. CLAUDE.MD SIZE: Must not exceed 40,000 characters
12
+ * 6. DOCUMENTATION CHECK: All source files must be documented
13
+ *
14
+ * ERROR MESSAGES ARE DESCRIPTIVE: They guide the agent on exactly what to do.
11
15
  */
12
16
 
13
17
  import { execSync } from 'child_process';
14
18
  import { existsSync, readdirSync, readFileSync, statSync } from 'fs';
15
19
  import { join, basename, extname } from 'path';
16
20
 
21
+ // ============================================================================
22
+ // CONFIGURATION
23
+ // ============================================================================
24
+
25
+ const PROJECT_DIR = process.env['CLAUDE_PROJECT_DIR'] || process.cwd();
26
+ const CLAUDE_MD_PATH = join(PROJECT_DIR, 'CLAUDE.md');
27
+ const MAX_CHARACTERS = 40000;
28
+
17
29
  const IGNORE_DIRS = new Set([
18
30
  '.next', 'node_modules', 'dist', 'build', 'coverage',
19
31
  '.git', '__pycache__', '.turbo', '.cache', '.husky',
@@ -32,24 +44,27 @@ const SOURCE_EXTENSIONS = new Set([
32
44
  '.java', '.kt', '.swift', '.vue', '.svelte'
33
45
  ]);
34
46
 
35
- const SYSTEM_CONFIG_PATTERNS = [
36
- 'CLAUDE.md',
37
- '.claude/',
38
- 'PROJECT.md',
39
- '.env.example',
47
+ // Required sections in CLAUDE.md
48
+ const REQUIRED_SECTIONS = [
49
+ { pattern: /^# .+/m, name: 'Project Title (H1)' },
50
+ { pattern: /^## Last Change/m, name: 'Last Change' },
51
+ { pattern: /^## 30 Seconds Overview/m, name: '30 Seconds Overview' },
52
+ { pattern: /^## Stack/m, name: 'Stack' },
53
+ { pattern: /^## Architecture/m, name: 'Architecture' },
40
54
  ];
41
55
 
56
+ // ============================================================================
57
+ // HELPER FUNCTIONS
58
+ // ============================================================================
59
+
42
60
  function shouldIgnoreFile(filePath: string): boolean {
43
61
  const parts = filePath.split(/[/\\]/);
44
-
45
62
  for (const part of parts) {
46
63
  if (IGNORE_DIRS.has(part)) return true;
47
64
  }
48
-
49
65
  for (const pattern of IGNORE_PATTERNS) {
50
66
  if (filePath.includes(pattern)) return true;
51
67
  }
52
-
53
68
  return false;
54
69
  }
55
70
 
@@ -58,39 +73,34 @@ function isSourceFile(filePath: string): boolean {
58
73
  return SOURCE_EXTENSIONS.has(ext) && !shouldIgnoreFile(filePath);
59
74
  }
60
75
 
61
- function isSystemConfigFile(filePath: string): boolean {
62
- return SYSTEM_CONFIG_PATTERNS.some(pattern => filePath.includes(pattern));
63
- }
64
-
65
- function getCurrentBranch(projectDir: string): string {
76
+ function getCurrentBranch(): string {
66
77
  try {
67
- const result = execSync('git rev-parse --abbrev-ref HEAD', {
68
- cwd: projectDir,
78
+ return execSync('git rev-parse --abbrev-ref HEAD', {
79
+ cwd: PROJECT_DIR,
69
80
  encoding: 'utf8',
70
81
  stdio: ['pipe', 'pipe', 'pipe']
71
- });
72
- return result.trim();
82
+ }).trim();
73
83
  } catch {
74
84
  return 'unknown';
75
85
  }
76
86
  }
77
87
 
78
- function getModifiedFiles(projectDir: string): string[] {
88
+ function getModifiedFiles(): string[] {
79
89
  try {
80
90
  const staged = execSync('git diff --name-only --cached', {
81
- cwd: projectDir,
91
+ cwd: PROJECT_DIR,
82
92
  encoding: 'utf8',
83
93
  stdio: ['pipe', 'pipe', 'pipe']
84
94
  }).trim().split('\n').filter(Boolean);
85
95
 
86
96
  const unstaged = execSync('git diff --name-only', {
87
- cwd: projectDir,
97
+ cwd: PROJECT_DIR,
88
98
  encoding: 'utf8',
89
99
  stdio: ['pipe', 'pipe', 'pipe']
90
100
  }).trim().split('\n').filter(Boolean);
91
101
 
92
102
  const untracked = execSync('git ls-files --others --exclude-standard', {
93
- cwd: projectDir,
103
+ cwd: PROJECT_DIR,
94
104
  encoding: 'utf8',
95
105
  stdio: ['pipe', 'pipe', 'pipe']
96
106
  }).trim().split('\n').filter(Boolean);
@@ -103,7 +113,6 @@ function getModifiedFiles(projectDir: string): string[] {
103
113
 
104
114
  function* walkDir(dir: string): Generator<string> {
105
115
  if (!existsSync(dir)) return;
106
-
107
116
  const entries = readdirSync(dir);
108
117
  for (const entry of entries) {
109
118
  const fullPath = join(dir, entry);
@@ -120,22 +129,20 @@ function* walkDir(dir: string): Generator<string> {
120
129
  }
121
130
  }
122
131
 
123
- function searchInDocs(projectDir: string, filePath: string): boolean {
132
+ function searchInDocs(filePath: string): boolean {
124
133
  const fileName = basename(filePath);
125
134
  const fileStem = basename(filePath, extname(filePath));
126
135
 
127
136
  const docDirs = [
128
- join(projectDir, 'docs'),
129
- join(projectDir, '.claude', 'skills', 'codebase-knowledge', 'domains'),
137
+ join(PROJECT_DIR, 'docs'),
138
+ join(PROJECT_DIR, '.claude', 'skills', 'codebase-knowledge', 'domains'),
130
139
  ];
131
140
 
132
141
  for (const docDir of docDirs) {
133
142
  if (!existsSync(docDir)) continue;
134
-
135
143
  for (const docFile of walkDir(docDir)) {
136
144
  const ext = extname(docFile);
137
145
  if (!DOC_EXTENSIONS.has(ext)) continue;
138
-
139
146
  try {
140
147
  const content = readFileSync(docFile, 'utf8');
141
148
  if (content.includes(fileName) || content.includes(fileStem) || content.includes(filePath)) {
@@ -146,27 +153,456 @@ function searchInDocs(projectDir: string, filePath: string): boolean {
146
153
  }
147
154
  }
148
155
  }
149
-
150
156
  return false;
151
157
  }
152
158
 
153
- function validateDocumentation(projectDir: string, modifiedFiles: string[]): { undocumented: string[], documented: string[] } {
154
- const undocumented: string[] = [];
155
- const documented: string[] = [];
159
+ // ============================================================================
160
+ // VALIDATION FUNCTIONS
161
+ // ============================================================================
162
+
163
+ interface ValidationError {
164
+ type: string;
165
+ message: string;
166
+ action: string;
167
+ }
168
+
169
+ function validateBranch(currentBranch: string, modifiedFiles: string[]): ValidationError | null {
170
+ const isMainBranch = currentBranch === 'main' || currentBranch === 'master';
171
+
172
+ // Case 1: On feature branch with changes - need to complete workflow
173
+ if (!isMainBranch && modifiedFiles.length > 0) {
174
+ return {
175
+ type: 'FEATURE_BRANCH_NOT_MERGED',
176
+ message: `Currently on branch '${currentBranch}' with uncommitted changes. The task cannot complete until work is merged to main.`,
177
+ action: `
178
+ ================================================================================
179
+ COMPLETE THE GIT WORKFLOW BEFORE TASK COMPLETION
180
+ ================================================================================
181
+
182
+ You are on branch '${currentBranch}' with ${modifiedFiles.length} modified file(s).
183
+
184
+ REQUIRED STEPS (execute in order):
185
+
186
+ 1. STAGE all changes:
187
+ git add -A
188
+
189
+ 2. COMMIT with conventional message:
190
+ git commit -m "feat: description of changes"
191
+
192
+ 3. PUSH to remote:
193
+ git push -u origin ${currentBranch}
194
+
195
+ 4. CREATE Pull Request:
196
+ gh pr create --title "Title" --body "$(cat <<'EOF'
197
+ ## Summary
198
+ - What was changed
199
+
200
+ ## Test plan
201
+ - How to verify
202
+
203
+ Generated with Claude Code
204
+ EOF
205
+ )"
206
+
207
+ 5. MERGE the PR (auto-delete branch):
208
+ gh pr merge --merge --delete-branch
209
+
210
+ 6. SWITCH to main and pull:
211
+ git checkout main && git pull
212
+
213
+ THEN the task can complete. The stop hook will verify main branch + clean tree.
214
+ ================================================================================`
215
+ };
216
+ }
217
+
218
+ // Case 2: On feature branch with clean tree - just need to switch
219
+ if (!isMainBranch && modifiedFiles.length === 0) {
220
+ return {
221
+ type: 'NOT_ON_MAIN_BRANCH',
222
+ message: `Currently on branch '${currentBranch}'. Task completion requires being on 'main'.`,
223
+ action: `
224
+ ================================================================================
225
+ SWITCH TO MAIN BRANCH
226
+ ================================================================================
227
+
228
+ The working tree is clean but you're on branch '${currentBranch}'.
229
+
230
+ If your PR was merged:
231
+ git checkout main && git pull
232
+
233
+ If you still need to create/merge PR:
234
+ gh pr create (if not created)
235
+ gh pr merge --merge --delete-branch (to merge)
236
+ git checkout main && git pull
237
+
238
+ IMPORTANT: Task completion is BLOCKED until you are on 'main' with a clean tree.
239
+ ================================================================================`
240
+ };
241
+ }
242
+
243
+ // Case 3: On main with changes - FORBIDDEN
244
+ if (isMainBranch && modifiedFiles.length > 0) {
245
+ const fileList = modifiedFiles.slice(0, 10).map(f => ` - ${f}`).join('\n');
246
+ return {
247
+ type: 'DIRECT_MAIN_COMMIT_FORBIDDEN',
248
+ message: `CRITICAL: Attempting to work directly on '${currentBranch}' branch with changes!`,
249
+ action: `
250
+ ================================================================================
251
+ FORBIDDEN: DIRECT COMMITS TO MAIN
252
+ ================================================================================
253
+
254
+ You have ${modifiedFiles.length} modified file(s) on main branch:
255
+ ${fileList}${modifiedFiles.length > 10 ? '\n ... and more' : ''}
256
+
257
+ ALL work MUST be done on feature branches. This is MANDATORY.
258
+
259
+ REQUIRED STEPS:
260
+
261
+ 1. CREATE a feature branch:
262
+ git checkout -b feature/your-feature-name
263
+ (or fix/, refactor/, chore/, test/ as appropriate)
264
+
265
+ 2. CONTINUE your work on the new branch
266
+
267
+ 3. When done, create PR to merge back to main
268
+
269
+ NEVER commit directly to main. The stop hook will BLOCK this.
270
+ ================================================================================`
271
+ };
272
+ }
273
+
274
+ return null; // All good - on main with clean tree
275
+ }
276
+
277
+ function validateGitTree(modifiedFiles: string[]): ValidationError | null {
278
+ if (modifiedFiles.length === 0) return null;
279
+
280
+ const fileList = modifiedFiles.slice(0, 15).map(f => ` - ${f}`).join('\n');
281
+
282
+ return {
283
+ type: 'GIT_TREE_NOT_CLEAN',
284
+ message: `Git working tree is not clean. Found ${modifiedFiles.length} modified/untracked file(s).`,
285
+ action: `
286
+ ================================================================================
287
+ GIT TREE MUST BE CLEAN FOR TASK COMPLETION
288
+ ================================================================================
289
+
290
+ Modified files:
291
+ ${fileList}${modifiedFiles.length > 15 ? '\n ... and more' : ''}
292
+
293
+ The task cannot complete with uncommitted work.
294
+
295
+ OPTIONS:
296
+
297
+ 1. COMMIT the changes (recommended):
298
+ git add -A
299
+ git commit -m "type: description"
300
+ git push
301
+
302
+ 2. STASH for later:
303
+ git stash push -m "WIP: description"
304
+
305
+ 3. DISCARD changes (use with caution):
306
+ git checkout -- .
307
+ git clean -fd
308
+
309
+ After cleaning the tree, the stop hook will pass.
310
+ ================================================================================`
311
+ };
312
+ }
313
+
314
+ function validateClaudeMdExists(): ValidationError | null {
315
+ if (!existsSync(CLAUDE_MD_PATH)) {
316
+ return {
317
+ type: 'CLAUDE_MD_MISSING',
318
+ message: 'CLAUDE.md file not found at project root.',
319
+ action: `
320
+ ================================================================================
321
+ CLAUDE.MD IS REQUIRED
322
+ ================================================================================
323
+
324
+ The project MUST have a CLAUDE.md file at the root with these sections:
325
+
326
+ # Project Name
327
+
328
+ ## Last Change
329
+ **Branch:** branch-name
330
+ **Date:** YYYY-MM-DD
331
+ **Summary:** What was done in this session
332
+
333
+ ## 30 Seconds Overview
334
+ Quick description of what this project does.
335
+
336
+ ## Stack
337
+ | Component | Technology |
338
+ |-----------|------------|
339
+ | Runtime | Bun |
340
+ | Language | TypeScript |
341
+ | Database | MongoDB |
342
+
343
+ ## Architecture
344
+ Project structure and key directories.
345
+
346
+ CREATE this file before the task can complete.
347
+ ================================================================================`
348
+ };
349
+ }
350
+ return null;
351
+ }
352
+
353
+ function validateClaudeMdSize(): ValidationError | null {
354
+ if (!existsSync(CLAUDE_MD_PATH)) return null;
355
+
356
+ const content = readFileSync(CLAUDE_MD_PATH, 'utf8');
357
+ if (content.length <= MAX_CHARACTERS) return null;
358
+
359
+ const excess = content.length - MAX_CHARACTERS;
360
+
361
+ return {
362
+ type: 'CLAUDE_MD_SIZE_EXCEEDED',
363
+ message: `CLAUDE.md exceeds 40,000 character limit by ${excess} characters (current: ${content.length}).`,
364
+ action: `
365
+ ================================================================================
366
+ CLAUDE.MD MUST BE COMPACTED (MAX 40,000 CHARACTERS)
367
+ ================================================================================
368
+
369
+ Current size: ${content.length} characters
370
+ Maximum allowed: ${MAX_CHARACTERS} characters
371
+ Excess: ${excess} characters
372
+
373
+ COMPACTION RULES (what to keep vs remove):
374
+
375
+ KEEP (critical):
376
+ - # Project Title
377
+ - ## Last Change (only the MOST RECENT)
378
+ - ## 30 Seconds Overview
379
+ - ## Stack
380
+ - ## Architecture
381
+ - ## Critical Rules
382
+ - ## FORBIDDEN Actions
383
+ - ## Quality Gates
384
+
385
+ REMOVE/CONDENSE:
386
+ - Verbose explanations (use bullet points)
387
+ - Duplicate information
388
+ - Old/outdated sections
389
+ - Long code examples (keep minimal)
390
+ - Multiple "Last Change" entries (keep only latest)
391
+
392
+ After editing, verify: wc -m CLAUDE.md
393
+ ================================================================================`
394
+ };
395
+ }
396
+
397
+ function validateClaudeMdStructure(): ValidationError | null {
398
+ if (!existsSync(CLAUDE_MD_PATH)) return null;
399
+
400
+ const content = readFileSync(CLAUDE_MD_PATH, 'utf8');
401
+ const missingSections: string[] = [];
402
+
403
+ for (const section of REQUIRED_SECTIONS) {
404
+ if (!section.pattern.test(content)) {
405
+ missingSections.push(section.name);
406
+ }
407
+ }
408
+
409
+ if (missingSections.length === 0) return null;
410
+
411
+ return {
412
+ type: 'CLAUDE_MD_MISSING_SECTIONS',
413
+ message: `CLAUDE.md is missing required sections: ${missingSections.join(', ')}`,
414
+ action: `
415
+ ================================================================================
416
+ CLAUDE.MD MISSING REQUIRED SECTIONS
417
+ ================================================================================
418
+
419
+ Missing sections:
420
+ ${missingSections.map(s => ` - ${s}`).join('\n')}
421
+
422
+ REQUIRED STRUCTURE:
423
+
424
+ # Project Name <- H1 title
425
+
426
+ ## Last Change <- ONLY the most recent change
427
+ **Branch:** feature/xxx
428
+ **Date:** YYYY-MM-DD
429
+ **Summary:** What was done
156
430
 
157
- for (const filePath of modifiedFiles) {
158
- if (!isSourceFile(filePath)) continue;
431
+ ## 30 Seconds Overview <- Quick project description
159
432
 
160
- if (searchInDocs(projectDir, filePath)) {
161
- documented.push(filePath);
162
- } else {
433
+ ## Stack <- Technology table
434
+
435
+ ## Architecture <- Project structure
436
+
437
+ ADD the missing sections before the task can complete.
438
+ ================================================================================`
439
+ };
440
+ }
441
+
442
+ function validateClaudeMdLastChange(): ValidationError | null {
443
+ if (!existsSync(CLAUDE_MD_PATH)) return null;
444
+
445
+ const content = readFileSync(CLAUDE_MD_PATH, 'utf8');
446
+ const lastChangeMatch = content.match(/## Last Change\n([\s\S]*?)(?=\n## |$)/);
447
+
448
+ if (!lastChangeMatch) return null; // Covered by structure check
449
+
450
+ const lastChangeContent = lastChangeMatch[1].trim();
451
+
452
+ // Check for meaningful content
453
+ if (lastChangeContent.length < 50) {
454
+ return {
455
+ type: 'CLAUDE_MD_LAST_CHANGE_EMPTY',
456
+ message: 'The "Last Change" section exists but lacks sufficient content.',
457
+ action: `
458
+ ================================================================================
459
+ UPDATE "LAST CHANGE" SECTION
460
+ ================================================================================
461
+
462
+ The "## Last Change" section must contain:
463
+
464
+ **Branch:** the-branch-name-used
465
+ **Date:** ${new Date().toISOString().split('T')[0]}
466
+ **Summary:** 1-2 sentences describing what was changed/implemented
467
+
468
+ Example:
469
+ ## Last Change
470
+
471
+ **Branch:** feature/add-auth
472
+ **Date:** 2025-01-05
473
+ **Summary:** Implemented JWT authentication with refresh tokens and session management.
474
+
475
+ IMPORTANT: This section should ONLY contain the LAST change, not a history.
476
+ ================================================================================`
477
+ };
478
+ }
479
+
480
+ // Check for multiple Last Change sections (stacking is forbidden)
481
+ const multipleChanges = content.match(/## Last Change/g);
482
+ if (multipleChanges && multipleChanges.length > 1) {
483
+ return {
484
+ type: 'CLAUDE_MD_STACKED_CHANGES',
485
+ message: `Found ${multipleChanges.length} "## Last Change" sections. Only ONE is allowed.`,
486
+ action: `
487
+ ================================================================================
488
+ REMOVE STACKED CHANGES - KEEP ONLY THE LATEST
489
+ ================================================================================
490
+
491
+ Rule: CLAUDE.md should only have ONE "## Last Change" section.
492
+ Previous changes belong in git history, not in the documentation.
493
+
494
+ Found ${multipleChanges.length} instances of "## Last Change".
495
+
496
+ ACTION: Remove all but the most recent "## Last Change" section.
497
+
498
+ This keeps the file focused and within the 40k character limit.
499
+ ================================================================================`
500
+ };
501
+ }
502
+
503
+ return null;
504
+ }
505
+
506
+ function validateClaudeMdUpdated(modifiedFiles: string[]): ValidationError | null {
507
+ // If no source files modified, no need to check
508
+ const sourceFiles = modifiedFiles.filter(isSourceFile);
509
+ if (sourceFiles.length === 0) return null;
510
+
511
+ // Check if CLAUDE.md is in the modified files
512
+ const claudeMdModified = modifiedFiles.some(f =>
513
+ f === 'CLAUDE.md' || f.endsWith('/CLAUDE.md') || f.endsWith('\\CLAUDE.md')
514
+ );
515
+
516
+ if (claudeMdModified) return null;
517
+
518
+ return {
519
+ type: 'CLAUDE_MD_NOT_UPDATED',
520
+ message: `${sourceFiles.length} source file(s) were modified but CLAUDE.md was not updated.`,
521
+ action: `
522
+ ================================================================================
523
+ UPDATE CLAUDE.MD WITH SESSION CHANGES (MANDATORY)
524
+ ================================================================================
525
+
526
+ You modified source files but did not update CLAUDE.md.
527
+
528
+ Modified source files:
529
+ ${sourceFiles.slice(0, 10).map(f => ` - ${f}`).join('\n')}${sourceFiles.length > 10 ? '\n ... and more' : ''}
530
+
531
+ REQUIRED UPDATES TO CLAUDE.MD:
532
+
533
+ 1. Update "## Last Change" section:
534
+ **Branch:** current-branch-name
535
+ **Date:** ${new Date().toISOString().split('T')[0]}
536
+ **Summary:** What you implemented/fixed
537
+
538
+ 2. If architecture changed:
539
+ Update "## Architecture" section
540
+
541
+ 3. If new patterns/rules were established:
542
+ Add to appropriate section
543
+
544
+ 4. If user mentioned preferences or corrections:
545
+ Add as rules in relevant section
546
+
547
+ CONTEXT SYNTHESIS:
548
+ Think about what the user asked and what you learned.
549
+ Capture important decisions and patterns for the next session.
550
+
551
+ The stop hook will BLOCK until CLAUDE.md is updated.
552
+ ================================================================================`
553
+ };
554
+ }
555
+
556
+ function validateDocumentation(sourceFiles: string[]): ValidationError | null {
557
+ if (sourceFiles.length === 0) return null;
558
+
559
+ const undocumented: string[] = [];
560
+ for (const filePath of sourceFiles) {
561
+ if (!searchInDocs(filePath)) {
163
562
  undocumented.push(filePath);
164
563
  }
165
564
  }
166
565
 
167
- return { undocumented, documented };
566
+ if (undocumented.length === 0) return null;
567
+
568
+ const fileList = undocumented.slice(0, 15).map(f => ` - ${f}`).join('\n');
569
+
570
+ return {
571
+ type: 'SOURCE_FILES_NOT_DOCUMENTED',
572
+ message: `${undocumented.length} source file(s) are not documented.`,
573
+ action: `
574
+ ================================================================================
575
+ DOCUMENT ALL MODIFIED SOURCE FILES (MANDATORY)
576
+ ================================================================================
577
+
578
+ Undocumented files:
579
+ ${fileList}${undocumented.length > 15 ? '\n ... and more' : ''}
580
+
581
+ REQUIRED ACTION:
582
+
583
+ Run the documenter agent to update documentation:
584
+
585
+ Task(subagent_type="documenter", prompt="Update documentation for all modified files")
586
+
587
+ The documenter will:
588
+ 1. Detect changed files via git diff
589
+ 2. Update domain files in .claude/skills/codebase-knowledge/domains/
590
+ 3. Update docs/ as needed
591
+ 4. Ensure all modified files are mentioned in documentation
592
+
593
+ A file is considered documented if its name appears in:
594
+ - docs/ folder
595
+ - .claude/skills/codebase-knowledge/domains/ folder
596
+
597
+ The stop hook will BLOCK until all source files are documented.
598
+ ================================================================================`
599
+ };
168
600
  }
169
601
 
602
+ // ============================================================================
603
+ // MAIN HOOK LOGIC
604
+ // ============================================================================
605
+
170
606
  interface HookInput {
171
607
  stop_hook_active?: boolean;
172
608
  }
@@ -205,8 +641,6 @@ async function readStdinWithTimeout(timeoutMs: number): Promise<string> {
205
641
  }
206
642
 
207
643
  async function main(): Promise<void> {
208
- const projectDir = process.env['CLAUDE_PROJECT_DIR'] || process.cwd();
209
-
210
644
  let hookInput: HookInput = {};
211
645
  try {
212
646
  const stdin = await readStdinWithTimeout(1000);
@@ -224,122 +658,107 @@ async function main(): Promise<void> {
224
658
  process.exit(0);
225
659
  }
226
660
 
227
- const currentBranch = getCurrentBranch(projectDir);
228
- const modifiedFiles = getModifiedFiles(projectDir);
661
+ // Gather state
662
+ const currentBranch = getCurrentBranch();
663
+ const modifiedFiles = getModifiedFiles();
229
664
  const sourceFiles = modifiedFiles.filter(isSourceFile);
230
- const systemConfigFiles = modifiedFiles.filter(isSystemConfigFile);
665
+ const isMainBranch = currentBranch === 'main' || currentBranch === 'master';
666
+ const isCleanTree = modifiedFiles.length === 0;
231
667
 
232
- const errors: Array<{ type: string; message: string }> = [];
668
+ // Run all validations
669
+ const errors: ValidationError[] = [];
233
670
 
234
- // Check 1: ANY changes on main branch are FORBIDDEN
235
- if ((currentBranch === 'main' || currentBranch === 'master') && modifiedFiles.length > 0) {
236
- const fileList = modifiedFiles.slice(0, 15).map(f => ` - ${f}`).join('\n');
237
- const more = modifiedFiles.length > 15 ? '\n ... and more' : '';
671
+ // Validation order matters - most critical first
672
+ const branchError = validateBranch(currentBranch, modifiedFiles);
673
+ if (branchError) errors.push(branchError);
238
674
 
239
- errors.push({
240
- type: 'DIRECT_MAIN_COMMIT',
241
- message: `
242
- BLOCKED: Attempting to work directly on '${currentBranch}' branch!
675
+ // Only check these if we're close to completion (on main or clean tree)
676
+ if (isMainBranch || isCleanTree) {
677
+ const treeError = validateGitTree(modifiedFiles);
678
+ if (treeError) errors.push(treeError);
679
+ }
243
680
 
244
- You have ${modifiedFiles.length} modified file(s):
245
- ${fileList}${more}
681
+ const claudeMdExistsError = validateClaudeMdExists();
682
+ if (claudeMdExistsError) errors.push(claudeMdExistsError);
246
683
 
247
- REQUIRED ACTION:
248
- 1. Create a feature branch: git checkout -b feature/[name]
249
- 2. Or fix/chore branch: git checkout -b fix/[name] or git checkout -b chore/[name]
250
- 3. Continue your work on the new branch
251
- 4. Create PR to merge back to main
684
+ if (!claudeMdExistsError) {
685
+ const sizeError = validateClaudeMdSize();
686
+ if (sizeError) errors.push(sizeError);
252
687
 
253
- NEVER make ANY changes directly on main. ALL work must be done on branches.
254
- `
255
- });
256
- }
688
+ const structureError = validateClaudeMdStructure();
689
+ if (structureError) errors.push(structureError);
257
690
 
258
- // Check 2: Documentation for source files
259
- if (sourceFiles.length > 0) {
260
- const { undocumented } = validateDocumentation(projectDir, sourceFiles);
691
+ const lastChangeError = validateClaudeMdLastChange();
692
+ if (lastChangeError) errors.push(lastChangeError);
261
693
 
262
- if (undocumented.length > 0) {
263
- const fileList = undocumented.slice(0, 15).map(f => ` - ${f}`).join('\n');
264
- const more = undocumented.length > 15 ? '\n ... and more' : '';
694
+ const updatedError = validateClaudeMdUpdated(modifiedFiles);
695
+ if (updatedError) errors.push(updatedError);
696
+ }
265
697
 
266
- errors.push({
267
- type: 'MISSING_DOCUMENTATION',
268
- message: `
269
- BLOCKED: ${undocumented.length} source file(s) are NOT documented!
698
+ const docError = validateDocumentation(sourceFiles);
699
+ if (docError) errors.push(docError);
270
700
 
271
- Undocumented files:
272
- ${fileList}${more}
701
+ // ============================================================================
702
+ // OUTPUT RESULTS
703
+ // ============================================================================
273
704
 
274
- REQUIRED ACTION:
275
- Run the documenter agent to update documentation:
705
+ if (errors.length > 0) {
706
+ let output = `
707
+ ################################################################################
708
+ # STOP VALIDATOR - TASK COMPLETION BLOCKED #
709
+ ################################################################################
276
710
 
277
- Task(subagent_type="documenter", prompt="Update documentation for all modified files")
711
+ ${errors.length} validation(s) failed. You MUST fix these before the task can complete.
278
712
 
279
- The documenter will:
280
- 1. Detect changed files via git diff
281
- 2. Update domain files in .claude/skills/codebase-knowledge/domains/
282
- 3. Update docs/CHANGELOG.md
283
- 4. Ensure all modified files are mentioned in documentation
713
+ `;
284
714
 
285
- DOCUMENTATION IS MANDATORY before task completion.
286
- `
287
- });
288
- }
289
- }
715
+ for (let i = 0; i < errors.length; i++) {
716
+ const err = errors[i];
717
+ output += `
718
+ --------------------------------------------------------------------------------
719
+ ERROR ${i + 1}/${errors.length}: ${err.type}
720
+ --------------------------------------------------------------------------------
290
721
 
291
- if (errors.length > 0) {
292
- let errorOutput = `
293
- ================================================================================
294
- STOP VALIDATOR - BLOCKING TASK COMPLETION
295
- ================================================================================
296
- `;
297
- for (const err of errors) {
298
- errorOutput += `
299
- --- ${err.type} ---
300
722
  ${err.message}
723
+
724
+ ${err.action}
301
725
  `;
302
726
  }
303
727
 
304
- errorOutput += `
305
- ================================================================================
306
- FIX THE ABOVE ISSUES BEFORE COMPLETING THE TASK
307
- ================================================================================
728
+ output += `
729
+ ################################################################################
730
+ # FIX ALL ERRORS ABOVE BEFORE TASK CAN COMPLETE #
731
+ ################################################################################
732
+
733
+ SYNTHESIS REMINDER:
734
+ Before completing, ask yourself:
735
+ - Did the user mention any preferences I should remember?
736
+ - Did I learn any patterns that should be documented?
737
+ - Were there any corrections I should add as rules?
738
+
739
+ Update CLAUDE.md with any learnings from this session.
308
740
  `;
309
741
 
310
- const result: HookResult = { decision: 'block', reason: errorOutput.trim() };
742
+ const result: HookResult = { decision: 'block', reason: output.trim() };
311
743
  console.log(JSON.stringify(result));
312
744
  process.exit(0);
313
745
  }
314
746
 
315
747
  // All validations passed
316
- let nextStepMessage: string;
317
- if (modifiedFiles.length > 0) {
318
- nextStepMessage = `
319
- ================================================================================
320
- ✓ ALL VALIDATIONS PASSED
321
- ================================================================================
748
+ const successOutput = `
749
+ ################################################################################
750
+ # STOP VALIDATOR - ALL CHECKS PASSED #
751
+ ################################################################################
322
752
 
323
753
  Branch: ${currentBranch}
324
- Modified files: ${modifiedFiles.length} (source: ${sourceFiles.length}, config: ${systemConfigFiles.length})
325
-
326
- MANDATORY NEXT STEP:
327
- You MUST now commit, push, and create a PR:
328
-
329
- 1. git add -A
330
- 2. git commit with conventional commit message
331
- 3. git push -u origin ${currentBranch}
332
- 4. gh pr create to main branch
754
+ Tree: ${isCleanTree ? 'Clean' : `${modifiedFiles.length} modified files`}
755
+ CLAUDE.md: Valid
333
756
 
334
- DO NOT ask the user - just execute the commit-manager flow.
335
-
336
- ================================================================================
757
+ All validations passed. Task may complete.
758
+ ################################################################################
337
759
  `;
338
- } else {
339
- nextStepMessage = `All validations passed. Branch: ${currentBranch}, no files modified.`;
340
- }
341
760
 
342
- const result: HookResult = { decision: 'approve', reason: nextStepMessage.trim() };
761
+ const result: HookResult = { decision: 'approve', reason: successOutput.trim() };
343
762
  console.log(JSON.stringify(result));
344
763
  process.exit(0);
345
764
  }
@@ -29,14 +29,18 @@ const STRICT_WORKFLOW = `
29
29
  │ 4. BRANCH → Create feature/ | fix/ | refactor/ | test/ │
30
30
  │ 5. IMPLEMENT → Follow rules + analyzer approval │
31
31
  │ 6. DOCUMENT → Document ALL modified files (MANDATORY) │
32
- │ 7. QUALITY typecheck + lint + test (Husky enforced)
33
- │ 8. FINISH commit-manager creates PR with task summary
32
+ │ 7. UPDATE Update CLAUDE.md with session changes
33
+ │ 8. QUALITY typecheck + lint + test (Husky enforced)
34
+ │ 9. FINISH → PR + merge to main (clean tree required) │
34
35
  └─────────────────────────────────────────────────────────────────┘
35
36
 
36
37
  ⚠️ STOP HOOK ACTIVE - Task completion will be BLOCKED if:
37
- - Working directly on main branch (must use feature/fix branch)
38
- - Source files not documented (must run documenter agent)
39
- - Documenter agent not executed for code changes
38
+ - NOT on main branch (PR must be merged first)
39
+ - Git tree NOT clean (all changes must be committed)
40
+ - CLAUDE.md NOT updated (must reflect session changes)
41
+ - CLAUDE.md missing required sections (Last Change, Stack, etc.)
42
+ - CLAUDE.md exceeds 40,000 characters (must compact)
43
+ - Source files NOT documented (must run documenter agent)
40
44
  `;
41
45
 
42
46
  // ============================================================================
@@ -725,11 +729,36 @@ async function main(): Promise<void> {
725
729
 
726
730
  const recommendedStr = bestAgents.map(([cat, agent, reason], i) => ` ${i + 1}. ${cat}/${agent} - ${reason}`).join('\n');
727
731
 
732
+ const claudeMdReminder = `
733
+ ================================================================================
734
+ CLAUDE.MD UPDATE REQUIREMENT (MANDATORY)
735
+ ================================================================================
736
+
737
+ Before completing ANY task, you MUST update CLAUDE.md at project root with:
738
+
739
+ 1. "## Last Change" section (ONLY keep the latest, do NOT stack):
740
+ **Branch:** your-branch-name
741
+ **Date:** ${new Date().toISOString().split('T')[0]}
742
+ **Summary:** What you implemented/fixed
743
+
744
+ 2. Update "## Architecture" if structure changed
745
+
746
+ 3. Add new rules/patterns learned to appropriate sections
747
+
748
+ 4. SYNTHESIZE: If user mentioned preferences or corrections, add as rules
749
+
750
+ CHARACTER LIMIT: 40,000 max. If exceeded, COMPACT the file (keep critical sections).
751
+
752
+ STOP HOOK WILL BLOCK if CLAUDE.md is not properly updated!
753
+ ================================================================================
754
+ `;
755
+
728
756
  const output = `
729
757
  ================================================================================
730
758
  STRICT WORKFLOW ENFORCEMENT - UserPromptSubmit Hook
731
759
  ================================================================================
732
760
  ${STRICT_WORKFLOW}
761
+ ${claudeMdReminder}
733
762
 
734
763
  ${isNewFeature ? '⚠️ NEW FEATURE DETECTED - RESEARCH AGENT IS MANDATORY!' : ''}
735
764
  ${isUiTask ? '⚠️ UI TASK DETECTED - SEPARATE UIs FOR MOBILE/TABLET/DESKTOP REQUIRED!' : ''}
@@ -4,16 +4,47 @@
4
4
 
5
5
  ---
6
6
 
7
- ## Workflow
7
+ ## Workflow (STRICT FLOW)
8
8
 
9
9
  ```
10
- 1. READ AGENTS .claude/agents/*.md
11
- 2. START TASK python .claude/hooks/workflow-manager.py start-task --type feature --description "..."
12
- 3. IMPLEMENT Follow project rules
13
- 4. QUALITY CHECK Run all quality gates
14
- 5. COMMIT Conventional commits
10
+ 0. INIT TASK Run commit-manager to REGISTER task start
11
+ 1. TODO LIST ALWAYS create detailed todo list from prompt
12
+ 2. RESEARCH Run research agent for NEW features (MANDATORY)
13
+ 3. AUDIT Check docs from last audit OR run fresh audit
14
+ 4. CREATE BRANCH feature/ | fix/ | refactor/ | test/
15
+ 5. IMPLEMENT → Follow project rules + analyzer approval
16
+ 6. DOCUMENT → Document ALL modified files (MANDATORY)
17
+ 7. QUALITY GATES → Run typecheck && lint && test (Husky enforced)
18
+ 8. FINISH → commit-manager creates PR with task summary
15
19
  ```
16
20
 
21
+ > **CRITICAL:** Research agent is MANDATORY for any new feature or complex bug fix.
22
+ > **CRITICAL:** All documentation must reference commit hashes for audit trail.
23
+ > **CRITICAL:** Stop hook BLOCKS task completion if files not documented.
24
+ > **FALLBACK:** If Task tool fails to invoke an agent, READ the agent file directly from `.claude/agents/[agent-name].md` and follow its instructions manually.
25
+
26
+ ---
27
+
28
+ ## MCP Servers (MANDATORY)
29
+
30
+ Configure these in `.mcp.json` at project root:
31
+
32
+ | Server | Purpose | When to Use |
33
+ | ------------------- | ----------------------------------------- | ---------------------------------------- |
34
+ | `context7` | Up-to-date library documentation | Before implementing with ANY library |
35
+ | `sequential-thinking` | Complex problem-solving | Multi-step tasks, planning |
36
+ | `memory` | Persistent knowledge graph | Store/recall project patterns |
37
+ | `playwright` | Browser automation and E2E testing | UI testing, page verification |
38
+ | `nextjs-devtools` | Next.js specific development tools | Next.js projects only |
39
+ | `mongodb` | MongoDB database operations | Database queries, schema inspection |
40
+
41
+ ### Usage Rules
42
+
43
+ - **ALWAYS** use `context7` before implementing features with external libraries
44
+ - **ALWAYS** use `playwright` for E2E tests instead of manual browser testing
45
+ - **ALWAYS** check `memory` for existing patterns before creating new ones
46
+ - **NEVER** hardcode library APIs - query `context7` for current docs
47
+
17
48
  ---
18
49
 
19
50
  ## Agent System
@@ -36,6 +67,18 @@ This project uses 11 specialized AI agents:
36
67
 
37
68
  ---
38
69
 
70
+ ## Stop Hook Enforcement
71
+
72
+ The Stop hook runs when Claude is about to finish and BLOCKS if:
73
+
74
+ | Violation | Action Required |
75
+ |-----------|-----------------|
76
+ | On main branch with source changes | Create feature/fix branch first |
77
+ | Source files not documented | Run documenter agent |
78
+ | Documenter not executed | Invoke documenter via Task tool |
79
+
80
+ ---
81
+
39
82
  ## Configuration
40
83
 
41
84
  Edit these files in `.claude/config/` for your project:
@@ -46,39 +89,17 @@ Edit these files in `.claude/config/` for your project:
46
89
  | `quality-gates.json` | Quality check commands |
47
90
  | `testing-config.json` | Test framework config |
48
91
  | `security-rules.json` | Security audit rules |
49
-
50
- ---
51
-
52
- ## Quick Start
53
-
54
- ```bash
55
- # 1. Start a task
56
- python .claude/hooks/workflow-manager.py start-task --type feature --description "Add user authentication"
57
-
58
- # 2. Approve files for modification
59
- python .claude/hooks/workflow-manager.py approve-files --files "src/auth/*.ts"
60
-
61
- # 3. Mark agents as executed
62
- python .claude/hooks/workflow-manager.py agent-executed --agent analyzer --result approved
63
-
64
- # 4. Run quality gates
65
- python .claude/hooks/workflow-manager.py quality-gate --gate typecheck --passed true
66
-
67
- # 5. Final validation
68
- python .claude/hooks/workflow-manager.py final-validation --result approved --ready-to-commit true
69
-
70
- # 6. Complete task
71
- python .claude/hooks/workflow-manager.py complete-task --commit-hash abc123
72
- ```
92
+ | `domain-mapping.json` | File patterns to domains |
73
93
 
74
94
  ---
75
95
 
76
96
  ## Critical Rules
77
97
 
78
- 1. **ALWAYS start task first** - Hooks block without active task
79
- 2. **ALWAYS approve files** - Pre-tool-use hook blocks unapproved edits
98
+ 1. **ALWAYS use MCP servers** - Context7 for docs, Playwright for E2E
99
+ 2. **ALWAYS start with todo list** - Track progress with TodoWrite tool
80
100
  3. **NEVER skip agents** - Stop hook blocks incomplete workflows
81
101
  4. **ALWAYS use conventional commits** - feat:, fix:, refactor:, docs:
102
+ 5. **NEVER commit to main** - Create feature/fix branches
82
103
 
83
104
  ---
84
105