First Session Bootstrap: When starting your first session on this project, explore the codebase and fill in all
[ADAPT]sections below. Read the code, understand the structure, document what you find. Future sessions depend on this orientation. The[ADAPT]markers are inside HTML comments — replace them with real content.
A portable Claude Code starter kit (harness) that you drop into any repo to bootstrap high-quality, auditable AI-assisted development. It provides session hooks, coding standards, skills, and documentation templates — not application code. Distilled from battle-tested patterns in the HIVE project.
- NOT an application. There is no source code to build, run, or deploy. Don't suggest adding application logic, endpoints, or features.
- NOT a library or package. There are no exports, no
package.json, no installable module. Don't add dependency management. - NOT project-specific. The "Fixed" files are universal templates. Don't hardcode project-specific values into fixed files — that belongs in
[ADAPT]sections only. - NOT meant to be forked and diverged. It's a drop-in kit. Changes should improve the universal templates, not specialize them.
├── CLAUDE.md # Project instructions (this file) — mixed fixed + adaptive
├── README.md # User-facing docs: what the kit is, quick start
├── LICENSE # MIT License
├── docs/
│ ├── PRINCIPLE_LATTICE.md # 5 axiomatic design principles with instantiation slots
│ └── TASK_CONTRACT_TEMPLATE.md # Copy per-task for acceptance criteria
└── .claude/
├── settings.json # Registers session hooks (SessionStart, Stop)
├── PR_GUIDELINES.md # Standardized PR description format
├── hooks/
│ ├── session-start.py # Auto-injects git state + next steps at session start
│ └── maintenance-check.py # Blocks session end if code changed but docs weren't updated
└── skills/
├── adversarial-review.md # /adversarial-review — three-pass bug verification
├── project-status.md # /project-status — quick project state overview
├── research-then-implement.md # /research-decide — two-phase research → implement
└── structured-reasoning.md # Decision framework: priority hierarchy, stuck protocol
This project follows 5 axiomatic principles. See docs/PRINCIPLE_LATTICE.md for the full lattice with details.
| # | Principle | Axiom |
|---|---|---|
| 1 | Modularity | Lego blocks, not monoliths |
| 2 | Simplicity Wins | Don't reinvent the wheel. Code exists to be used |
| 3 | Errors Are Answers | Every failure teaches. Errors must be actionable |
| 4 | Fix The Pattern | Cure the root cause. Don't treat symptoms |
| 5 | Secrets Stay Secret | Nothing left open to exploitation |
When making design decisions, check against these principles. If a choice violates one, reconsider.
- Python 3 is required for the session hooks (
session-start.py,maintenance-check.py) - Git is required — hooks rely on
gitcommands for orientation and maintenance checks - Files marked "Fixed" in README.md should not be modified unless improving the universal template
[ADAPT]sections (inside HTML comments) are the only parts meant to be project-specific — fill them in, don't delete the surrounding structure- Hook registration lives in
.claude/settings.json— if you add a new hook script, register it there - The
maintenance-check.pyhook uses aTRIVIAL_SESSION_THRESHOLDof 15 lines — sessions shorter than that skip the doc-update check CODE_EXTENSIONSinmaintenance-check.pydefines which file types trigger the doc-update reminder — extend it if your project uses unlisted extensions
No build step — this is a documentation/config kit, not compiled code.
No dev server — drop these files into a target repo and start a Claude Code session.
No test suite. Hooks can be tested manually:
echo '{}' | python3 .claude/hooks/session-start.py— should output JSON withadditionalContextmaintenance-check.pyrequires atranscript_pathin stdin JSON to run meaningfully
- SessionStart hook (
session-start.py): Reads stdin JSON, gathers git state (branch, recent commits, uncommitted changes) and next steps fromROADMAP.md/TODO.md, outputs{"additionalContext": "..."}to inject orientation into the session. - Stop hook (
maintenance-check.py): Reads stdin JSON withtranscript_path, checks if code files were modified (viagit diff), and blocks session end with a doc-update reminder if code changed but docs weren't updated. Sessions under 15 transcript lines are skipped. If Claude states "No maintenance needed" in the last 2000 chars of transcript, the check passes.
Files are categorized as Fixed (universal, don't modify) or Adaptive (project-specific, fill in [ADAPT] markers). This separation lets the kit be dropped into any repo without conflict.
Skills in .claude/skills/ are markdown files that define structured prompts invokable via /skill-name. They don't contain executable code — they instruct Claude on how to perform a specific workflow (adversarial review, research-then-implement, etc.).
These are universal anti-patterns that cause real damage. They apply every session.
-
Don't add features, refactoring, or "improvements" beyond what was asked. A bug fix doesn't need surrounding code cleaned up. A simple feature doesn't need extra configurability.
-
Don't add error handling for scenarios that can't happen. Trust internal code and framework guarantees. Only validate at system boundaries (user input, external APIs).
-
Don't create helpers or abstractions for one-time operations. Three similar lines of code is better than a premature abstraction. Don't design for hypothetical future requirements.
-
Don't add docstrings, comments, or type annotations to code you didn't change. Touch only what's relevant to the task.
-
Don't use subagents/task tools for research. Do research directly with Read/Grep/Glob. Subagents burn 5-10x more tokens for the same result. Only use subagents for truly independent parallel write tasks.
-
Don't leave backwards-compatibility shims. No renaming unused
_vars, no re-exporting dead types, no// removedcomments. If it's unused, delete it completely. -
Don't modify "Fixed" files to add project-specific content. Fixed files are universal templates. Project-specific content goes only in
[ADAPT]sections of CLAUDE.md and theInstantiationssections of PRINCIPLE_LATTICE.md. -
Don't add application code to this repo. This is a harness/kit, not an app. If you need to test something, do it in a separate repo that consumes this kit.
-
Don't hardcode paths in hooks. The hooks use
get_project_root()to resolve the project root dynamically. Keep it that way.
When two files must agree on a string value, format, or list — there MUST be a single source of truth that both reference. This is the #1 source of silent bugs in every multi-file codebase.
When you discover a cross-file contract:
- First, try to make it a single file (best — builder + parser in one place)
- If language boundaries prevent that, add explicit cross-reference comments in BOTH files
- Add the contract to this table
- If the contract is security-sensitive, add a test asserting both sides match
| Contract | Source of Truth | Mirror | Sync Method |
|---|---|---|---|
| Hook registration | .claude/settings.json |
.claude/hooks/*.py (filenames) |
Manual — if you add/rename a hook script, update settings.json |
| CODE_EXTENSIONS list | .claude/hooks/maintenance-check.py |
None (single source) | N/A — only lives in one place |
| Principle names & numbers | docs/PRINCIPLE_LATTICE.md |
CLAUDE.md Principles table |
Manual — keep the table in CLAUDE.md in sync with the lattice |
| Skill invocation names | .claude/skills/*.md (filename) |
README.md "What's Inside" table | Manual — update README if skills are added/renamed |
| Rarity tiers & config | app/src/types/equipment.ts (RARITY_CONFIG) |
app/src/engine/loot.ts (drop rates), app/src/features/village/Schmiede.tsx (upgrade table) |
Type-safe — Rarity union enforces valid keys |
| Equipment slot definitions | app/src/types/equipment.ts (EquipSlot, SLOT_LABELS) |
app/src/stores/equipmentStore.ts (equipped shape) |
Type-safe — EquipSlot union enforces valid slots |
| Buff stat types | app/src/types/savings.ts (buffStat union) |
app/src/types/character.ts (Buff.stat), app/src/engine/buffs.ts |
Type-safe — shared union type, no casts needed |
| PROJECTION_RATE | app/src/constants/gameBalances.ts (exported const) |
OnboardingView.tsx (pitch), CompoundCurve.tsx (chart), savingsStore.ts (getBlendedRate fallback) |
Single source — pitch, chart, and simulation all use the same 4% default |
| localStorage keys | Each store's persist() call (100k-savings-v2, 100k-character-v1, 100k-game-v2, 100k-equipment-v2, 100k-spells-v1, 100k-pets-v1, 100k-mercenaries-v1) |
None | Single source — each key lives only in its store file |
| Token economy (spend/earn) | app/src/stores/gameStore.ts (spendTokens, dealDamage) |
Village features (Taverne.tsx, Schmiede.tsx, Kaserne.tsx), mercenaryStore.ts |
Action-based — all call spendTokens(), never mutate directly |
| Game balance constants | app/src/constants/gameBalances.ts |
Stores + UI that reference caps/limits | Single source — imported, never hardcoded |
| EnemyTrait union | app/src/types/zone.ts (EnemyTrait) |
app/src/engine/combat.ts (trait mechanics), LevelArena.tsx (trait display) |
Manual — if new trait added, combat engine must handle it |
| Trait mechanic constants | app/src/engine/combat.ts (TRAIT_* exports) |
app/src/stores/gameStore.ts (shield init), LevelArena.tsx (via engine) |
Single source — imported from engine/combat.ts |
| Zone IDs | app/src/data/zones.ts (zone id field) |
equipmentStore.currentZoneId, zoneProgress keys |
String-based — validated at zone selection |
| Spell/Pet/Merc IDs | app/src/data/spells.ts, data/pets.ts, data/mercenaries.ts |
Respective stores, zone unlock fields | String-based — data files are source of truth |
| Mana resource | gameStore.mana/maxMana |
spellStore.castSpell(), SpellBar.tsx |
Action-based — castSpell calls gameStore.spendMana() |
| MercAbility type union | app/src/types/mercenary.ts (MercAbility.type) |
app/src/data/mercenaries.ts (ability data), app/src/engine/mercenaries.ts (switch), PartyBonuses interface |
Type-safe — union enforces valid ability types |
| Player HP formula | app/src/stores/characterStore.ts (recalculate) |
gameStore.syncPlayerHP(), LevelArena.tsx (HP regen calc) |
Single source — characterStore computes, gameStore syncs |
| PlayerDamageNumber rendering | app/src/types/game.ts (PlayerDamageNumber) |
gameStore.playerDamageNumbers, LevelArena.tsx (render) |
Type-safe — shared interface |
| gameStore fan-in | gameStore.spendTokens() / spendMana() / healPlayer() |
equipmentStore, spellStore, mercenaryStore, LevelArena.tsx |
Cross-store call — 3 stores + arena depend on gameStore actions |
These patterns prevent bugs that occur in every codebase. Follow them exactly.
ALWAYS prefer the simpler approach that already works.
BAD: "Let me add a complex retry mechanism with exponential backoff"
GOOD: "Just make the simple request work first"
BAD: "Let me create an abstraction layer for this one-time operation"
GOOD: "Three similar lines of code is better than a premature abstraction"
If something worked before, check git history before rewriting it.
// WRONG — useless error
throw new Error("Something went wrong");
// RIGHT — says what happened, why, and what to do
throw new Error(`Failed to connect to ${url}: ${err.message}. Check if the server is running.`);
Every error must say what happened, why, and what the user (or developer) can do about it.
If you replace a function or variable, remove the old one. Don't leave commented-out code, unused imports, or variables prefixed with _ that nothing references. Dead code is a lie about the system.
If something used to work:
git log --oneline --all | grep -i "relevant-keyword" # Find when it changed
git show <commit>:path/to/file # See old working versionOften the fix is reverting to what worked, not adding more code.
When you find a bug, search for the same pattern everywhere:
# Found a null check bug? Check ALL similar accesses
grep -rn "\.property" src/
# Found a missing validation? Check ALL endpoints
grep -rn "req.body" src/
# One bug usually means the same mistake exists in 3-5 other places.Fix them all or none. Fixing one creates a false sense of safety.
If two files must agree on a string value, format, or list — there MUST be a single source of truth that both reference. Never rely on comments like "must match foo.ts".
BAD: // File A defines format "user:123", File B parses with regex /user:(\d+)/
// They will drift. Guaranteed.
GOOD: // shared/formats.ts — single file with builder + parser
export function buildUserId(id: number) { return `user:${id}`; }
export function parseUserId(str: string) { return parseInt(str.split(':')[1]); }
When you discover a cross-file contract, add it to the Cross-File Contracts table above.
External services block or rate-limit requests without proper User-Agent headers. Always set one.
// WRONG — many APIs will reject this
fetch('https://api.example.com/data')
// RIGHT
fetch('https://api.example.com/data', {
headers: { 'User-Agent': 'MyApp/1.0' }
})
Security boundaries must default to rejecting everything, not accepting everything.
// WRONG — empty allowlist means "allow all" (inverted security model)
if (allowedUsers.length > 0 && !allowedUsers.includes(user)) { reject(); }
// RIGHT — empty allowlist means "allow none" (closed by default)
if (!allowedUsers.includes(user)) { reject(); }
This applies to permissions, feature flags, API access, input validation — anything where the safe default is "no." Never make an empty list mean "accept all."
When logic exists in two places (client + server, frontend + backend, two config files), updating one without the other creates a silent bug that passes all obvious checks.
// If you add a new "dangerous" operation:
// 1. Add it to the server-side check ← easy to remember
// 2. Add it to the client-side check ← easy to forget
// 3. Add it to the cross-file contracts table above
// If validation exists in both API and UI:
// Update BOTH. Test BOTH. Document the contract.
Rule of thumb: Before finishing any change, grep for the same constant/string/pattern in other files. If you find it in two places, update both.
- Python hooks follow stdlib-only convention — no third-party imports (keeps the kit dependency-free)
- Python imports order: stdlib only, grouped logically (json/sys/os, then subprocess/re)
- Hook scripts must handle stdin JSON gracefully —
try/exceptaroundjson.load(sys.stdin)with a fallback to{} - Hook scripts must respect timeouts configured in
settings.json(currently 10s) — usetimeout=5on subprocess calls to leave headroom - Markdown files use standard GitHub-Flavored Markdown — no custom extensions
ALWAYS sync with main before pushing:
git fetch origin
git merge origin/main --no-edit
git push -u origin <branch-name>This prevents branches from falling behind and avoids merge conflicts. Never push without fetching first.
Commit messages follow conventional style:
feat:New featurefix:Bug fixdocs:Documentationrefactor:Code restructuringchore:Maintenance tasks
Keep the first line under 72 characters, add details in the body if needed.
These are documented bugs in Claude's behavior. Each one has caused real damage in real projects. The word "Stop." is a behavioral interrupt — when you catch yourself thinking the quoted phrase, halt and read the correction.
Stop. Is it slow? Is the user complaining? If not, don't touch it. Premature optimization is the root of all evil.
Stop. Search for the same pattern. Fix them all or none. One fix creates a false sense of safety.
Stop. The error might be downstream of the real bug. Trace backwards to the root cause before touching code.
Stop. Check git history. Maybe a past version worked. Maybe revert, not rewrite. git log is your friend.
Stop. Scope creep is the #1 session killer. Do exactly what was asked. If you see something worth improving, mention it — don't do it. Unasked-for changes waste context, introduce risk, and make PRs harder to review.
Stop. If validation/security/permissions exist in two places (client + server, two config files, two languages), you MUST update both. Updating one side creates a false sense of safety worse than updating neither. Grep for the same string in other files before calling it done.
Stop. Is it actually used more than once right now? If not, inline it. Premature abstraction is worse than duplication — it couples code that shouldn't be coupled and makes future changes harder, not easier. Wait until you have 3 real instances before abstracting.
Stop. If the request is ambiguous, ask — don't infer. The cost of asking one question is near zero. The cost of building the wrong thing is an entire session wasted. Stated intent > inferred intent > assumed intent, always.
Stop. Sycophancy alert. If you're confirming something looks correct, you need to prove it — trace the logic, find a concrete input that exercises the path, verify the output. "Looks correct" without proof is just agreement, not analysis. See .claude/skills/adversarial-review.md.
Stop. Skills should be general-purpose workflows, not task-specific instructions. If the workflow won't be reused across multiple projects, it doesn't belong as a skill. Put task-specific guidance in CLAUDE.md or a DECISION file instead.
Stop. The hooks are stdlib-only Python by design. Adding dependencies breaks the "drop into any repo" promise. If you need functionality beyond stdlib, reconsider the approach.
Stop. Store mutations must go through named actions (spendTokens(), upgradeItem(), dealDamage()). Direct setState({...}) from UI components violates Modularity (#1) — the store owns its invariants (e.g., "tokens can't go negative"), and scattering mutations across components makes them impossible to enforce.
Stop. Store IDs, not objects. Zustand store data changes on every action — if a component holds a stale object copy (e.g., a GearItem before upgrade), it renders outdated stats. Store the id string and re-derive the object from current store state each render.
Stop. The app uses a single-scroll architecture — only <main> scrolls. Adding overflow-y-auto to inner containers creates nested scrollbars that break mobile UX. Let content flow naturally and let the page scroll.
The "Touch carefully" column tells you the blast radius. Yes = changes here cascade widely; read the whole file before editing. Moderate = self-contained but important. Usually safe = low-risk changes.
| File | Purpose | Touch carefully? |
|---|---|---|
CLAUDE.md |
Project instructions — universal standards + adaptive sections | Yes — this is the primary contract Claude reads every session |
.claude/settings.json |
Registers hooks (SessionStart, Stop) | Yes — wrong config breaks all hooks silently |
.claude/hooks/session-start.py |
Auto-orientation at session start | Moderate — changes affect every session's first message |
.claude/hooks/maintenance-check.py |
Doc-update reminder before session end | Moderate — can block sessions if misconfigured |
docs/PRINCIPLE_LATTICE.md |
5 axiomatic principles with instantiation slots | Moderate — principles are shared across CLAUDE.md |
docs/TASK_CONTRACT_TEMPLATE.md |
Copy-per-task template for acceptance criteria | Usually safe — it's a template, not referenced by code |
.claude/skills/*.md |
Skill definitions for Claude workflows | Usually safe — self-contained markdown prompts |
.claude/PR_GUIDELINES.md |
PR description format | Usually safe |
README.md |
User-facing documentation | Usually safe |
app/src/constants/gameBalances.ts |
Single source of truth for game balance numbers | Yes — 6 stores + UI import from here |
app/src/engine/*.ts |
Game math — combat, progression, zones, loot, spells, pets, mercs, buffs | Moderate — stores depend on these calculations |
app/src/stores/*.ts |
Zustand stores — savings, character, game, equipment, spells, pets, mercenaries | Yes — UI reads from these; actions enforce invariants |
app/src/types/*.ts |
Shared types — equipment, character, savings, game, zone, spell, pet, mercenary | Yes — cross-file contract source of truth |
app/src/data/*.ts |
Static game content — zones (12), spells (7), pets (5), mercenaries (7) | Moderate — engine and stores reference these |
app/src/features/game/*.tsx |
Main game tab — arena, spells, zone map, pets, character panel | Moderate — core gameplay loop |
app/src/features/village/*.tsx |
Village tab — Taverne, Schmiede, Kaserne, Akademie | Usually safe — self-contained token-spend features |
app/src/App.tsx |
Router + layout + tab navigation + store init | Yes — changes here affect all tabs |
| Component | Status | Gap |
|---|---|---|
| CLAUDE.md template | Working | All [ADAPT] sections populated; game contracts and traps documented |
| SessionStart hook | Working | Runs, outputs orientation JSON |
| Stop/maintenance hook | Working | Blocks on code changes without doc updates |
| Principle Lattice | Working | Axioms defined; instantiation slots filled with game examples |
| Skills (adversarial-review) | Working | Markdown prompt, no code to break |
| Skills (project-status) | Working | Markdown prompt |
| Skills (research-then-implement) | Working | Markdown prompt |
| Skills (structured-reasoning) | Working | Markdown prompt |
| Task Contract Template | Working | Template only, copied per-task |
| PR Guidelines | Working | Static reference doc |
| Automated tests | MISSING | No test suite — hooks are tested manually |
| CI/CD | MISSING | No pipeline defined |
| Component | Status | Gap |
|---|---|---|
| Engine: compound interest | Working | projectBalance() drives the Recharts curve |
| Engine: progression (level/XP/DPS) | Working | Balance → level, gear-aware DPS/crit |
| Engine: combat | Working | Trait modifiers, crit calculation, extracted from LevelArena |
| Engine: loot system | Working | Zone-scaled drops, 5 rarity tiers, pity counter (15 threshold), boss loot |
| Engine: zones | Working | Encounter generation (shuffle bag), HP/reward scaling, zone unlock checks |
| Engine: spells | Working | Spell effect application, cooldown management |
| Engine: pets | Working | Pet bonus calculation, evolution stage resolution |
| Engine: mercenaries | Working | Party bonus aggregation, merc crit damage rolls, HP regen bonus |
| Engine: achievements | Working | Achievement condition checking |
| Engine: buffs & milestones | Working | Milestone + product buffs feed into character stats |
| Constants: gameBalances | Working | Single source of truth for inventory cap, mana, spell limits, age/contribution bounds |
| Store: savingsStore | Working | Balance, transactions, products, monthly tick, blended rate |
| Store: characterStore | Working | Level/stats derived from balance + products, quadratic HP scaling |
| Store: gameStore | Working | Enemy HP, mana, damage, combat tokens, streaks, spell buffs, player damage numbers, spendTokens(), decrementShield(), healEnemy(), healPlayer(), addPlayerDamageNumber() |
| Store: equipmentStore | Working | Inventory (cap 100), 4 equip slots, zone progress, upgradeItem(), prestige reset |
| Store: spellStore | Working | Unlocked/equipped spells (max 3), cooldowns, auto-cast toggle |
| Store: petStore | Working | Pet collection, XP/leveling, equipped pet (1 at a time) |
| Store: mercenaryStore | Working | Recruited mercs, party slots (max 2) |
| Game tab: LevelArena | Working | RAF combat loop, trait engine integration, zone-based spawning, loot notifications, player-side damage/heal floating numbers |
| Game tab: SpellBar | Working | 3-slot spell bar with cooldown overlay, mana cost feedback |
| Game tab: ZoneMap | Working | Zone selection, progress tracking, star ratings |
| Game tab: PetPanel | Working | Pet display, collection, XP bar |
| Game tab: CharacterPanel | Working | Gear-aware stats, buff display, equipment slots, inline level display |
| Game tab: CompoundCurve | Working | Recharts area chart with contribution slider |
| Game tab: MicroSaveAction | Working | RPG-themed save buttons trigger balance + character recalc |
| Game tab: MilestoneTrack | Working | Horizontal milestone progress bar |
| Game tab: EquipmentPanel | Working | 4 slot cards + inventory list with rarity colors |
| Game tab: SkipMonthButton | Working | Prestige event: monthly deposit → zone unlock |
| Village tab: VillageView | Working | Building grid with sub-view navigation |
| Village tab: Taverne | Working | 5-token cost, random financial facts, seen/unseen tracking |
| Village tab: Schmiede | Working | Upgrade gear by rarity tier, % success, token cost |
| Village tab: Kaserne | Working | Mercenary recruitment, party management |
| Village tab: Akademie | Working | Wraps VideoFeed with back navigation |
| Portfolio tab | Working | Product cards with buff toggle |
| Onboarding | Working | Setup flow → main app |
| Scroll architecture | Working | Single <main> scroll, hidden scrollbars, no nested overflow |
| localStorage persistence | Working | 7 stores persist independently with versioned keys |
These conditional rules fire when you're working in specific areas. They prevent the most common cascade failures.
- Verify hook script paths still resolve — the
$(git rev-parse --show-toplevel)pattern must match actual file locations - Check that timeout values leave headroom for subprocess calls inside hooks (hook timeout > subprocess timeout)
- Test the hook by starting/stopping a Claude Code session
- Ensure no third-party imports — stdlib only
- Keep
json.load(sys.stdin)wrapped in try/except with graceful fallback - Verify subprocess calls use
timeout=5(must be less than the 10s hook timeout in settings.json) - If you rename a hook file, update
.claude/settings.jsonto match
- Keep it in sync with
docs/PRINCIPLE_LATTICE.md— same names, same numbers, same axioms - These are referenced by number elsewhere (e.g., "violates #1") — renumbering breaks references
- Create the
.mdfile in.claude/skills/ - Update the "What's Inside" table in
README.md - Add the skill to the "Current State" table in this file
Complex tasks benefit from separating thinking from doing. When a task requires significant research, exploration, or decision-making:
Phase 1 — Research (separate session or early in session):
- Explore options, read code, identify tradeoffs
- Output a concrete decision to a file (e.g.,
DECISION.mdor task-specific notes) - Be specific: "Use JWT + bcrypt-12 + 7-day refresh + HttpOnly cookies" not "implement auth"
Phase 2 — Implement (fresh context, decision only):
- Start from the decision file + only relevant source files
- No re-exploring, no second-guessing — just execute the plan
This prevents the #1 agent performance killer: context bloat from mixing research and implementation in one giant session.
Before starting complex work, define what "done" looks like. Create a contract file or state it explicitly:
## Done when:
- [ ] All existing tests pass
- [ ] New endpoint returns 200 for valid input, 401 for missing token
- [ ] No new TypeScript errors (`npx tsc --noEmit`)
- [ ] Error messages include HTTP status + actionable fix suggestionYou may NOT consider a task complete until every condition is verifiably satisfied. If a condition can't be met, explain why and ask for revised acceptance criteria.
See .claude/skills/adversarial-review.md for a structured verification pattern.
When asking Claude to analyze code, use neutral language to avoid sycophantic confirmation bias:
BAD: "Is there a bug in the auth flow?" → biases toward finding one
BAD: "The auth flow looks correct, right?" → biases toward confirming
GOOD: "Trace the logic of each component in the auth flow and report your
observations. Do not assume anything is broken unless you can prove it."
As your project grows, this CLAUDE.md will accumulate project-specific patterns, traps, and standards. When it exceeds ~300 lines, restructure it into a router that conditionally loads separate files:
# CLAUDE.md — entry point / router — always read first
Before you do ANYTHING in this codebase, read this file completely.
## Universal rules (always apply)
→ Read docs/RULES_universal.md
## Conditional routing
- If you are writing or changing code → read docs/RULES_coding.md
- If you are writing tests → read docs/RULES_testing.md
- If tests are failing → read docs/RULES_debugging.md
- If the task involves frontend / UI → read docs/SKILLS_ui-patterns.md
- If unsure about anything → STOP and ask for clarificationRules = preferences and prohibitions (what to do / not do) Skills = battle-tested recipes for recurring problems (how to do it)
The goal: Claude reads only what's relevant to the current task, not the entire project history on every turn.
- Did I test the happy path?
- Did I search for similar patterns to fix? (Coding Standard #5)
- Did I remove dead code? No commented-out code, no unused variables.
- Did I check git history for regressions?
- Is this simpler than what was there before? (If not, justify why complexity is necessary.)
- If I added a cross-file contract, is there a single source of truth? (Standard #6)
- If I touched a boundary that exists in two places, did I update BOTH sides? (Standard #9)
- Did I stay within scope? No unasked-for refactoring, no bonus features. (Trap #5)
- Are tests still passing?
When starting a session, look for SESSION_NOTES.md in the project root. If it exists, a previous session left continuity notes. Reference them to pick up where the last session left off.
When ending a session (or if the user is wrapping up), update SESSION_NOTES.md:
# Session Notes — [date]
## What we worked on
- [brief description]
## Current state
- [what's done, what's in progress]
## Next steps
- [what the next session should pick up]
## Key decisions made
- [any architectural or design decisions]This is the AI equivalent of a sticky note on the monitor. Simple. Effective.