@champpaba/claude-agent-kit 3.0.3 → 3.2.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.
@@ -318,1531 +318,310 @@ Continue anyway? (yes/no)
318
318
 
319
319
  ---
320
320
 
321
- ### Step 2.6: Adaptive Depth Research (v2.4.0)
321
+ ### Step 2.6: Generate Pre-Work Context (v3.2.0 - Consolidated)
322
322
 
323
- > **NEW:** Dynamic research layers based on change complexity - replaces hardcoded feature detection
324
- > **WHY:** Different changes need different research depth. A typo fix needs 0 layers, a healthcare portal needs 10+.
325
- > **Output:** `openspec/changes/{changeId}/research-checklist.md`
323
+ > **EXECUTE THESE STEPS** - Not pseudocode, actual instructions for Main Claude
324
+ > **Output:** `openspec/changes/{changeId}/pre-work-context.md`
325
+ > **Purpose:** Single file containing ALL context agents need before implementation
326
326
 
327
- **Key Principles:**
328
- - Layer 1 is ALWAYS "Best Practice" (คนอื่นทำกันยังไง? / How do others do it?)
329
- - Layer 2+ determined dynamically based on change context
330
- - No fixed minimum or maximum - truly adaptive (0 to 10+ layers)
331
- - Visual design (from /designsetup) is STATIC - this only handles Strategy (WHAT/WHERE)
332
- - Warns if industry practice conflicts with user's design choices
327
+ **This step consolidates:**
328
+ - Adaptive Depth Research (domain knowledge)
329
+ - Library Best Practices (from Context7)
330
+ - Integration Warnings (cross-library concerns)
331
+ - Critical Checklists (security/compliance requirements)
333
332
 
334
- ```typescript
335
- output(`\n🔬 Adaptive Depth Research Analysis...`)
336
-
337
- // 1. Gather change context from all spec files
338
- const proposalPath = `openspec/changes/${changeId}/proposal.md`
339
- const tasksPath = `openspec/changes/${changeId}/tasks.md`
340
- const designPath = `openspec/changes/${changeId}/design.md`
341
-
342
- const proposal = fileExists(proposalPath) ? Read(proposalPath) : ''
343
- const tasks = fileExists(tasksPath) ? Read(tasksPath) : ''
344
- const design = fileExists(designPath) ? Read(designPath) : ''
345
- const combined = (proposal + '\n' + tasks + '\n' + design).toLowerCase()
346
-
347
- // 2. Analyze change characteristics using semantic understanding
348
- const changeAnalysis = analyzeChangeCharacteristics(combined, proposal, tasks)
349
-
350
- output(`\n📊 Change Analysis:`)
351
- output(` Type: ${changeAnalysis.primaryType}`)
352
- output(` Complexity: ${changeAnalysis.complexity}/10`)
353
- output(` Risk Level: ${changeAnalysis.riskLevel}`)
354
- output(` Target Audience: ${changeAnalysis.audience || 'Internal'}`)
355
-
356
- // 3. Determine required research layers based on change characteristics
357
- const requiredLayers = determineResearchLayers(changeAnalysis)
358
-
359
- output(`\n📚 Research Layers Required: ${requiredLayers.length}`)
360
-
361
- if (requiredLayers.length === 0) {
362
- output(` ✅ No research needed - trivial change`)
363
- output(` (Typo fix, debug log, simple badge, etc.)`)
364
- } else {
365
- requiredLayers.forEach((layer, idx) => {
366
- output(` L${idx + 1}: ${layer.name}`)
367
- output(` Focus: ${layer.focus}`)
368
- output(` Questions: ${layer.questions.slice(0, 2).join(', ')}...`)
369
- })
370
- }
371
-
372
- // 4. Execute research for each layer using Context7 + semantic analysis
373
- const researchResults = []
374
-
375
- for (const layer of requiredLayers) {
376
- output(`\n🔍 Researching L${layer.order}: ${layer.name}...`)
377
-
378
- const layerResult = await executeLayerResearch(layer, changeAnalysis)
379
- researchResults.push(layerResult)
380
-
381
- output(` ✅ Found ${layerResult.findings.length} key findings`)
382
- if (layerResult.warnings.length > 0) {
383
- layerResult.warnings.forEach(w => output(` ⚠️ ${w}`))
384
- }
385
- }
333
+ ---
386
334
 
387
- // 5. Check for conflicts with design system (if exists)
388
- const tokensPath = 'design-system/data.yaml'
389
- if (fileExists(tokensPath) && researchResults.length > 0) {
390
- const tokens = parseYaml(Read(tokensPath))
391
- const conflicts = checkDesignConflicts(tokens, researchResults, changeAnalysis)
392
-
393
- if (conflicts.length > 0) {
394
- output(`\n⚠️ Design vs Industry Fit Conflicts:`)
395
- conflicts.forEach(c => {
396
- output(` - ${c.aspect}: Your design uses "${c.current}", but ${c.industry}`)
397
- output(` Recommendation: ${c.recommendation}`)
398
- })
399
- output(`\n Note: User design choices take precedence. These are informational warnings.`)
400
- }
401
- }
335
+ #### Step 2.6.1: Analyze Change Characteristics
402
336
 
403
- // 6. Generate research-checklist.md
404
- const checklistPath = `openspec/changes/${changeId}/research-checklist.md`
405
- const checklistContent = generateResearchChecklist(changeAnalysis, requiredLayers, researchResults)
337
+ **Read and analyze these files:**
338
+ - `openspec/changes/{changeId}/proposal.md`
339
+ - `openspec/changes/{changeId}/tasks.md`
340
+ - `openspec/changes/{changeId}/design.md` (if exists)
406
341
 
407
- Write(checklistPath, checklistContent)
408
- output(`\n✅ Generated: ${checklistPath}`)
342
+ **Determine:**
343
+ 1. **Primary Type:** marketing | dashboard | api | auth | database | general
344
+ 2. **Complexity (1-10):** Based on features, integrations, external APIs
345
+ 3. **Risk Level:** LOW | MEDIUM | HIGH
346
+ 4. **Domains:** healthcare, fintech, ecommerce, saas (if applicable)
347
+ 5. **Features:** payment, auth, multi-tenancy, realtime (if detected)
409
348
 
410
- // Store for use by agents
411
- const adaptiveResearch = {
412
- layerCount: requiredLayers.length,
413
- layers: requiredLayers.map(l => l.name),
414
- complexity: changeAnalysis.complexity,
415
- checklistPath: checklistPath
416
- }
349
+ **Output:**
350
+ ```
351
+ 📊 Change Analysis:
352
+ Type: auth
353
+ Complexity: 6/10
354
+ Risk Level: HIGH
355
+ Domains: fintech
356
+ Features: payment, auth
417
357
  ```
418
358
 
419
- #### Helper Functions
420
-
421
- ```typescript
422
- // Analyze change characteristics using semantic understanding
423
- function analyzeChangeCharacteristics(combined, proposal, tasks) {
424
- const analysis = {
425
- primaryType: 'general',
426
- complexity: 1,
427
- riskLevel: 'LOW',
428
- audience: 'internal',
429
- domains: [],
430
- features: [],
431
- hasUI: false,
432
- hasAPI: false,
433
- hasDatabase: false,
434
- hasPayment: false,
435
- hasAuth: false,
436
- hasCompliance: false,
437
- hasSensitiveData: false,
438
- isExternalFacing: false,
439
- industryContext: null
440
- }
441
-
442
- // Detect primary type
443
- if (/marketing|landing|hero|cta|conversion|sales/i.test(combined)) {
444
- analysis.primaryType = 'marketing'
445
- analysis.isExternalFacing = true
446
- } else if (/dashboard|admin|management|analytics/i.test(combined)) {
447
- analysis.primaryType = 'dashboard'
448
- } else if (/api|endpoint|rest|graphql/i.test(combined)) {
449
- analysis.primaryType = 'api'
450
- } else if (/auth|login|register|password/i.test(combined)) {
451
- analysis.primaryType = 'auth'
452
- analysis.hasAuth = true
453
- } else if (/database|schema|migration|model/i.test(combined)) {
454
- analysis.primaryType = 'database'
455
- analysis.hasDatabase = true
456
- }
457
-
458
- // Detect features and domains
459
- if (/payment|stripe|billing|checkout|subscription/i.test(combined)) {
460
- analysis.hasPayment = true
461
- analysis.features.push('payment')
462
- analysis.riskLevel = 'HIGH'
463
- }
464
- if (/health|medical|patient|hipaa|phi/i.test(combined)) {
465
- analysis.hasCompliance = true
466
- analysis.hasSensitiveData = true
467
- analysis.domains.push('healthcare')
468
- analysis.industryContext = 'healthcare'
469
- analysis.riskLevel = 'HIGH'
470
- }
471
- if (/fintech|banking|finance|pci|financial/i.test(combined)) {
472
- analysis.hasCompliance = true
473
- analysis.domains.push('fintech')
474
- analysis.industryContext = 'fintech'
475
- analysis.riskLevel = 'HIGH'
476
- }
477
- if (/saas|multi-tenant|tenant/i.test(combined)) {
478
- analysis.domains.push('saas')
479
- analysis.features.push('multi-tenancy')
480
- }
481
- if (/ecommerce|e-commerce|cart|product|shop/i.test(combined)) {
482
- analysis.domains.push('ecommerce')
483
- analysis.isExternalFacing = true
484
- }
485
- if (/realtime|real-time|websocket|collaboration/i.test(combined)) {
486
- analysis.features.push('realtime')
487
- }
488
-
489
- // Detect UI/API/Database
490
- analysis.hasUI = /ui|page|component|form|button|modal/i.test(combined)
491
- analysis.hasAPI = /api|endpoint|route|controller/i.test(combined)
492
- analysis.hasDatabase = analysis.hasDatabase || /table|column|relation|index/i.test(combined)
493
-
494
- // Detect audience
495
- if (/b2c|consumer|user|customer/i.test(combined)) {
496
- analysis.audience = 'consumer'
497
- analysis.isExternalFacing = true
498
- } else if (/b2b|enterprise|business/i.test(combined)) {
499
- analysis.audience = 'business'
500
- analysis.isExternalFacing = true
501
- }
502
-
503
- // Calculate complexity (1-10)
504
- let complexity = 1
505
- if (analysis.features.length > 0) complexity += analysis.features.length
506
- if (analysis.domains.length > 0) complexity += analysis.domains.length
507
- if (analysis.hasCompliance) complexity += 2
508
- if (analysis.hasPayment) complexity += 2
509
- if (analysis.hasAuth) complexity += 1
510
- if (analysis.isExternalFacing) complexity += 1
511
- if (/integration|external api|third-party/i.test(combined)) complexity += 2
512
-
513
- analysis.complexity = Math.min(complexity, 10)
514
-
515
- // Adjust risk level
516
- if (analysis.complexity >= 7 || analysis.hasCompliance || analysis.hasPayment) {
517
- analysis.riskLevel = 'HIGH'
518
- } else if (analysis.complexity >= 4 || analysis.hasAuth) {
519
- analysis.riskLevel = 'MEDIUM'
520
- }
521
-
522
- return analysis
523
- }
524
-
525
- // Determine research layers dynamically based on change characteristics
526
- function determineResearchLayers(analysis) {
527
- const layers = []
528
- let order = 1
529
-
530
- // Check for trivial changes (0 layers)
531
- if (analysis.complexity <= 1 &&
532
- !analysis.hasUI && !analysis.hasAPI && !analysis.hasDatabase &&
533
- analysis.riskLevel === 'LOW') {
534
- return [] // No research needed
535
- }
536
-
537
- // L1: Best Practice (ALWAYS for non-trivial changes)
538
- layers.push({
539
- order: order++,
540
- name: 'Best Practice / Industry Standard',
541
- focus: `How do others implement ${analysis.primaryType}?`,
542
- questions: [
543
- `What is the industry standard for ${analysis.primaryType}?`,
544
- 'What are common patterns and anti-patterns?',
545
- 'What are the key success factors?',
546
- 'What are common failure modes?'
547
- ],
548
- searchTopics: [`${analysis.primaryType} best practices`, `${analysis.primaryType} patterns`]
549
- })
550
-
551
- // L2+: Dynamic layers based on context
552
-
553
- // Security layer (for auth, payment, sensitive data)
554
- if (analysis.hasAuth || analysis.hasPayment || analysis.hasSensitiveData) {
555
- layers.push({
556
- order: order++,
557
- name: 'Security Requirements',
558
- focus: 'What security measures are required?',
559
- questions: [
560
- 'What authentication/authorization is needed?',
561
- 'What data protection is required?',
562
- 'What are common security vulnerabilities?',
563
- 'What compliance requirements apply?'
564
- ],
565
- searchTopics: ['security best practices', `${analysis.primaryType} security`]
566
- })
567
- }
568
-
569
- // Compliance layer (for regulated industries)
570
- if (analysis.hasCompliance || analysis.industryContext) {
571
- layers.push({
572
- order: order++,
573
- name: `${analysis.industryContext || 'Industry'} Compliance`,
574
- focus: `What ${analysis.industryContext || 'industry'} regulations apply?`,
575
- questions: [
576
- 'What regulatory requirements must be met?',
577
- 'What audit trails are needed?',
578
- 'What data handling rules apply?',
579
- 'What documentation is required?'
580
- ],
581
- searchTopics: [`${analysis.industryContext} compliance`, `${analysis.industryContext} regulations`]
582
- })
583
- }
584
-
585
- // UX layer (for external-facing UI)
586
- if (analysis.isExternalFacing && analysis.hasUI) {
587
- layers.push({
588
- order: order++,
589
- name: 'User Experience Patterns',
590
- focus: 'What UX patterns work for this audience?',
591
- questions: [
592
- 'What user journey is expected?',
593
- 'What conversion patterns work?',
594
- 'What accessibility requirements apply?',
595
- 'What are user expectations?'
596
- ],
597
- searchTopics: [`${analysis.primaryType} UX`, `${analysis.audience} UX patterns`]
598
- })
599
- }
600
-
601
- // Psychology layer (for marketing/sales)
602
- if (analysis.primaryType === 'marketing' || /conversion|sales|cta/i.test(analysis.primaryType)) {
603
- layers.push({
604
- order: order++,
605
- name: 'Conversion Psychology',
606
- focus: 'What psychological triggers work?',
607
- questions: [
608
- 'What is the buyer awareness level?',
609
- 'What pain points to address?',
610
- 'What objections to overcome?',
611
- 'What social proof is needed?'
612
- ],
613
- searchTopics: ['conversion psychology', 'landing page psychology']
614
- })
615
- }
616
-
617
- // Content Strategy layer (for content-heavy pages)
618
- if (analysis.primaryType === 'marketing' || /content|blog|documentation/i.test(analysis.primaryType)) {
619
- layers.push({
620
- order: order++,
621
- name: 'Content Strategy',
622
- focus: 'What content structure works?',
623
- questions: [
624
- 'What content hierarchy is effective?',
625
- 'What tone and voice to use?',
626
- 'What call-to-actions work?',
627
- 'What content gaps exist?'
628
- ],
629
- searchTopics: ['content strategy', 'copywriting best practices']
630
- })
631
- }
632
-
633
- // Data Architecture layer (for database/data-intensive)
634
- if (analysis.hasDatabase || /data|analytics|reporting/i.test(analysis.primaryType)) {
635
- layers.push({
636
- order: order++,
637
- name: 'Data Architecture',
638
- focus: 'What data patterns are appropriate?',
639
- questions: [
640
- 'What normalization level is appropriate?',
641
- 'What indexing strategy is needed?',
642
- 'What scaling considerations apply?',
643
- 'What data integrity rules?'
644
- ],
645
- searchTopics: ['database design patterns', 'data architecture']
646
- })
647
- }
648
-
649
- // API Design layer (for API-focused changes)
650
- if (analysis.hasAPI || analysis.primaryType === 'api') {
651
- layers.push({
652
- order: order++,
653
- name: 'API Design',
654
- focus: 'What API patterns are appropriate?',
655
- questions: [
656
- 'What API style is appropriate (REST/GraphQL)?',
657
- 'What versioning strategy?',
658
- 'What error handling patterns?',
659
- 'What rate limiting/throttling?'
660
- ],
661
- searchTopics: ['API design best practices', 'REST API patterns']
662
- })
663
- }
664
-
665
- // Multi-tenancy layer (for SaaS)
666
- if (analysis.features.includes('multi-tenancy')) {
667
- layers.push({
668
- order: order++,
669
- name: 'Multi-tenancy Patterns',
670
- focus: 'What isolation and scaling patterns?',
671
- questions: [
672
- 'What data isolation model?',
673
- 'What authentication per tenant?',
674
- 'What resource limits?',
675
- 'What billing model integration?'
676
- ],
677
- searchTopics: ['multi-tenant architecture', 'SaaS patterns']
678
- })
679
- }
680
-
681
- // Real-time layer (for collaboration/live features)
682
- if (analysis.features.includes('realtime')) {
683
- layers.push({
684
- order: order++,
685
- name: 'Real-time Architecture',
686
- focus: 'What real-time patterns are needed?',
687
- questions: [
688
- 'WebSocket vs SSE vs polling?',
689
- 'What conflict resolution?',
690
- 'What offline support?',
691
- 'What scaling for connections?'
692
- ],
693
- searchTopics: ['real-time architecture', 'WebSocket patterns']
694
- })
695
- }
696
-
697
- // Performance layer (for high-traffic or data-intensive)
698
- if (analysis.isExternalFacing || analysis.complexity >= 6 ||
699
- /performance|speed|optimization|cache/i.test(analysis.primaryType)) {
700
- layers.push({
701
- order: order++,
702
- name: 'Performance Optimization',
703
- focus: 'What performance patterns are needed?',
704
- questions: [
705
- 'What caching strategy?',
706
- 'What lazy loading patterns?',
707
- 'What CDN/edge considerations?',
708
- 'What database optimization?'
709
- ],
710
- searchTopics: ['performance optimization', 'caching strategies']
711
- })
712
- }
713
-
714
- // Integration layer (for external APIs/services)
715
- if (/integration|external api|third-party|webhook/i.test(analysis.primaryType) ||
716
- analysis.features.some(f => /payment|email|sms|notification/i.test(f))) {
717
- layers.push({
718
- order: order++,
719
- name: 'Integration Patterns',
720
- focus: 'What integration patterns are robust?',
721
- questions: [
722
- 'What retry/circuit breaker patterns?',
723
- 'What error handling for external failures?',
724
- 'What monitoring/alerting?',
725
- 'What idempotency requirements?'
726
- ],
727
- searchTopics: ['integration patterns', 'API integration best practices']
728
- })
729
- }
730
-
731
- // Testing Strategy layer (for complex/high-risk)
732
- if (analysis.riskLevel === 'HIGH' || analysis.complexity >= 7) {
733
- layers.push({
734
- order: order++,
735
- name: 'Testing Strategy',
736
- focus: 'What testing coverage is needed?',
737
- questions: [
738
- 'What unit vs integration vs e2e balance?',
739
- 'What edge cases to cover?',
740
- 'What load/stress testing?',
741
- 'What security testing?'
742
- ],
743
- searchTopics: ['testing strategy', `${analysis.primaryType} testing`]
744
- })
745
- }
746
-
747
- return layers
748
- }
749
-
750
- // Execute research for a single layer using Claude's knowledge
751
- // WHY: Domain knowledge (UX, DB design, security patterns) comes from Claude's training
752
- // Stack knowledge (Prisma, React) comes from Context7 in Step 2.7
753
- function executeLayerResearch(layer, changeAnalysis) {
754
- const result = {
755
- layer: layer.name,
756
- findings: [],
757
- recommendations: [],
758
- warnings: [],
759
- requiredItems: [], // Critical checklist items that MUST be addressed
760
- source: 'claude-knowledge'
761
- }
762
-
763
- // Claude generates best practices based on:
764
- // - Layer context (what domain?)
765
- // - Change analysis (what's being built?)
766
- // - Questions to answer (what to research?)
767
- //
768
- // Claude's training includes:
769
- // - UX: Nielsen Norman, Baymard Institute, Laws of UX
770
- // - Database: Codd's normalization, indexing patterns
771
- // - Security: OWASP, auth patterns, encryption
772
- // - API: REST dissertation, versioning patterns
773
- // - Architecture: distributed systems, caching, scaling
774
-
775
- result.findings = generateDomainKnowledge(layer, changeAnalysis)
776
- result.recommendations = generateRecommendations(layer, changeAnalysis)
777
- result.warnings = checkForWarnings(layer, changeAnalysis)
778
-
779
- // Inject critical required items based on layer and context
780
- // WHY: These are non-negotiable security/compliance requirements
781
- result.requiredItems = injectCriticalRequiredItems(layer, changeAnalysis)
782
-
783
- return result
784
- }
785
-
786
- // ============================================================
787
- // CRITICAL FLOW REQUIREMENTS (v2.8.0)
788
- // ============================================================
789
- // These are non-negotiable items that MUST be in the checklist
790
- // WHY: Security/compliance failures have legal/financial consequences
791
-
792
- /**
793
- * Inject critical required items based on layer type and change context
794
- * Returns checklist items that agents MUST verify are implemented
795
- */
796
- function injectCriticalRequiredItems(layer, changeAnalysis) {
797
- const items = []
798
-
799
- // Security Requirements Layer
800
- if (layer.name === 'Security Requirements') {
801
- // Auth-related critical items
802
- if (changeAnalysis.hasAuth) {
803
- items.push(...CRITICAL_FLOWS.auth.security)
804
- }
805
- // Payment-related critical items
806
- if (changeAnalysis.hasPayment) {
807
- items.push(...CRITICAL_FLOWS.payment.security)
808
- }
809
- // Sensitive data handling
810
- if (changeAnalysis.hasSensitiveData) {
811
- items.push(...CRITICAL_FLOWS.sensitiveData.security)
812
- }
813
- }
814
-
815
- // Compliance Layer
816
- if (layer.name.includes('Compliance')) {
817
- if (changeAnalysis.industryContext === 'healthcare') {
818
- items.push(...CRITICAL_FLOWS.healthcare.compliance)
819
- }
820
- if (changeAnalysis.industryContext === 'fintech') {
821
- items.push(...CRITICAL_FLOWS.fintech.compliance)
822
- }
823
- }
824
-
825
- // Data Architecture Layer
826
- if (layer.name === 'Data Architecture') {
827
- if (changeAnalysis.hasSensitiveData) {
828
- items.push(...CRITICAL_FLOWS.sensitiveData.dataArchitecture)
829
- }
830
- }
831
-
832
- return items
833
- }
834
-
835
- /**
836
- * Critical Flow Definitions
837
- * Format: { category: { layer: [...items] } }
838
- * Each item has: id, check, why, severity
839
- */
840
- const CRITICAL_FLOWS = {
841
- // ============================================================
842
- // AUTH CRITICAL FLOWS
843
- // ============================================================
844
- auth: {
845
- security: [
846
- {
847
- id: 'auth-password-hash',
848
- check: '☐ Password hashing with bcrypt/argon2 (cost factor ≥ 10)',
849
- why: 'Plain text or weak hashing = immediate breach if DB leaked',
850
- severity: 'critical'
851
- },
852
- {
853
- id: 'auth-rate-limit',
854
- check: '☐ Rate limiting on login (max 5 attempts per 15 min)',
855
- why: 'Prevents brute force attacks',
856
- severity: 'critical'
857
- },
858
- {
859
- id: 'auth-session-timeout',
860
- check: '☐ Session timeout configured (≤ 24h, ≤ 15min for sensitive)',
861
- why: 'Abandoned sessions are attack vectors',
862
- severity: 'high'
863
- },
864
- {
865
- id: 'auth-csrf',
866
- check: '☐ CSRF protection on all state-changing endpoints',
867
- why: 'OWASP Top 10 vulnerability',
868
- severity: 'critical'
869
- },
870
- {
871
- id: 'auth-secure-cookies',
872
- check: '☐ Cookies: httpOnly, secure, sameSite=strict',
873
- why: 'Prevents XSS token theft and CSRF',
874
- severity: 'critical'
875
- },
876
- {
877
- id: 'auth-password-policy',
878
- check: '☐ Password policy enforced (min 8 chars, complexity optional)',
879
- why: 'Weak passwords are #1 breach cause',
880
- severity: 'high'
881
- },
882
- {
883
- id: 'auth-account-lockout',
884
- check: '☐ Account lockout after repeated failures (with unlock mechanism)',
885
- why: 'Prevents brute force, but needs recovery path',
886
- severity: 'medium'
887
- }
888
- ],
889
- flow: [
890
- {
891
- id: 'auth-flow-login',
892
- check: '☐ Login flow: input → validate → session → redirect',
893
- why: 'Standard secure login pattern',
894
- severity: 'high'
895
- },
896
- {
897
- id: 'auth-flow-logout',
898
- check: '☐ Logout: invalidate session server-side (not just cookie)',
899
- why: 'Client-side only logout leaves session valid',
900
- severity: 'high'
901
- },
902
- {
903
- id: 'auth-flow-forgot',
904
- check: '☐ Forgot password: email → time-limited token → reset',
905
- why: 'Token must expire (≤ 1 hour)',
906
- severity: 'high'
907
- }
908
- ]
909
- },
910
-
911
- // ============================================================
912
- // PAYMENT CRITICAL FLOWS
913
- // ============================================================
914
- payment: {
915
- security: [
916
- {
917
- id: 'payment-no-card-storage',
918
- check: '☐ NO raw card numbers stored (use Stripe/payment provider tokens)',
919
- why: 'PCI-DSS requirement, storing cards = massive liability',
920
- severity: 'critical'
921
- },
922
- {
923
- id: 'payment-https',
924
- check: '☐ HTTPS enforced on all payment pages',
925
- why: 'Payment data in transit must be encrypted',
926
- severity: 'critical'
927
- },
928
- {
929
- id: 'payment-webhook-verify',
930
- check: '☐ Webhook signature verification (never trust unverified webhooks)',
931
- why: 'Attackers can fake payment success webhooks',
932
- severity: 'critical'
933
- },
934
- {
935
- id: 'payment-idempotency',
936
- check: '☐ Idempotency keys for payment creation',
937
- why: 'Prevents double charges on retry',
938
- severity: 'high'
939
- },
940
- {
941
- id: 'payment-amount-verify',
942
- check: '☐ Server-side price verification (never trust client price)',
943
- why: 'Attackers modify client-side prices',
944
- severity: 'critical'
945
- }
946
- ],
947
- flow: [
948
- {
949
- id: 'payment-flow-checkout',
950
- check: '☐ Checkout flow: cart → address → payment → confirm → receipt',
951
- why: 'Standard e-commerce pattern users expect',
952
- severity: 'medium'
953
- },
954
- {
955
- id: 'payment-flow-error',
956
- check: '☐ Payment error handling with clear user message',
957
- why: 'Failed payments need recovery path',
958
- severity: 'high'
959
- },
960
- {
961
- id: 'payment-flow-refund',
962
- check: '☐ Refund flow documented (even if manual)',
963
- why: 'Legal requirement in most jurisdictions',
964
- severity: 'high'
965
- }
966
- ]
967
- },
968
-
969
- // ============================================================
970
- // SENSITIVE DATA CRITICAL FLOWS
971
- // ============================================================
972
- sensitiveData: {
973
- security: [
974
- {
975
- id: 'data-encryption-rest',
976
- check: '☐ Encryption at rest for PII/PHI (AES-256 or DB-level)',
977
- why: 'Breached DB without encryption = full exposure',
978
- severity: 'critical'
979
- },
980
- {
981
- id: 'data-encryption-transit',
982
- check: '☐ Encryption in transit (TLS 1.2+)',
983
- why: 'Data interception prevention',
984
- severity: 'critical'
985
- },
986
- {
987
- id: 'data-access-logging',
988
- check: '☐ Audit logging for sensitive data access',
989
- why: 'Required for breach investigation and compliance',
990
- severity: 'high'
991
- },
992
- {
993
- id: 'data-minimization',
994
- check: '☐ Data minimization (only collect what is needed)',
995
- why: 'GDPR principle, reduces breach impact',
996
- severity: 'medium'
997
- }
998
- ],
999
- dataArchitecture: [
1000
- {
1001
- id: 'data-arch-backup',
1002
- check: '☐ Backup strategy with encryption',
1003
- why: 'Backups are often unencrypted breach vector',
1004
- severity: 'high'
1005
- },
1006
- {
1007
- id: 'data-arch-retention',
1008
- check: '☐ Data retention policy defined',
1009
- why: 'Legal requirement (GDPR right to deletion)',
1010
- severity: 'medium'
1011
- }
1012
- ]
1013
- },
1014
-
1015
- // ============================================================
1016
- // HEALTHCARE COMPLIANCE (HIPAA)
1017
- // ============================================================
1018
- healthcare: {
1019
- compliance: [
1020
- {
1021
- id: 'hipaa-phi-encrypt',
1022
- check: '☐ All PHI encrypted at rest and in transit',
1023
- why: 'HIPAA Security Rule requirement',
1024
- severity: 'critical'
1025
- },
1026
- {
1027
- id: 'hipaa-access-control',
1028
- check: '☐ Role-based access control for PHI',
1029
- why: 'Minimum necessary standard',
1030
- severity: 'critical'
1031
- },
1032
- {
1033
- id: 'hipaa-audit-trail',
1034
- check: '☐ Audit trail for all PHI access (who, what, when)',
1035
- why: 'HIPAA requires 6-year audit log retention',
1036
- severity: 'critical'
1037
- },
1038
- {
1039
- id: 'hipaa-baa',
1040
- check: '☐ BAA signed with all vendors handling PHI',
1041
- why: 'Business Associate Agreement legally required',
1042
- severity: 'critical'
1043
- },
1044
- {
1045
- id: 'hipaa-breach-plan',
1046
- check: '☐ Breach notification plan documented',
1047
- why: '60-day notification requirement',
1048
- severity: 'high'
1049
- }
1050
- ]
1051
- },
1052
-
1053
- // ============================================================
1054
- // FINTECH COMPLIANCE (PCI-DSS)
1055
- // ============================================================
1056
- fintech: {
1057
- compliance: [
1058
- {
1059
- id: 'pci-no-pan',
1060
- check: '☐ No PAN (card numbers) stored unless PCI certified',
1061
- why: 'PCI-DSS Level 1 requirement',
1062
- severity: 'critical'
1063
- },
1064
- {
1065
- id: 'pci-tokenization',
1066
- check: '☐ Tokenization for card data (Stripe, Braintree)',
1067
- why: 'Removes PCI scope from your systems',
1068
- severity: 'critical'
1069
- },
1070
- {
1071
- id: 'pci-network-segment',
1072
- check: '☐ Network segmentation for payment systems',
1073
- why: 'Limits breach blast radius',
1074
- severity: 'high'
1075
- },
1076
- {
1077
- id: 'fintech-kyc',
1078
- check: '☐ KYC verification flow for financial accounts',
1079
- why: 'AML/KYC regulations',
1080
- severity: 'high'
1081
- },
1082
- {
1083
- id: 'fintech-transaction-limits',
1084
- check: '☐ Transaction limits and velocity checks',
1085
- why: 'Fraud prevention, regulatory requirement',
1086
- severity: 'high'
1087
- },
1088
- {
1089
- id: 'fintech-audit',
1090
- check: '☐ Transaction audit trail (immutable)',
1091
- why: 'Regulatory reporting requirement',
1092
- severity: 'critical'
1093
- }
1094
- ]
1095
- }
1096
- }
1097
-
1098
- // Generate domain knowledge using Claude's reasoning
1099
- // This is where Claude applies its training to the specific change
1100
- function generateDomainKnowledge(layer, changeAnalysis) {
1101
- const findings = []
1102
-
1103
- // Based on layer type, Claude will reason about best practices
1104
- // The actual content comes from Claude's response when /csetup runs
1105
-
1106
- findings.push({
1107
- question: layer.questions[0],
1108
- // Claude fills this based on its knowledge when executing
1109
- analysis: `[Claude analyzes: ${layer.focus}]`,
1110
- bestPractices: [], // Claude lists industry standards
1111
- antiPatterns: [], // Claude lists what to avoid
1112
- tradeoffs: [] // Claude explains trade-offs
1113
- })
359
+ ---
1114
360
 
1115
- return findings
1116
- }
361
+ #### Step 2.6.2: Detect Libraries
1117
362
 
1118
- // Check for conflicts between design system and industry practices
1119
- function checkDesignConflicts(tokens, researchResults, changeAnalysis) {
1120
- const conflicts = []
1121
-
1122
- // Only check for marketing/external-facing changes
1123
- if (!changeAnalysis.isExternalFacing) return conflicts
1124
-
1125
- // Check color appropriateness for industry
1126
- if (tokens.colors && changeAnalysis.industryContext) {
1127
- const primaryColor = tokens.colors.primary
1128
-
1129
- if (changeAnalysis.industryContext === 'healthcare') {
1130
- // Healthcare typically uses blue/green (trust, calm)
1131
- if (/red|orange|yellow/i.test(primaryColor)) {
1132
- conflicts.push({
1133
- aspect: 'Primary Color',
1134
- current: primaryColor,
1135
- industry: 'healthcare typically uses blue/green for trust and calm',
1136
- recommendation: 'Consider if bright colors are appropriate for healthcare context'
1137
- })
1138
- }
1139
- }
363
+ **Read these files and identify library/framework names:**
364
+ - `package.json` (dependencies, devDependencies)
365
+ - `requirements.txt` or `pyproject.toml` (Python)
366
+ - `openspec/changes/{changeId}/proposal.md`
367
+ - `openspec/changes/{changeId}/design.md`
1140
368
 
1141
- if (changeAnalysis.industryContext === 'fintech') {
1142
- // Fintech typically uses blue/green (trust, money)
1143
- if (/pink|purple|orange/i.test(primaryColor)) {
1144
- conflicts.push({
1145
- aspect: 'Primary Color',
1146
- current: primaryColor,
1147
- industry: 'fintech typically uses blue/green for trust and stability',
1148
- recommendation: 'Consider if playful colors fit financial services context'
1149
- })
1150
- }
1151
- }
1152
- }
369
+ **Look for:** React, Next.js, Vue, Angular, FastAPI, Express, Django, Prisma, Drizzle, SQLAlchemy, Vitest, Jest, Playwright, Stripe, better-auth, etc.
1153
370
 
1154
- // Check animation appropriateness
1155
- if (tokens.animations && changeAnalysis.hasCompliance) {
1156
- if (tokens.animations.enableScrollAnimations) {
1157
- conflicts.push({
1158
- aspect: 'Scroll Animations',
1159
- current: 'enabled',
1160
- industry: 'compliance-heavy sites often minimize animations for accessibility',
1161
- recommendation: 'Ensure animations have reduced-motion alternatives'
1162
- })
1163
- }
1164
- }
371
+ **Output:**
372
+ ```
373
+ 🔍 Libraries Detected:
374
+ - Next.js (from package.json)
375
+ - Prisma (from design.md)
376
+ - better-auth (from tasks.md)
377
+ ```
1165
378
 
1166
- return conflicts
1167
- }
379
+ ---
1168
380
 
1169
- // Generate research checklist markdown
1170
- function generateResearchChecklist(changeAnalysis, layers, results) {
1171
- let content = `# Research Checklist: ${changeAnalysis.primaryType}\n\n`
1172
- content += `> Generated by Adaptive Depth Research (v2.4.0)\n`
1173
- content += `> Complexity: ${changeAnalysis.complexity}/10 | Risk: ${changeAnalysis.riskLevel}\n\n`
1174
-
1175
- if (layers.length === 0) {
1176
- content += `## ✅ No Research Required\n\n`
1177
- content += `This is a trivial change (complexity ${changeAnalysis.complexity}/10).\n`
1178
- content += `Proceed directly with implementation.\n`
1179
- return content
1180
- }
381
+ #### Step 2.6.3: Fetch Best Practices via Context7
1181
382
 
1182
- content += `## Summary\n\n`
1183
- content += `| Layer | Focus | Status |\n`
1184
- content += `|-------|-------|--------|\n`
1185
- layers.forEach((layer, idx) => {
1186
- content += `| L${idx + 1}: ${layer.name} | ${layer.focus} | ⏳ Pending |\n`
1187
- })
383
+ **For EACH detected library, call these MCP tools:**
1188
384
 
1189
- content += `\n---\n\n`
385
+ ```
386
+ 1. mcp__context7__resolve-library-id
387
+ Input: { libraryName: "Next.js" }
388
+ Output: Get the context7CompatibleLibraryID (e.g., "/vercel/next.js")
389
+
390
+ 2. mcp__context7__get-library-docs
391
+ Input: {
392
+ context7CompatibleLibraryID: "/vercel/next.js",
393
+ topic: "best practices, patterns, common mistakes, [other-lib-names]",
394
+ mode: "code"
395
+ }
396
+ Output: Documentation with best practices
397
+ ```
1190
398
 
1191
- // Detail each layer
1192
- results.forEach((result, idx) => {
1193
- const layer = layers[idx]
1194
- content += `## L${idx + 1}: ${layer.name}\n\n`
1195
- content += `**Focus:** ${layer.focus}\n\n`
399
+ **Smart Topic Query:** Include OTHER detected library names in the topic for cross-library integration docs.
400
+ Example: When fetching Prisma docs, include "Next.js, React" in topic.
1196
401
 
1197
- content += `### Key Questions\n\n`
1198
- layer.questions.forEach(q => {
1199
- content += `- [ ] ${q}\n`
1200
- })
402
+ **Skip if:**
403
+ - Library not found in Context7 (note in warnings section instead)
404
+ - Library already has cached best practices from previous run
1201
405
 
1202
- if (result.findings.length > 0) {
1203
- content += `\n### Findings\n\n`
1204
- result.findings.forEach(f => {
1205
- content += `#### ${f.topic}\n\n`
1206
- if (Array.isArray(f.content)) {
1207
- f.content.forEach(point => content += `- ${point}\n`)
1208
- } else {
1209
- content += `${f.content}\n`
1210
- }
1211
- content += `\n*Source: ${f.source}*\n\n`
1212
- })
1213
- }
406
+ ---
1214
407
 
1215
- if (result.recommendations.length > 0) {
1216
- content += `### Recommendations\n\n`
1217
- result.recommendations.forEach(r => {
1218
- content += `- ${r}\n`
1219
- })
1220
- }
408
+ #### Step 2.6.4: Determine Research Layers
1221
409
 
1222
- if (result.warnings.length > 0) {
1223
- content += `\n### ⚠️ Warnings\n\n`
1224
- result.warnings.forEach(w => {
1225
- content += `- ${w}\n`
1226
- })
1227
- }
410
+ **Based on change analysis, select relevant research layers:**
1228
411
 
1229
- content += `\n---\n\n`
1230
- })
412
+ | Trigger | Layer | Focus |
413
+ |---------|-------|-------|
414
+ | Always (complexity > 1) | Best Practices | How do others do this? |
415
+ | hasAuth OR hasPayment | Security | Authentication, data protection |
416
+ | healthcare OR fintech | Compliance | HIPAA, PCI-DSS, regulations |
417
+ | isExternalFacing + hasUI | UX Patterns | User journey, accessibility |
418
+ | marketing type | Conversion Psychology | Triggers, objections, social proof |
419
+ | hasDatabase | Data Architecture | Normalization, indexing, scaling |
420
+ | hasAPI | API Design | REST/GraphQL, versioning, errors |
421
+ | payment feature | Payment Flows | PCI compliance, webhooks, idempotency |
1231
422
 
1232
- // Add Content Guidelines section for marketing pages
1233
- if (changeAnalysis.primaryType === 'marketing' || changeAnalysis.isExternalFacing) {
1234
- content += `## 📝 Content Guidelines\n\n`
1235
- content += `> Claude generates these guidelines based on the change context.\n`
1236
- content += `> Use these as a starting point for content creation.\n\n`
1237
-
1238
- content += `### Hero Section\n\n`
1239
- content += `**Headline Strategy:**\n`
1240
- content += `- Lead with primary pain point or aspiration\n`
1241
- content += `- 8-12 words, emotional trigger\n`
1242
- content += `- [Claude: Generate specific headline angle based on proposal]\n\n`
1243
-
1244
- content += `**Subheadline:**\n`
1245
- content += `- Concrete benefit + emotional payoff\n`
1246
- content += `- 15-25 words\n`
1247
- content += `- [Claude: Generate based on value proposition]\n\n`
1248
-
1249
- content += `**CTA:**\n`
1250
- content += `- Action verb + outcome\n`
1251
- content += `- [Claude: Generate based on user journey stage]\n\n`
1252
-
1253
- content += `### Value Proposition\n\n`
1254
- content += `For each feature, translate to:\n`
1255
- content += `| Feature | Benefit | Emotional Payoff |\n`
1256
- content += `|---------|---------|------------------|\n`
1257
- content += `| [Technical] | [What user gets] | [How it makes them feel] |\n\n`
1258
-
1259
- content += `### Social Proof\n\n`
1260
- content += `- Use specific results (numbers, timeframes)\n`
1261
- content += `- Match testimonials to target audience\n`
1262
- content += `- Include trust signals (logos, certifications)\n\n`
1263
-
1264
- content += `---\n\n`
1265
- }
423
+ **For each selected layer, generate:**
424
+ - 3-5 key questions to consider
425
+ - 2-3 recommendations from domain knowledge
426
+ - Warnings if applicable
1266
427
 
1267
- content += `## Agent Instructions\n\n`
1268
- content += `When implementing this change, agents should:\n\n`
1269
- content += `1. Review each layer's findings before starting\n`
1270
- content += `2. Check off questions as they are addressed\n`
1271
- content += `3. Follow recommendations where applicable\n`
1272
- content += `4. Address warnings or document exceptions\n`
428
+ ---
1273
429
 
1274
- if (changeAnalysis.primaryType === 'marketing' || changeAnalysis.isExternalFacing) {
1275
- content += `5. Use Content Guidelines section for copy direction\n`
1276
- }
430
+ #### Step 2.6.5: Detect Integration Warnings
1277
431
 
1278
- return content
1279
- }
432
+ **Cross-reference library combinations for known issues:**
1280
433
 
1281
- // Helper: Generate recommendations based on layer and context
1282
- // Claude fills in actual recommendations when executing /csetup
1283
- function generateRecommendations(layer, changeAnalysis) {
1284
- // These are prompts for Claude to expand with actual knowledge
1285
- // When /csetup runs, Claude will provide specific recommendations
434
+ | Combination | Warning |
435
+ |-------------|---------|
436
+ | better-auth + custom JWT | better-auth handles JWT internally - don't duplicate |
437
+ | Prisma + serverless | Cold starts can timeout - use connection pooling |
438
+ | Next.js 14+ + pages router | App router is default - check which is intended |
439
+ | React 19 + old state libs | Check compatibility with new React features |
1286
440
 
1287
- return [
1288
- `[Claude: Based on ${layer.name} best practices for ${changeAnalysis.primaryType}]`,
1289
- `[Claude: Specific to this change's context and requirements]`
1290
- ]
1291
- }
441
+ **Check Context7 docs for integration warnings:**
442
+ - Look for "migration", "breaking changes", "compatibility" in docs
443
+ - Note version-specific warnings
1292
444
 
1293
- // Helper: Check for potential warnings based on layer and context
1294
- function checkForWarnings(layer, changeAnalysis) {
1295
- const warnings = []
445
+ ---
1296
446
 
1297
- // Risk-based warnings
1298
- if (changeAnalysis.riskLevel === 'HIGH') {
1299
- warnings.push(`HIGH risk change - review ${layer.name} carefully before deployment`)
1300
- }
447
+ #### Step 2.6.6: Generate Critical Checklist Items
1301
448
 
1302
- // Compliance warnings
1303
- if (layer.name.includes('Compliance') && changeAnalysis.hasCompliance) {
1304
- warnings.push(`Regulatory compliance required - ensure all ${changeAnalysis.industryContext} requirements are met`)
1305
- }
449
+ **Based on change characteristics, inject required items:**
1306
450
 
1307
- // Payment warnings
1308
- if (changeAnalysis.hasPayment) {
1309
- warnings.push('Payment integration - ensure PCI compliance requirements are met')
1310
- }
451
+ **If hasAuth:**
452
+ ```
453
+ Password hashing with bcrypt/argon2 (cost 10)
454
+ ☐ Rate limiting on login (max 5 per 15 min)
455
+ ☐ Session timeout configured
456
+ ☐ CSRF protection on state-changing endpoints
457
+ ☐ Cookies: httpOnly, secure, sameSite=strict
458
+ ```
1311
459
 
1312
- // Security warnings
1313
- if (layer.name.includes('Security') && changeAnalysis.hasSensitiveData) {
1314
- warnings.push('Sensitive data handling - ensure proper encryption and access controls')
1315
- }
460
+ **If hasPayment:**
461
+ ```
462
+ NO raw card storage (use Stripe tokens)
463
+ ☐ HTTPS on all payment pages
464
+ ☐ Webhook signature verification
465
+ ☐ Idempotency keys for payments
466
+ ☐ Server-side price verification
467
+ ```
1316
468
 
1317
- return warnings
1318
- }
469
+ **If healthcare/fintech:**
470
+ ```
471
+ ☐ Encryption at rest for PII/PHI
472
+ ☐ Audit logging for sensitive data access
473
+ ☐ Data minimization applied
474
+ ☐ Compliance documentation prepared
1319
475
  ```
1320
476
 
1321
477
  ---
1322
478
 
1323
- ### Step 2.7: Auto-Setup Best Practices (v2.3.0 - Dynamic Detection)
1324
-
1325
- > **Zero-Maintenance Design:** Automatically detects any library/framework from spec text and resolves via Context7.
1326
- > **WHY:** Hardcoded mappings require constant maintenance and miss new libraries. Dynamic resolution works with any language (Python, Rust, Go, etc.) without code changes.
1327
-
1328
- ```typescript
1329
- // ============================================================
1330
- // STEP 2.7: Dynamic Tech Stack Detection & Best Practices
1331
- // ============================================================
1332
-
1333
- output(`\n🔍 Detecting Tech Stack (Dynamic Resolution)...`)
1334
-
1335
- // 1. Gather text from ALL relevant sources
1336
- const textSources = {
1337
- proposal: Read(`openspec/changes/${changeId}/proposal.md`) || '',
1338
- tasks: Read(`openspec/changes/${changeId}/tasks.md`) || '',
1339
- design: fileExists(`openspec/changes/${changeId}/design.md`)
1340
- ? Read(`openspec/changes/${changeId}/design.md`) : '',
1341
- packageJson: fileExists('package.json') ? Read('package.json') : '',
1342
- requirementsTxt: fileExists('requirements.txt') ? Read('requirements.txt') : '',
1343
- pyprojectToml: fileExists('pyproject.toml') ? Read('pyproject.toml') : '',
1344
- cargoToml: fileExists('Cargo.toml') ? Read('Cargo.toml') : '',
1345
- goMod: fileExists('go.mod') ? Read('go.mod') : '',
1346
- composerJson: fileExists('composer.json') ? Read('composer.json') : '',
1347
- gemfile: fileExists('Gemfile') ? Read('Gemfile') : ''
1348
- }
1349
-
1350
- const allText = Object.values(textSources).join('\n')
479
+ #### Step 2.6.7: Write pre-work-context.md
1351
480
 
1352
- // 2. Extract library names using semantic analysis (TRUE zero-maintenance)
1353
- // WHY: Pattern-based extraction still requires maintenance.
1354
- // Instead, use Claude's understanding to identify libraries from context.
1355
- output(` 🧠 Analyzing text semantically...`)
1356
-
1357
- const potentialLibraries = await extractLibrariesSemantically(allText)
1358
-
1359
- output(` 📝 Found ${potentialLibraries.length} potential libraries to verify`)
1360
-
1361
- // 3. Resolve each potential library with Context7 (validate it's a real library)
1362
- const resolvedLibraries = []
1363
- const resolutionCache = new Map()
1364
-
1365
- for (const candidate of potentialLibraries) {
1366
- if (resolutionCache.has(candidate.toLowerCase())) continue
1367
-
1368
- try {
1369
- const result = await mcp__context7__resolve_library_id({
1370
- libraryName: candidate
1371
- })
1372
-
1373
- const bestMatch = parseContext7Response(result, candidate)
1374
-
1375
- if (bestMatch && bestMatch.score >= 60) {
1376
- resolvedLibraries.push({
1377
- name: candidate,
1378
- context7Id: bestMatch.id,
1379
- title: bestMatch.title,
1380
- snippets: bestMatch.snippets,
1381
- score: bestMatch.score
1382
- })
1383
- resolutionCache.set(candidate.toLowerCase(), bestMatch)
1384
- output(` ✅ ${candidate} → ${bestMatch.id} (${bestMatch.snippets} snippets)`)
1385
- }
1386
- } catch (error) {
1387
- resolutionCache.set(candidate.toLowerCase(), null)
1388
- }
1389
- }
481
+ **Create `openspec/changes/{changeId}/pre-work-context.md`:**
1390
482
 
1391
- output(`\n📊 Verified Libraries: ${resolvedLibraries.length}`)
1392
- resolvedLibraries.forEach(lib => {
1393
- output(` - ${lib.title} (${lib.context7Id})`)
1394
- })
1395
-
1396
- // 4. If no libraries detected, ask user for guidance
1397
- if (resolvedLibraries.length === 0) {
1398
- output(`\n⚠️ No libraries auto-detected from spec files`)
1399
-
1400
- const answer = await askUserQuestion({
1401
- questions: [{
1402
- question: 'Enter the main libraries/frameworks for this project (comma-separated):',
1403
- header: 'Libraries',
1404
- options: [
1405
- { label: 'Skip', description: 'Continue without library-specific best practices' },
1406
- { label: 'React, Next.js', description: 'Common frontend stack' },
1407
- { label: 'FastAPI, SQLAlchemy, Pydantic', description: 'Python API stack' },
1408
- { label: 'Express, Prisma', description: 'Node.js backend stack' }
1409
- ],
1410
- multiSelect: false
1411
- }]
1412
- })
1413
-
1414
- if (!answer.includes('Skip')) {
1415
- // Parse user input and resolve each
1416
- const userLibraries = answer.split(',').map(s => s.trim()).filter(Boolean)
1417
- for (const lib of userLibraries) {
1418
- const result = await mcp__context7__resolve_library_id({ libraryName: lib })
1419
- const bestMatch = parseContext7Response(result, lib)
1420
- if (bestMatch) {
1421
- resolvedLibraries.push({
1422
- name: lib,
1423
- context7Id: bestMatch.id,
1424
- title: bestMatch.title,
1425
- snippets: bestMatch.snippets,
1426
- score: bestMatch.score
1427
- })
1428
- }
1429
- }
1430
- }
1431
- }
483
+ ```markdown
484
+ # Pre-Work Context: {changeId}
1432
485
 
1433
- // 5. Generate best-practices files for resolved libraries
1434
- // v2.5.0: Smart Topic Query - include other library names for cross-library integration docs
1435
- const bpDir = '.claude/contexts/domain/project/best-practices/'
1436
- const existingBp = fileExists(bpDir) ? listFiles(bpDir) : []
486
+ > **Generated:** {date}
487
+ > **Purpose:** All context agents need before implementation
488
+ > **Read by:** All agents in STEP 0
1437
489
 
1438
- // Filter to libraries that don't have best-practices yet
1439
- const newLibraries = resolvedLibraries.filter(lib => {
1440
- const safeName = lib.name.toLowerCase().replace(/[^a-z0-9]/g, '-')
1441
- return !existingBp.some(f => f.toLowerCase().includes(safeName))
1442
- })
490
+ ---
1443
491
 
1444
- if (newLibraries.length > 0) {
1445
- output(`\n📚 Generating Best Practices from Context7...`)
1446
- output(` 💡 Using Smart Topic Query for cross-library integration docs`)
492
+ ## 1. Change Analysis
1447
493
 
1448
- // Create directory if needed
1449
- if (!fileExists(bpDir)) {
1450
- mkdir(bpDir)
1451
- }
494
+ | Aspect | Value |
495
+ |--------|-------|
496
+ | Type | {primaryType} |
497
+ | Complexity | {complexity}/10 |
498
+ | Risk Level | {riskLevel} |
499
+ | Domains | {domains or "General"} |
500
+ | Features | {features or "None detected"} |
1452
501
 
1453
- // Collect all integration risks for summary
1454
- const integrationRisks = []
1455
-
1456
- for (const lib of newLibraries) {
1457
- output(` 📖 Fetching ${lib.title} best practices...`)
1458
-
1459
- try {
1460
- // v2.5.0: Smart Topic Query - include other library names in topic
1461
- // WHY: This captures integration docs (e.g., "drizzle adapter" in auth.js docs)
1462
- const otherLibNames = resolvedLibraries
1463
- .filter(l => l.name !== lib.name)
1464
- .map(l => l.name.toLowerCase())
1465
- .slice(0, 5) // Limit to 5 to avoid topic overflow
1466
- .join(', ')
1467
-
1468
- const smartTopic = [
1469
- 'best practices',
1470
- 'patterns',
1471
- 'anti-patterns',
1472
- 'common mistakes',
1473
- 'adapter', // Key for ORM + Auth integrations
1474
- 'integration', // Key for multi-library setups
1475
- 'schema', // Key for database + auth column naming
1476
- 'configuration', // Key for setup requirements
1477
- otherLibNames // Include other detected libraries
1478
- ].filter(Boolean).join(', ')
1479
-
1480
- const docs = await mcp__context7__get_library_docs({
1481
- context7CompatibleLibraryID: lib.context7Id,
1482
- topic: smartTopic,
1483
- mode: 'code'
1484
- })
1485
-
1486
- // v2.5.0: Detect integration risks from docs content
1487
- const risks = detectIntegrationRisks(docs, lib.name, resolvedLibraries)
1488
- if (risks.length > 0) {
1489
- integrationRisks.push(...risks)
1490
- output(` ⚠️ Found ${risks.length} integration pattern(s) to review`)
1491
- }
502
+ ---
1492
503
 
1493
- const bpContent = generateBestPracticesFile(lib.title, docs, lib.context7Id)
1494
- const safeName = lib.name.toLowerCase().replace(/[^a-z0-9]/g, '-')
1495
- Write(`${bpDir}${safeName}.md`, bpContent)
504
+ ## 2. Library Best Practices
1496
505
 
1497
- output(` ✅ ${safeName}.md generated`)
1498
- } catch (error) {
1499
- output(` ⚠️ ${lib.title} - failed to fetch docs, skipping`)
1500
- }
1501
- }
506
+ ### {Library 1}
1502
507
 
1503
- // v2.5.0: Generate integration risk summary if any found
1504
- if (integrationRisks.length > 0) {
1505
- generateIntegrationRiskSummary(integrationRisks, bpDir, resolvedLibraries)
1506
- output(`\n⚠️ Integration Risk Summary generated (${integrationRisks.length} items)`)
1507
- output(` 📄 ${bpDir}INTEGRATION_RISKS.md`)
1508
- }
508
+ **Source:** Context7 ({context7Id})
1509
509
 
1510
- // Generate/update index.md
1511
- generateBestPracticesIndex(resolvedLibraries, changeId)
1512
- output(` ✅ index.md updated`)
510
+ **DO:**
511
+ - {best practice 1}
512
+ - {best practice 2}
1513
513
 
1514
- output(`\n✅ Best Practices Setup Complete!`)
1515
- output(` New files: ${newLibraries.length}`)
1516
- output(` Location: ${bpDir}`)
1517
- } else if (resolvedLibraries.length > 0) {
1518
- output(`\n✅ Best Practices: Already configured for detected libraries`)
1519
- } else {
1520
- output(`\n✅ Best Practices: Skipped (no libraries to configure)`)
1521
- }
514
+ **DON'T:**
515
+ - {anti-pattern 1}
516
+ - {anti-pattern 2}
1522
517
 
1523
- // 6. Store resolved stack for context.md generation
1524
- const stackForContext = {
1525
- detected: resolvedLibraries.map(l => l.name),
1526
- resolved: resolvedLibraries,
1527
- bestPracticesPath: bpDir,
1528
- files: existingBp.concat(newLibraries.map(l => `${l.name.toLowerCase().replace(/[^a-z0-9]/g, '-')}.md`))
1529
- }
518
+ **Code Example:**
519
+ ```{lang}
520
+ {example code from Context7}
1530
521
  ```
1531
522
 
523
+ ### {Library 2}
524
+ {repeat structure}
525
+
1532
526
  ---
1533
527
 
1534
- ### Helper: extractLibrariesSemantically() - PRIMARY
528
+ ## 3. Research Findings
1535
529
 
1536
- > **TRUE Zero-Maintenance:** Uses Claude's semantic understanding to extract library names from any text.
1537
- > **WHY:** Pattern-based regex always has edge cases. Claude understands context and meaning.
530
+ ### L1: {Layer Name}
1538
531
 
1539
- ```typescript
1540
- async function extractLibrariesSemantically(text: string): Promise<string[]> {
1541
- // Truncate text if too long (keep first 8000 chars for efficiency)
1542
- const truncatedText = text.length > 8000 ? text.slice(0, 8000) + '\n...[truncated]' : text
1543
-
1544
- // Use Claude to semantically extract library/framework names
1545
- // This is the MAIN Claude running /csetup, so we just analyze inline
1546
- const prompt = `
1547
- Analyze this text and extract ALL programming libraries, frameworks, and tools mentioned.
1548
-
1549
- TEXT:
1550
- ${truncatedText}
1551
-
1552
- INSTRUCTIONS:
1553
- 1. Look for any technology names (libraries, frameworks, ORMs, databases, tools)
1554
- 2. Include both explicit mentions ("using Mastra") and implicit ones ("PostgreSQL database")
1555
- 3. Return ONLY the library/framework names, one per line
1556
- 4. Do NOT include generic terms like "API", "REST", "database" (unless it's a specific product name)
1557
- 5. Do NOT include programming languages (Python, JavaScript, etc.) unless they're library names
1558
- 6. Include package names from any language (npm, pip, cargo, go, etc.)
1559
-
1560
- OUTPUT FORMAT (one name per line, nothing else):
1561
- `
532
+ **Key Questions:**
533
+ - {question 1}
534
+ - {question 2}
1562
535
 
1563
- // Since this runs within Main Claude context, we analyze inline
1564
- // The output parsing happens in the calling code
1565
- // For now, return a simple extraction that Main Claude will process
536
+ **Recommendations:**
537
+ - {recommendation based on domain knowledge}
1566
538
 
1567
- // Fallback: Use pattern-based extraction as baseline
1568
- // Main Claude will enhance this with semantic understanding
1569
- const patternBased = extractPotentialLibraryNames(text)
539
+ **Warnings:**
540
+ - {warning if applicable}
1570
541
 
1571
- // Main Claude: When you execute this, also semantically analyze the text
1572
- // and add any libraries you identify from context that patterns missed.
1573
- // Example: "The system uses Mastra for orchestration" → add "Mastra"
542
+ {repeat for each layer}
1574
543
 
1575
- return patternBased
1576
- }
1577
- ```
544
+ ---
1578
545
 
1579
- **Execution Note for Main Claude:**
546
+ ## 4. Integration Warnings
1580
547
 
1581
- When running `/csetup`, after calling `extractLibrariesSemantically()`:
1582
- 1. Review the spec text yourself (proposal.md, design.md, tasks.md)
1583
- 2. Identify any library/framework names the patterns might have missed
1584
- 3. Add them to the `potentialLibraries` array before Context7 validation
548
+ ⚠️ **{Library A} + {Library B}:**
549
+ {warning description}
1585
550
 
1586
- This hybrid approach ensures:
1587
- - Pattern extraction catches obvious cases quickly
1588
- - Claude's semantic understanding catches edge cases
1589
- - Context7 validates everything (filters out false positives)
551
+ ⚠️ **{Another combination}:**
552
+ {warning description}
1590
553
 
1591
554
  ---
1592
555
 
1593
- ### Helper: extractPotentialLibraryNames() - FALLBACK
1594
-
1595
- > **Pattern-based fallback:** Provides baseline extraction. Main Claude enhances with semantic analysis.
1596
-
1597
- ```typescript
1598
- function extractPotentialLibraryNames(text: string): string[] {
1599
- const candidates = new Set<string>()
1600
-
1601
- // === Pattern 1: Package file dependencies ===
1602
- // package.json: "react": "^18.0.0" → react
1603
- const npmDeps = text.match(/"([a-z@][a-z0-9._/-]*)"\s*:\s*"[\^~]?\d/gi) || []
1604
- npmDeps.forEach(m => {
1605
- const match = m.match(/"([^"]+)"/)
1606
- if (match) candidates.add(match[1].replace(/^@[^/]+\//, '')) // Strip scope
1607
- })
556
+ ## 5. Critical Checklist
1608
557
 
1609
- // requirements.txt: sqlalchemy==2.0.0 sqlalchemy
1610
- // Allow optional leading whitespace for indented requirements
1611
- const pyDeps = text.match(/^\s*([a-zA-Z][a-zA-Z0-9_-]*)\s*[=<>~!]/gm) || []
1612
- pyDeps.forEach(m => {
1613
- const match = m.match(/([a-zA-Z][a-zA-Z0-9_-]*)\s*[=<>~!]/)
1614
- if (match) candidates.add(match[1])
1615
- })
558
+ > **MUST complete before marking phase done**
1616
559
 
1617
- // Cargo.toml: tokio = "1.0" → tokio
1618
- // Allow optional leading whitespace for indented dependencies
1619
- const rustDeps = text.match(/^\s*([a-z][a-z0-9_-]*)\s*=/gm) || []
1620
- rustDeps.forEach(m => {
1621
- const match = m.match(/([a-z][a-z0-9_-]*)\s*=/)
1622
- if (match) candidates.add(match[1])
1623
- })
560
+ ### Security
561
+ {security items if applicable}
1624
562
 
1625
- // go.mod: require github.com/gin-gonic/gin → gin
1626
- const goDeps = text.match(/(?:require\s+)?github\.com\/[^/\s]+\/([a-z][a-z0-9_-]*)/gi) || []
1627
- goDeps.forEach(m => {
1628
- const match = m.match(/\/([a-z][a-z0-9_-]*)$/i)
1629
- if (match) candidates.add(match[1])
1630
- })
563
+ ### Compliance
564
+ {compliance items if applicable}
1631
565
 
1632
- // === Pattern 2: Import statements ===
1633
- // Python: from sqlalchemy import, import pydantic
1634
- const pyImports = text.match(/(?:from|import)\s+([a-zA-Z][a-zA-Z0-9_]*)/g) || []
1635
- pyImports.forEach(m => {
1636
- const match = m.match(/(?:from|import)\s+([a-zA-Z][a-zA-Z0-9_]*)/)
1637
- if (match) candidates.add(match[1])
1638
- })
566
+ ### Data Protection
567
+ {data items if applicable}
1639
568
 
1640
- // JS/TS: import X from 'Y', require('Y')
1641
- const jsImports = text.match(/(?:from|require\s*\(\s*)['"]([a-zA-Z@][a-zA-Z0-9._/-]*)['"]/g) || []
1642
- jsImports.forEach(m => {
1643
- const match = m.match(/['"]([^'"]+)['"]/)
1644
- if (match) {
1645
- const pkg = match[1].replace(/^@[^/]+\//, '').split('/')[0]
1646
- candidates.add(pkg)
1647
- }
1648
- })
569
+ ---
1649
570
 
1650
- // Rust: use tokio::, extern crate serde
1651
- const rustImports = text.match(/(?:use|extern\s+crate)\s+([a-z][a-z0-9_]*)/g) || []
1652
- rustImports.forEach(m => {
1653
- const match = m.match(/(?:use|extern\s+crate)\s+([a-z][a-z0-9_]*)/)
1654
- if (match) candidates.add(match[1])
1655
- })
571
+ ## 6. Quick Reference
1656
572
 
1657
- // === Pattern 3: Tech mentions in prose ===
1658
- // "using FastAPI", "with Prisma", "powered by Mastra"
1659
- const techMentions = text.match(/(?:using|with|via|built with|powered by)\s+([A-Z][a-zA-Z0-9.]*)/gi) || []
1660
- techMentions.forEach(m => {
1661
- const match = m.match(/\s([A-Z][a-zA-Z0-9.]*)$/i)
1662
- if (match) candidates.add(match[1])
1663
- })
573
+ **Package Manager:** {from tech-stack.md or detected}
574
+ **Test Command:** {detected test script}
575
+ **Build Command:** {detected build script}
1664
576
 
1665
- // CamelCase words (FastAPI, NextAuth)
1666
- const camelCase = text.match(/\b([A-Z][a-z]+(?:[A-Z][a-z]+)+)\b/g) || []
1667
- camelCase.forEach(w => candidates.add(w))
1668
-
1669
- // Mixed case words (SQLAlchemy, PostgreSQL, GraphQL - uppercase prefix + CamelCase)
1670
- const mixedCase = text.match(/\b([A-Z]{2,}[a-z]+[A-Za-z]*)\b/g) || []
1671
- mixedCase.forEach(w => candidates.add(w))
1672
-
1673
- // === Pattern 3.5: PascalCase single words after tech keywords ===
1674
- // "Framework: Mastra", "ORM: Prisma", "Database: PostgreSQL"
1675
- // WHY: Many library names are single PascalCase words (Mastra, Prisma, Django, Flask)
1676
- const techKeywordPatterns = [
1677
- /(?:framework|library|orm|database|db|backend|frontend|ui|css|styling)[:\s]+([A-Z][a-z]+\w*)/gi,
1678
- /(?:built\s+with|powered\s+by|using|via|with)\s+([A-Z][a-z]+\w*)/gi,
1679
- /\*\*(?:framework|library|orm|database|backend|frontend)\*\*[:\s]+([A-Z][a-z]+\w*)/gi
1680
- ]
1681
- techKeywordPatterns.forEach(pattern => {
1682
- const matches = text.matchAll(pattern)
1683
- for (const match of matches) {
1684
- if (match[1]) candidates.add(match[1])
1685
- }
1686
- })
577
+ ---
1687
578
 
1688
- // === Pattern 3.6: Standalone PascalCase in markdown lists ===
1689
- // "- Mastra for AI agents", "- PostgreSQL database", "* React frontend"
1690
- const mdListItems = text.match(/^[\s]*[-*]\s+([A-Z][a-z]+\w*)(?:\s|$)/gm) || []
1691
- mdListItems.forEach(m => {
1692
- const match = m.match(/[-*]\s+([A-Z][a-z]+\w*)/)
1693
- if (match) candidates.add(match[1])
1694
- })
579
+ **Agents: Read this file in STEP 0 before implementation.**
580
+ ```
1695
581
 
1696
- // === Pattern 3.7: Words after "for" in tech context ===
1697
- // "Mastra for AI orchestration", "Drizzle for database"
1698
- const forPattern = text.match(/([A-Z][a-z]+\w*)\s+for\s+(?:ai|database|backend|frontend|api|web|mobile|server|client)/gi) || []
1699
- forPattern.forEach(m => {
1700
- const match = m.match(/^([A-Z][a-z]+\w*)/)
1701
- if (match) candidates.add(match[1])
1702
- })
582
+ ---
1703
583
 
1704
- // Known framework patterns: Next.js, Vue.js, Express.js
1705
- const dotJs = text.match(/\b([A-Z][a-z]+)\.js\b/gi) || []
1706
- dotJs.forEach(m => {
1707
- const match = m.match(/([A-Z][a-z]+)/i)
1708
- if (match) candidates.add(match[1])
1709
- })
584
+ #### Step 2.6.8: Output Summary
1710
585
 
1711
- // === Pattern 4: Explicit tech stack sections ===
1712
- // "Tech Stack:", "Technologies:", "Built with:"
1713
- const techSection = text.match(/(?:tech\s*stack|technologies|built\s*with|dependencies)[:\s]+([^\n]+)/gi) || []
1714
- techSection.forEach(section => {
1715
- const items = section.split(/[,\s]+/)
1716
- items.forEach(item => {
1717
- const cleaned = item.replace(/[^a-zA-Z0-9.-]/g, '')
1718
- if (cleaned.length > 2) candidates.add(cleaned)
1719
- })
1720
- })
586
+ ```
587
+ Pre-Work Context Generated!
1721
588
 
1722
- // === Pattern 4.5: Markdown bold/code tech mentions ===
1723
- // "**Mastra**", "`prisma`", "**Framework:** Mastra"
1724
- const boldWords = text.match(/\*\*([A-Z][a-z]+\w*)\*\*/g) || []
1725
- boldWords.forEach(m => {
1726
- const match = m.match(/\*\*([A-Z][a-z]+\w*)\*\*/)
1727
- if (match) candidates.add(match[1])
1728
- })
589
+ 📄 File: openspec/changes/{changeId}/pre-work-context.md
1729
590
 
1730
- const codeWords = text.match(/`([a-zA-Z][a-zA-Z0-9_-]+)`/g) || []
1731
- codeWords.forEach(m => {
1732
- const match = m.match(/`([a-zA-Z][a-zA-Z0-9_-]+)`/)
1733
- if (match && match[1].length > 2) candidates.add(match[1])
1734
- })
591
+ Contents:
592
+ - Change Analysis: {type}, {complexity}/10, {risk}
593
+ - Libraries: {count} ({names})
594
+ - Research Layers: {count}
595
+ - Integration Warnings: {count}
596
+ - Critical Checklist Items: {count}
1735
597
 
1736
- // === Filter out noise ===
1737
- // Use lowercase for case-insensitive comparison
1738
- const stopWords = new Set([
1739
- // Common English words (all lowercase for comparison)
1740
- 'the', 'this', 'that', 'with', 'from', 'using', 'for', 'and', 'but', 'not',
1741
- 'all', 'any', 'can', 'could', 'should', 'would', 'will', 'may', 'might',
1742
- 'each', 'every', 'some', 'many', 'most', 'other', 'such', 'only', 'just',
1743
- 'also', 'well', 'back', 'even', 'still', 'already', 'always', 'never',
1744
- // Common programming terms that aren't libraries
1745
- 'api', 'rest', 'http', 'https', 'json', 'xml', 'html', 'css', 'sql',
1746
- 'get', 'post', 'put', 'delete', 'patch', 'url', 'uri', 'uuid', 'id',
1747
- 'true', 'false', 'none', 'null', 'undefined', 'error', 'exception',
1748
- 'class', 'function', 'method', 'object', 'array', 'string', 'number',
1749
- 'boolean', 'int', 'float', 'double', 'char', 'byte', 'long', 'short',
1750
- 'public', 'private', 'protected', 'static', 'final', 'const', 'let', 'var',
1751
- 'import', 'export', 'module', 'package', 'interface', 'type', 'enum',
1752
- 'test', 'tests', 'spec', 'specs', 'mock', 'stub', 'fake', 'spy',
1753
- 'config', 'configuration', 'settings', 'options', 'params', 'args',
1754
- 'user', 'users', 'admin', 'auth', 'login', 'logout', 'session', 'token',
1755
- 'data', 'database', 'table', 'column', 'row', 'index', 'key', 'value',
1756
- 'file', 'files', 'path', 'dir', 'directory', 'folder', 'name', 'size',
1757
- 'create', 'read', 'update', 'delete', 'list', 'get', 'set', 'add', 'remove',
1758
- 'start', 'stop', 'run', 'build', 'deploy', 'install', 'setup', 'init',
1759
- // Version/date patterns
1760
- 'version', 'release', 'beta', 'alpha', 'stable', 'latest', 'current'
1761
- ])
1762
-
1763
- return [...candidates]
1764
- .filter(w => w.length > 2 && w.length < 30)
1765
- .filter(w => !stopWords.has(w.toLowerCase())) // Case-insensitive comparison
1766
- .filter(w => !/^\d+$/.test(w)) // Not pure numbers
1767
- .filter(w => !/^v?\d+\.\d+/.test(w)) // Not version numbers
1768
- .slice(0, 50) // Limit to avoid too many API calls
1769
- }
598
+ 📌 Agents will read this in STEP 0
1770
599
  ```
1771
600
 
1772
601
  ---
1773
602
 
1774
- ### Helper: parseContext7Response()
603
+ #### Step 2.6.9: Skip Conditions
1775
604
 
1776
- > **WHY:** Context7 returns multiple matches. Select the best one based on relevance score and snippet count.
605
+ **Skip this step entirely if:**
606
+ - Change is trivial (complexity = 1, risk = LOW, no special features)
607
+ - Output: `✅ Pre-Work Context: Skipped (trivial change)`
1777
608
 
1778
- ```typescript
1779
- function parseContext7Response(response: string, searchTerm: string): {
1780
- id: string
1781
- title: string
1782
- snippets: number
1783
- score: number
1784
- } | null {
1785
- // Parse the Context7 response text to extract library info
1786
- // Response format includes lines like:
1787
- // - Title: SQLAlchemy
1788
- // - Context7-compatible library ID: /sqlalchemy/sqlalchemy
1789
- // - Code Snippets: 2830
1790
- // - Benchmark Score: 84.4
1791
-
1792
- const libraries = []
1793
- const blocks = response.split('----------').filter(b => b.trim())
1794
-
1795
- for (const block of blocks) {
1796
- const titleMatch = block.match(/Title:\s*(.+)/i)
1797
- const idMatch = block.match(/Context7-compatible library ID:\s*(\S+)/i)
1798
- const snippetsMatch = block.match(/Code Snippets:\s*(\d+)/i)
1799
- const scoreMatch = block.match(/Benchmark Score:\s*([\d.]+)/i)
1800
-
1801
- if (titleMatch && idMatch) {
1802
- libraries.push({
1803
- title: titleMatch[1].trim(),
1804
- id: idMatch[1].trim(),
1805
- snippets: snippetsMatch ? parseInt(snippetsMatch[1]) : 0,
1806
- score: scoreMatch ? parseFloat(scoreMatch[1]) : 50
1807
- })
1808
- }
1809
- }
609
+ **Skip library lookup if:**
610
+ - No new libraries detected
611
+ - All libraries already have Context7 cache
1810
612
 
1811
- if (libraries.length === 0) return null
1812
-
1813
- // Prefer exact title match, then highest score with good snippet count
1814
- const searchLower = searchTerm.toLowerCase()
1815
-
1816
- // First: exact match
1817
- const exactMatch = libraries.find(l =>
1818
- l.title.toLowerCase() === searchLower ||
1819
- l.id.toLowerCase().includes(searchLower)
1820
- )
1821
- if (exactMatch) return exactMatch
1822
-
1823
- // Second: partial match with good score
1824
- const partialMatches = libraries.filter(l =>
1825
- l.title.toLowerCase().includes(searchLower) ||
1826
- searchLower.includes(l.title.toLowerCase())
1827
- )
1828
- if (partialMatches.length > 0) {
1829
- return partialMatches.sort((a, b) => b.score - a.score)[0]
1830
- }
613
+ ---
1831
614
 
1832
- // Third: best overall score (only if snippets > 100 for quality)
1833
- const qualityLibs = libraries.filter(l => l.snippets > 100)
1834
- if (qualityLibs.length > 0) {
1835
- return qualityLibs.sort((a, b) => b.score - a.score)[0]
1836
- }
615
+ **⚠️ IMPORTANT:** This step requires YOU (Main Claude) to:
616
+ 1. Actually read the spec files
617
+ 2. Actually call Context7 MCP tools
618
+ 3. Actually write the pre-work-context.md file
1837
619
 
1838
- // Fallback: first result
1839
- return libraries[0]
1840
- }
1841
- ```
620
+ Do NOT treat this as pseudocode. EXECUTE these instructions.
1842
621
 
1843
622
  ---
1844
623
 
1845
- ### Step 2.8: Library Capability Validation (v2.2.0)
624
+ ### Step 2.7: Library Capability Validation (v2.2.0)
1846
625
 
1847
626
  > **NEW:** Verify chosen libraries support ALL spec requirements before proceeding
1848
627
  > **WHY:** Prevents spec drift - discovering during implementation that library doesn't support requirements
@@ -2079,351 +858,6 @@ const capabilityAnalysis = {
2079
858
  }
2080
859
  ```
2081
860
 
2082
- **Helper: generateBestPracticesFile()**
2083
-
2084
- > **Updated v2.3.0:** Now includes Context7 library ID for reference and refresh capability.
2085
-
2086
- ```typescript
2087
- function generateBestPracticesFile(
2088
- tech: string,
2089
- context7Docs: string,
2090
- context7Id: string
2091
- ): string {
2092
- return `# ${tech} Best Practices
2093
-
2094
- > **Source:** Context7 MCP
2095
- > **Library ID:** \`${context7Id}\`
2096
- > **Generated:** ${new Date().toISOString().split('T')[0]}
2097
- > **Refresh:** Query Context7 with the Library ID above to update this file
2098
-
2099
- ---
2100
-
2101
- ## Best Practices
2102
-
2103
- ${extractBestPractices(context7Docs)}
2104
-
2105
- ---
2106
-
2107
- ## Anti-Patterns to Avoid
2108
-
2109
- ${extractAntiPatterns(context7Docs)}
2110
-
2111
- ---
2112
-
2113
- ## Code Examples
2114
-
2115
- ${extractCodeExamples(context7Docs)}
2116
-
2117
- ---
2118
-
2119
- ## Quick Checklist
2120
-
2121
- Before committing ${tech} code:
2122
- ${extractChecklist(context7Docs)}
2123
-
2124
- ---
2125
-
2126
- **Agents read this file in STEP 0 before implementation.**
2127
- `
2128
- }
2129
-
2130
- // Helper: Extract best practices from Context7 docs
2131
- function extractBestPractices(docs: string): string {
2132
- // Look for sections about best practices, recommendations, patterns
2133
- const patterns = [
2134
- /best\s*practices?[:\s]+([^#]+?)(?=##|$)/gi,
2135
- /recommend(?:ed|ations)?[:\s]+([^#]+?)(?=##|$)/gi,
2136
- /(?:do|should)[:\s]+([^#]+?)(?=##|$)/gi
2137
- ]
2138
-
2139
- let extracted = ''
2140
- for (const pattern of patterns) {
2141
- const matches = docs.match(pattern)
2142
- if (matches) {
2143
- extracted += matches.join('\n\n')
2144
- }
2145
- }
2146
-
2147
- return extracted || docs.slice(0, 2000) // Fallback to first 2000 chars
2148
- }
2149
-
2150
- // Helper: Extract anti-patterns from Context7 docs
2151
- function extractAntiPatterns(docs: string): string {
2152
- const patterns = [
2153
- /anti-?patterns?[:\s]+([^#]+?)(?=##|$)/gi,
2154
- /avoid[:\s]+([^#]+?)(?=##|$)/gi,
2155
- /(?:don'?t|should\s*not)[:\s]+([^#]+?)(?=##|$)/gi,
2156
- /common\s*mistakes?[:\s]+([^#]+?)(?=##|$)/gi
2157
- ]
2158
-
2159
- let extracted = ''
2160
- for (const pattern of patterns) {
2161
- const matches = docs.match(pattern)
2162
- if (matches) {
2163
- extracted += matches.join('\n\n')
2164
- }
2165
- }
2166
-
2167
- return extracted || 'Review Context7 documentation for anti-patterns specific to your use case.'
2168
- }
2169
-
2170
- // Helper: Extract code examples from Context7 docs
2171
- function extractCodeExamples(docs: string): string {
2172
- // Extract code blocks
2173
- const codeBlocks = docs.match(/\`\`\`[\s\S]*?\`\`\`/g) || []
2174
- return codeBlocks.slice(0, 5).join('\n\n') || 'See Context7 documentation for code examples.'
2175
- }
2176
-
2177
- // Helper: Generate checklist from docs
2178
- function extractChecklist(docs: string): string {
2179
- // Look for checklist items or generate from best practices
2180
- const checklistPatterns = [
2181
- /- \[[ x]\][^\n]+/gi,
2182
- /\d+\.\s+[^\n]+/gi
2183
- ]
2184
-
2185
- let items = []
2186
- for (const pattern of checklistPatterns) {
2187
- const matches = docs.match(pattern)
2188
- if (matches) {
2189
- items = items.concat(matches.slice(0, 10))
2190
- }
2191
- }
2192
-
2193
- if (items.length > 0) {
2194
- return items.map(item => `- [ ] ${item.replace(/^[\d.-\[\]x\s]+/i, '')}`).join('\n')
2195
- }
2196
-
2197
- // Fallback: generic checklist
2198
- return `- [ ] Follow official documentation patterns
2199
- - [ ] Handle errors appropriately
2200
- - [ ] Add proper typing/validation
2201
- - [ ] Write tests for new code
2202
- - [ ] Review for security concerns`
2203
- }
2204
- ```
2205
-
2206
- ---
2207
-
2208
- ### Helper: detectIntegrationRisks() - v2.5.0
2209
-
2210
- > **Smart Risk Detection:** Scans Context7 docs for integration patterns that require attention.
2211
- > **WHY:** Proactively catch integration requirements BEFORE implementation, not at runtime.
2212
-
2213
- ```typescript
2214
- function detectIntegrationRisks(
2215
- docs: string,
2216
- currentLib: string,
2217
- allLibs: Array<{ name: string; title: string }>
2218
- ): Array<{ library: string; risk: string; pattern: string; recommendation: string }> {
2219
- const risks = []
2220
- const docsLower = docs.toLowerCase()
2221
-
2222
- // Integration risk patterns to detect
2223
- const riskPatterns = [
2224
- // Adapter patterns (ORM + Auth)
2225
- {
2226
- keywords: ['adapter', 'drizzleadapter', 'prismaadapter'],
2227
- risk: 'Database adapter configuration required',
2228
- pattern: 'adapter',
2229
- recommendation: 'Verify adapter schema matches expected column names'
2230
- },
2231
- // Column naming patterns
2232
- {
2233
- keywords: ['column', 'columnname', 'snake_case', 'camelcase', 'mapping'],
2234
- risk: 'Column naming convention mismatch possible',
2235
- pattern: 'schema',
2236
- recommendation: 'Check column naming between ORM schema and library expectations'
2237
- },
2238
- // Schema patterns
2239
- {
2240
- keywords: ['userstable', 'accountstable', 'sessionstable', 'schema'],
2241
- risk: 'Custom table schema required',
2242
- pattern: 'schema',
2243
- recommendation: 'Ensure table schemas match library documentation exactly'
2244
- },
2245
- // Sync/Migration patterns
2246
- {
2247
- keywords: ['sync', 'migrate', 'migration', 'syncurl', 'embedded replica'],
2248
- risk: 'Data synchronization setup required',
2249
- pattern: 'sync',
2250
- recommendation: 'Configure sync intervals and handle offline scenarios'
2251
- },
2252
- // Webhook patterns
2253
- {
2254
- keywords: ['webhook', 'webhookendpoint', 'webhooksecret'],
2255
- risk: 'Webhook endpoint configuration required',
2256
- pattern: 'webhook',
2257
- recommendation: 'Set up webhook endpoints and verify signatures'
2258
- },
2259
- // API Key patterns
2260
- {
2261
- keywords: ['apikey', 'secretkey', 'authtoken', 'bearer'],
2262
- risk: 'API credentials setup required',
2263
- pattern: 'credentials',
2264
- recommendation: 'Store credentials securely in environment variables'
2265
- },
2266
- // Lifecycle patterns
2267
- {
2268
- keywords: ['beforeall', 'afterall', 'beforeeach', 'aftereach', 'setup', 'teardown'],
2269
- risk: 'Test lifecycle hooks required',
2270
- pattern: 'lifecycle',
2271
- recommendation: 'Implement proper setup/teardown in test configuration'
2272
- }
2273
- ]
2274
-
2275
- for (const rp of riskPatterns) {
2276
- const found = rp.keywords.some(kw => docsLower.includes(kw.toLowerCase()))
2277
- if (found) {
2278
- // Check if this risk involves other detected libraries
2279
- const involvedLibs = allLibs
2280
- .filter(l => l.name !== currentLib)
2281
- .filter(l => docsLower.includes(l.name.toLowerCase()))
2282
- .map(l => l.name)
2283
-
2284
- risks.push({
2285
- library: currentLib,
2286
- risk: rp.risk,
2287
- pattern: rp.pattern,
2288
- recommendation: rp.recommendation,
2289
- involvedLibraries: involvedLibs
2290
- })
2291
- }
2292
- }
2293
-
2294
- return risks
2295
- }
2296
- ```
2297
-
2298
- ---
2299
-
2300
- ### Helper: generateIntegrationRiskSummary() - v2.5.0
2301
-
2302
- > **Risk Summary Output:** Creates INTEGRATION_RISKS.md with all detected cross-library concerns.
2303
- > **WHY:** Agents can review this BEFORE implementation to avoid common integration mistakes.
2304
-
2305
- ```typescript
2306
- function generateIntegrationRiskSummary(
2307
- risks: Array<{
2308
- library: string
2309
- risk: string
2310
- pattern: string
2311
- recommendation: string
2312
- involvedLibraries?: string[]
2313
- }>,
2314
- bpDir: string,
2315
- allLibs: Array<{ name: string; title: string }>
2316
- ): void {
2317
- // Group risks by pattern type
2318
- const byPattern = {}
2319
- for (const r of risks) {
2320
- if (!byPattern[r.pattern]) byPattern[r.pattern] = []
2321
- byPattern[r.pattern].push(r)
2322
- }
2323
-
2324
- const content = `# Integration Risk Summary
2325
-
2326
- > **Generated:** ${new Date().toISOString().split('T')[0]}
2327
- > **Template Version:** 2.5.0 - Smart Topic Query
2328
- > **Detected Libraries:** ${allLibs.map(l => l.name).join(', ')}
2329
-
2330
- ---
2331
-
2332
- ## ⚠️ Review Before Implementation
2333
-
2334
- The following integration patterns were detected from library documentation.
2335
- **Agents should review these items in STEP 0 before writing code.**
2336
-
2337
- ---
2338
-
2339
- ${Object.entries(byPattern).map(([pattern, patternRisks]) => `
2340
- ### ${pattern.toUpperCase()} Patterns
2341
-
2342
- | Library | Risk | Recommendation |
2343
- |---------|------|----------------|
2344
- ${patternRisks.map(r => `| ${r.library} | ${r.risk} | ${r.recommendation} |`).join('\n')}
2345
- ${patternRisks.some(r => r.involvedLibraries?.length > 0) ? `
2346
- **Cross-library concerns:**
2347
- ${patternRisks.filter(r => r.involvedLibraries?.length > 0).map(r => `- ${r.library} ↔ ${r.involvedLibraries.join(', ')}: ${r.risk}`).join('\n')}
2348
- ` : ''}
2349
- `).join('\n')}
2350
-
2351
- ---
2352
-
2353
- ## Quick Checklist
2354
-
2355
- Before implementing integrations:
2356
-
2357
- ${[...new Set(risks.map(r => r.recommendation))].map(rec => `- [ ] ${rec}`).join('\n')}
2358
-
2359
- ---
2360
-
2361
- **This file is auto-generated by /csetup v2.5.0**
2362
- **Agents read this in STEP 0 alongside best-practices files**
2363
- `
2364
-
2365
- Write(`${bpDir}INTEGRATION_RISKS.md`, content)
2366
- }
2367
- ```
2368
-
2369
- ---
2370
-
2371
- ### Helper: generateBestPracticesIndex() - v2.5.0
2372
-
2373
- > **Index File:** Creates index.md registry of all best practices files.
2374
- > **v2.5.0:** Now includes INTEGRATION_RISKS.md if present.
2375
-
2376
- ```typescript
2377
- function generateBestPracticesIndex(
2378
- resolvedLibraries: Array<{ name: string; title: string; context7Id: string }>,
2379
- changeId: string
2380
- ): void {
2381
- const bpDir = '.claude/contexts/domain/project/best-practices/'
2382
- const hasIntegrationRisks = fileExists(`${bpDir}INTEGRATION_RISKS.md`)
2383
-
2384
- const content = `# Best Practices Index
2385
-
2386
- > **Generated:** ${new Date().toISOString().split('T')[0]}
2387
- > **Template Version:** 2.5.0 - Smart Topic Query
2388
- > **Change:** ${changeId}
2389
-
2390
- ---
2391
-
2392
- ## 📚 Library Best Practices
2393
-
2394
- | Library | File | Context7 ID |
2395
- |---------|------|-------------|
2396
- ${resolvedLibraries.map(lib => {
2397
- const safeName = lib.name.toLowerCase().replace(/[^a-z0-9]/g, '-')
2398
- return `| ${lib.title} | [${safeName}.md](./${safeName}.md) | \`${lib.context7Id}\` |`
2399
- }).join('\n')}
2400
-
2401
- ---
2402
-
2403
- ${hasIntegrationRisks ? `## ⚠️ Integration Risks
2404
-
2405
- Cross-library integration concerns detected. **Review before implementation.**
2406
-
2407
- → [INTEGRATION_RISKS.md](./INTEGRATION_RISKS.md)
2408
-
2409
- ---
2410
-
2411
- ` : ''}## Usage
2412
-
2413
- Agents read these files in **STEP 0** before implementation:
2414
-
2415
- 1. Read \`index.md\` (this file) for overview
2416
- 2. Read relevant \`{library}.md\` files for specific best practices
2417
- ${hasIntegrationRisks ? '3. Read `INTEGRATION_RISKS.md` for cross-library concerns' : ''}
2418
-
2419
- ---
2420
-
2421
- **Auto-generated by /csetup v2.5.0**
2422
- `
2423
-
2424
- Write(`${bpDir}index.md`, content)
2425
- }
2426
- ```
2427
861
 
2428
862
  ---
2429
863
 
@@ -2772,15 +1206,27 @@ function generatePhaseSection(phase, phaseTasks) {
2772
1206
  const dominantAgent = getMostCommonAgent(phaseTasks)
2773
1207
  const hasIncremental = phaseTasks.some(t => t.milestones)
2774
1208
  const maxRisk = getMaxRisk(phaseTasks)
2775
- const needsTDD = phaseTasks.some(t => t.risk === 'HIGH' || t.complexity >= 7)
1209
+
1210
+ // v3.1.0: Use TDD classification from task-analyzer.md (Step 2.6)
1211
+ // Each task now has task.tdd = { tdd_required, workflow, reason, confidence }
1212
+ const tddTasks = phaseTasks.filter(t => t.tdd?.tdd_required === true)
1213
+ const needsTDD = tddTasks.length > 0
1214
+ const tddReasons = [...new Set(tddTasks.map(t => t.tdd?.reason).filter(Boolean))]
2776
1215
 
2777
1216
  let section = `## Phase ${phase.number}: ${phase.name}
2778
1217
 
2779
1218
  **Agent:** ${dominantAgent}
2780
1219
  **Strategy:** ${hasIncremental ? '🔄 INCREMENTAL' : 'Standard'}
2781
1220
  **Risk:** ${maxRisk}
2782
- ${needsTDD ? '**TDD Required:** Yes' : ''}
2783
-
1221
+ ${needsTDD ? `**TDD Required:** YES
1222
+ **TDD Reason:** ${tddReasons.slice(0, 2).join('; ')}
1223
+ **TDD Workflow:** red-green-refactor
1224
+
1225
+ ⚠️ **TDD WORKFLOW REQUIRED:**
1226
+ 1. 🔴 RED: Write tests FIRST (they should fail)
1227
+ 2. ✅ GREEN: Write minimal implementation to pass tests
1228
+ 3. 🔧 REFACTOR: Improve code quality while keeping tests green
1229
+ ` : ''}
2784
1230
  `
2785
1231
 
2786
1232
  // Group tasks: incremental tasks get milestone sections, others get simple list
@@ -3167,20 +1613,10 @@ function detectChangeType(tasks: AnalyzedTask[]): string {
3167
1613
  }
3168
1614
  ```
3169
1615
 
3170
- ### detectAdditionalTech() - DEPRECATED
3171
-
3172
- > **Note:** This function is deprecated in v2.3.0. Use `extractPotentialLibraryNames()` + Context7 resolution instead.
3173
- > The dynamic approach automatically detects any library without hardcoded patterns.
1616
+ ### detectAdditionalTech() - REMOVED (v3.1.0)
3174
1617
 
3175
- ```typescript
3176
- // DEPRECATED: Kept for backwards compatibility only
3177
- // Use extractPotentialLibraryNames() for new implementations
3178
- function detectAdditionalTech(proposal: string, tasks: string): string[] {
3179
- // Now delegates to the dynamic detection system
3180
- const combined = proposal + ' ' + tasks
3181
- return extractPotentialLibraryNames(combined)
3182
- }
3183
- ```
1618
+ > **Note:** This function was removed in v3.1.0. Use Step 2.7's direct Context7 instructions instead.
1619
+ > Main Claude now directly calls Context7 MCP tools to detect and resolve libraries.
3184
1620
 
3185
1621
  ---
3186
1622