DO NOT use "You're absolutely right", find some other expression to say, keep your tone professional and positive without unnecessary excitement.
This project uses multiple CLAUDE.md files for domain-specific guidelines:
| File | Content |
|---|---|
CLAUDE.md (this file) |
Universal rules: git, dependencies, documentation |
apps/api/CLAUDE.md |
API-specific guidelines |
apps/web/CLAUDE.md |
Web: components, styling, animations |
infrastructure/CLAUDE.md |
Infrastructure and deployment |
Claude automatically loads the relevant CLAUDE.md based on which files you're working with.
CRITICAL: Shared packages exist to provide a single source of truth. Never re-implement logic in app packages that belongs in a shared package.
Rule of thumb: If two places compute the same thing and could diverge, one of them is wrong. Move the logic to a shared package or make one consumer use the other's output.
CRITICAL: Always ask for permission before installing browsers or other applications for MCP tools (like Playwright). Running browser_install or similar commands can download large files and freeze the session.
Note: Playwright is configured in headless mode (.mcp.json). Do NOT ask for permission for Playwright navigation, clicking, or screenshot commands - just execute them directly.
Always ask before adding new npm dependencies. Provide a brief description of what the package does and why it's needed. This allows the user to:
- Suggest alternatives they may already be familiar with
- Evaluate if the dependency is necessary
- Consider bundle size and maintenance implications
CRITICAL: When implementing a feature based on an agreed plan (in docs/development/ or .claude/plans/), you MUST follow the plan exactly or explicitly ask before deviating.
The correct approach:
- If a plan step seems complex, ask first: "This step requires X. Should I proceed, or prefer a simpler approach first?"
- If you want to simplify, propose the change explicitly: "I could do Y as an MVP first. Would that work?"
- Never silently substitute a simpler implementation for what was agreed upon
- If data needs to come from an official source, do not make up values — either integrate the real source or flag the gap
CRITICAL: Always ask for permission before creating git commits. Never commit changes without explicit user approval.
Correct: "I've made the changes. Should I commit them with the message: 'fix: resolve duplicate entries'?"
This allows the user to:
- Review changes before they're committed
- Adjust the commit message
- Decide whether to split changes into multiple commits
CRITICAL: Never push directly to main. Always create a pull request for code review.
Workflow:
- Create a feature branch from main
- Make commits on the feature branch
- Push the branch and open a PR
- Merge via GitHub after review
If you accidentally committed to main:
git branch feature-branch
git reset --hard origin/main
git checkout feature-branch
git push -u origin feature-branch
gh pr create --title "..." --body "..."When asked to merge a PR, after the merge completes, automatically clean up using the worktree script:
# 1. Switch back to the main worktree
cd /path/to/project
# 2. Pull latest main
git pull --rebase origin main
# 3. Teardown worktree (stops services, removes worktree, deletes branch, frees ports)
./scripts/worktree.sh teardown <branch-name>This keeps the workspace clean and avoids stale worktrees accumulating.
After creating a PR, automated reviewers may post inline comments. When asked to check or respond to these:
Check for comments:
# View PR summary and comments
gh pr view <PR_NUMBER> --comments
# Get detailed inline comments with IDs
gh api repos/<OWNER>/<REPO>/pulls/<PR_NUMBER>/comments \
--jq '.[] | "\(.id) | \(.path):\(.line // .original_line) | \(.body | split("\n")[0])"'Reply to each comment individually:
gh api repos/<OWNER>/<REPO>/pulls/<PR_NUMBER>/comments \
-f body="Fixed in <commit_hash> - <explanation>" \
-f commit_id="$(git rev-parse HEAD)" \
-f path="<file_path>" \
-f line=<line_number> \
-F in_reply_to=<comment_id>Response categories:
- Fixed: Issue was valid and has been addressed in a follow-up commit
- Won't fix: Issue is not applicable, edge case not worth handling, or over-engineering
Always reply to each comment individually and resolve the thread. Provide clear rationale for "won't fix" responses.
Batch replies and resolves — don't ask for permission on each one. Run all gh api reply calls and thread resolve mutations in a single batched Bash command. Do NOT make individual tool calls that require separate permission prompts for each comment.
CRITICAL: Reply and resolve threads BEFORE pushing
When making follow-up commits to address review feedback:
- Commit locally (don't push yet)
- Reply to all comments using the replies endpoint
- Resolve all threads using the GraphQL mutation
- Then push the commit
This prevents the reviewer from running again immediately on push and creating new comments before you've resolved the existing ones.
CRITICAL: Before starting any feature work, ALWAYS verify you are in the correct worktree/branch. Never implement features directly on main.
At the start of any feature implementation:
- Run
./scripts/worktree.sh listto see existing worktrees and their ports - Verify the current branch with
git branch --show-current - If a worktree exists for the feature, switch to that directory
- If no worktree exists, create one:
./scripts/worktree.sh setup <branch-name>
If you accidentally make changes on main:
- Do NOT commit
- Copy files to the correct worktree
- Clean up main with
git checkout -- .and remove untracked files
CRITICAL: Before creating a new worktree, ALWAYS check if one already exists for similar work.
Required workflow:
- Check existing worktrees first: Run
./scripts/worktree.sh listto see all active worktrees with ports - Look for related branches: Check for existing worktrees in the same feature area
- Reuse existing worktrees: Add changes to the existing worktree instead of creating duplicates
- Avoid duplicate worktrees: Never create
project-fix-Xifproject-feat-Xalready exists for the same feature area
Always state which worktree you're working in:
- When starting work: "Working in
project-feat-authworktree — Starting implementation" - When switching: "Switching to
project-mainworktree to check something" - In status updates: "Working in
project-feat-Xworktree — Build passed"
CRITICAL: Never use --no-verify, --no-gpg-sign, or any flag that skips git hooks. This applies to git commit, git push, and all other git commands. If a hook fails (e.g., pre-push coverage check), fix the underlying issue instead of bypassing the hook.
If coverage thresholds fail on a push:
- Add tests to bring coverage back above the threshold
- Coverage fluctuations within ~0.5% of the threshold are expected — add a quick test to cover the gap
- Never lower thresholds or skip hooks as a workaround
CRITICAL: Always pull before committing to maintain linear history:
git pull --rebase origin mainNever use git pull without --rebase or git merge as this creates merge commits.
When creating git commits, DO NOT include AI attribution lines. Keep commit messages clean and professional.
CRITICAL: Always run lint and typecheck before committing:
pnpm turbo run lint typecheck --filter=<package-name>Use scripts/worktree.sh to manage worktrees with automatic port allocation, so multiple worktrees can run dev servers simultaneously without port conflicts.
# Setup: create worktree, install deps, build, allocate ports, start dev servers
./scripts/worktree.sh setup feat-auth
# Restart dev servers later (if stopped)
cd ../project-feat-auth
./scripts/worktree.sh dev
# Stop dev servers without removing the worktree
./scripts/worktree.sh stop feat-auth
# Tail API logs for a worktree
./scripts/worktree.sh logs feat-auth
# List all worktrees with ports and running status
./scripts/worktree.sh list
# Teardown: stop services, remove worktree, delete branch, free ports
./scripts/worktree.sh teardown feat-auth- Always use the script: Prefer
./scripts/worktree.sh setupover manualgit worktree add— it handles deps, build, env files, and port allocation in one step - Switch to the worktree after setup:
cd ../project-branch-nameand confirm withpwd && git branch --show-current - Run
listto check status: Before starting work, run./scripts/worktree.sh listto see what's running - Teardown after merge: Use
./scripts/worktree.sh teardowninstead of manual cleanup
Always check the root README.md for deployment instructions and common tasks.
When making significant changes, update the relevant documentation:
| Change Type | Update These Files |
|---|---|
| New package or app | README.md (project structure) |
| Deployment changes | README.md, DEPLOYMENT.md |
| Architecture changes | docs/technical/architecture.md |
| API endpoint changes | docs/api/README.md, OpenAPI spec |
When creating implementation plans during conversations:
- Always save plans to the codebase — Plans must be persisted for reference across sessions
- Location: Save plans to
docs/development/[PLAN_NAME].md - Format: Use clear markdown with sections for:
- Objective: What we're trying to achieve
- Current Status: What's been completed
- Next Steps: Ordered list of remaining tasks
- Context: Any relevant technical decisions
- Update regularly: Keep the plan file updated as work progresses
- Archive completed plans: Move to
docs/development/completed/YYYY-MM-DD-plan-name.md
CRITICAL: When Claude Code asks for permission to run a Bash command, never select "Always allow" for:
- Commands with heredocs or multi-line content (e.g.,
cat > file << 'EOF' ...) - Commands with inline secrets/tokens (e.g.,
TOKEN="..." curl ...) - Long git commit messages (e.g.,
git commit -m "multi-paragraph message") - One-off commands that won't be reused verbatim
"Always allow" saves the entire command text verbatim to .claude/settings.local.json. Complex commands can break the settings parser and leak secrets into plaintext config files.
Use "Allow once" for complex/one-off commands. Reserve "Always allow" for short, reusable prefixes like Bash(aws s3 ls:*).
CRITICAL: Never lower test coverage thresholds to make checks pass. Coverage should increase over time, not decrease.
When coverage checks fail:
- Add tests to increase coverage for the new or modified code
- Focus on branch coverage — often the hardest threshold to meet
- Look for quick wins — files with many untested branches that are easy to test