When implementing any fix or feature, Claude Code MUST:
-
Treat Every Issue as a CLASS Problem
- Never fix just the symptom; identify the underlying pattern
- Ask: "What category of problem is this? Where else might this occur?"
- The fix should resolve ALL instances of this problem type, not just the one encountered
-
Implement UNIVERSAL Solutions
- Solutions must work for edge cases, not just the happy path
- Handle null, undefined, empty arrays, missing properties gracefully
- Don't hardcode values; use configurable defaults, constants, or computed fallbacks
- Example BAD:
const value = data.score ?? 0.3(magic number) - Example GOOD:
const value = data.score ?? DEFAULT_SCORES.community.baseline
-
Design for FLEXIBILITY
- Use configuration objects instead of hardcoded values
- Implement proper type guards and validation at system boundaries
- Create reusable utility functions for common patterns
- Prefer composition over rigid inheritance
-
Ensure FUTURE-PROOFING
- Consider how the codebase might evolve
- Add appropriate abstractions that allow extension without modification
- Document assumptions and constraints in code comments
- Use TypeScript types/interfaces to enforce contracts
Before implementing ANY fix, Claude Code MUST:
- Identify Root Cause: What is the underlying issue, not just the symptom?
- Find All Occurrences: Where else in the codebase might this pattern exist?
- Design Universal Fix: How can this fix apply to the entire class of problems?
- Consider Edge Cases: null, undefined, empty, invalid inputs handled?
- Use Proper Defaults: Are defaults configurable and documented?
- Type Safety: Does the fix maintain or improve type safety?
- No Magic Numbers: Are all constants named and centralized?
- Validation at Boundaries: Is input validated where it enters the system?
// BAD - fixes one spot with magic defaults
function calculateScore(data: Data): number {
const value = data.score ?? 0.5; // Magic number
return value * 100;
}// GOOD - centralized defaults, reusable utility, type-safe
const SCORE_DEFAULTS = {
baseline: 0.5,
minimum: 0,
maximum: 1,
} as const;
function safeNumber(value: number | null | undefined, fallback: number): number {
if (value === null || value === undefined || Number.isNaN(value)) {
return fallback;
}
return Math.max(SCORE_DEFAULTS.minimum, Math.min(SCORE_DEFAULTS.maximum, value));
}
function calculateScore(data: Data): number {
const value = safeNumber(data.score, SCORE_DEFAULTS.baseline);
return value * 100;
}// BAD - only fixes this one endpoint
if (!profile.target_schools) {
profile.target_schools = ['HARVARD', 'MIT']; // Hardcoded
}// GOOD - validation utility used everywhere
import { validateProfile, withDefaults } from '@/lib/validation/profile';
const validatedProfile = withDefaults(validateProfile(profile));
// Defaults come from a central config, validation is reusableWhen Claude Code sees these patterns, STOP and refactor:
- Magic Numbers: Any literal number in business logic
- Repeated Null Checks: Same
?? defaultpattern in multiple places - Type Assertions:
as Typewithout validation - Hardcoded Arrays/Objects: Inline data that should be in config
- Copy-Paste Logic: Similar code in multiple locations
- Swallowed Errors: Empty catch blocks or ignored error states
- Implicit Assumptions: Code that assumes data shape without validation
- Mutating Array Methods on Store Data:
.sort(),.reverse(),.splice()on arrays from Zustand/Redux stores (usesafeSort(),[...arr].sort()etc.)
- Single Source of Truth: Constants, defaults, and configs in ONE place
- Fail Fast: Validate early, provide clear error messages
- Defensive Programming: Assume inputs can be invalid
- Separation of Concerns: Validation, transformation, business logic separated
- DRY (Don't Repeat Yourself): Extract common patterns into utilities
UNIVERSAL RULE: Never use dark-mode Tailwind CSS classes in Frame components.
The Ivylevel brand uses a light-mode color scheme. The dark-mode CSS variables in globals.css are for system UI, NOT for Frame content.
text-text-primary,text-text-secondary,text-text-muted→ These are white/light colors for dark backgroundsbg-background-primary,bg-background-secondary→ These are dark backgroundsbg-primary-blue,text-primary-blue→ Wrong brand color (should be orange)border-border-subtle,border-border-default→ Dark-mode borders
import { BRAND_COLORS } from '@/lib/constants/brand';
// Text colors (inline styles)
style={{ color: BRAND_COLORS.textHeading }} // Maroon #641432
style={{ color: BRAND_COLORS.textPrimary }} // Gray-700 #374151
style={{ color: BRAND_COLORS.textMuted }} // Gray-400 #9ca3af
// Background colors
style={{ backgroundColor: BRAND_COLORS.bgPrimary }} // White with slight transparency
style={{ backgroundColor: BRAND_COLORS.primaryBg }} // Light orange rgba(255, 74, 35, 0.1)
style={{ backgroundColor: BRAND_COLORS.bgSuccess }} // Light green
// Border colors
style={{ border: `1px solid ${BRAND_COLORS.borderLight}` }}
style={{ border: `2px solid ${BRAND_COLORS.primary}` }} // Selected state- Primary:
#FF4A23(Ivylevel orange) - main accent, buttons, selected states - Secondary:
#641432(Ivylevel maroon) - headings, important text - Success:
#16a34a(Green-600) - positive indicators - Warning:
#d97706(Amber-600) - caution indicators - Error:
#dc2626(Red-600) - negative indicators
All brand constants are in /lib/constants/brand.ts. Import and use these instead of Tailwind classes in Frame components.
- All scoring attributes should have centralized defaults in
/lib/constants/defaults.ts - Profile validation should happen at API boundaries using a validation layer
- Null handling should use utility functions, not inline
??with magic numbers - The scoring engine should be robust to incomplete profiles
User Input → Validation Layer → Normalized Data → Business Logic → Output
↓
Defaults Applied (from central config)
↓
Type-safe throughout
Claude Code MUST NOT proceed with implementation until:
- The fix addresses the ROOT CAUSE
- The solution is UNIVERSAL (applies to all similar cases)
- No MAGIC NUMBERS or hardcoded values exist
- Proper DEFAULTS and VALIDATION are in place
- The fix is FUTURE-PROOF and extensible
This is the #1 documentation rule. Violations cause chaos.
When releasing new versions, fixing bugs, or adding features, Claude Code MUST:
- UPDATE the existing canonical doc - DO NOT create a new file
- Add a timestamp to the "Last Updated" field in the doc header
- Update the version number if it's a version release
- Add changelog entry to
/docs/CHANGELOG.md
These files are the SINGLE SOURCE OF TRUTH. Update them in place:
| File | Purpose | Update When |
|---|---|---|
/STRUCTURE.md |
Project structure | Adding folders/files |
/docs/ARCHITECTURE.md |
System architecture | Adding components |
/docs/DATABASE.md |
Database schema | Adding tables/columns |
/docs/API.md |
API endpoints | Adding/changing APIs |
/docs/DEPLOYMENT.md |
Deployment guide | Changing deploy process |
/docs/CHANGELOG.md |
Version history | EVERY release |
/agents/docs/AGENTS.md |
Agent catalog | Adding/modifying agents |
/agents/docs/PROACTIVE.md |
Proactive system | Changing proactive features |
/app/docs/COMPONENTS.md |
Component guide | Adding components |
/app/docs/FRAMES.md |
Assessment frames | Changing frames |
# Document Title
**Version:** v1.1 → v1.2 ← INCREMENT VERSION
**Last Updated:** January 21, 2026 → January 22, 2026 ← UPDATE DATE
... rest of content (update relevant sections) ...Create a new file ONLY when:
- It's a completely NEW topic/scope not covered by existing docs
- It's a temporary PLANNING spec (prefix with
SPEC_)
Planning specs use dated names and get archived after implementation:
SPEC_<feature>_YYYYMMDD.md → Move to /_archive/docs/specs/ when done
docs/ARCHITECTURE.md
docs/ARCHITECTURE_v2.md ❌ NEVER DO THIS
docs/ARCHITECTURE_20260121.md ❌ NEVER DO THIS
docs/ARCHITECTURE_new.md ❌ NEVER DO THIS
docs/ARCHITECTURE.md ✅ Update this file
✅ Change "Last Updated" date
✅ Add entry to CHANGELOG.md
docs/API.md
docs/API_v2.md ❌
docs/API_ENDPOINTS.md ❌
docs/API_REFERENCE.md ❌
docs/API.md ✅ Single source of truth
Before ANY release, bug fix, or feature:
- Update
/docs/CHANGELOG.mdwith version/date/changes - Update relevant canonical docs (ARCHITECTURE, DATABASE, API, etc.)
- Update "Last Updated" timestamp in each modified doc
- Increment version number if it's a release
- DO NOT create new files for existing topics
- Archive old planning specs to
/_archive/docs/specs/
All version history goes in ONE file: /docs/CHANGELOG.md
# Changelog
## v1.2.0 - January 22, 2026
- Added: New proactive feature X
- Fixed: Bug in opportunity matcher
- Changed: API endpoint Y
## v1.1.0 - January 21, 2026
- Added: MVP cleanup
- ...Use SPEC_*.md files ONLY for:
- New feature planning before implementation
- Design decisions that need approval
- Complex changes requiring detailed spec
SPEC_<FEATURE>_YYYYMMDD.md
Examples:
SPEC_PAYMENTS_20260122.md
SPEC_REALTIME_CHAT_20260125.md
- Create in
/agents/specs/during planning - Implement the feature
- Update canonical docs with final implementation
- Archive spec to
/_archive/docs/specs/
/agents/specs/ # Active planning specs only
/_archive/docs/specs/ # Completed/archived specs
Every spec MUST include:
- Header - Title, date, author
- Status - Draft/Review/Approved/Implemented
- Summary - 2-3 sentence overview
- Proposed Changes - What will change
- Technical Details - Implementation approach
- Testing Plan - How to verify