Add dotclaude configuration files
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
+11
@@ -0,0 +1,11 @@
|
||||
# Local overrides (not shared with team)
|
||||
settings.local.json
|
||||
CLAUDE.local.md
|
||||
|
||||
# OS artifacts
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
|
||||
# Editor artifacts
|
||||
*.swp
|
||||
*~
|
||||
@@ -0,0 +1,26 @@
|
||||
# Personal Overrides
|
||||
|
||||
> Rename this to CLAUDE.local.md — it's gitignored and won't be shared with the team.
|
||||
|
||||
## My Preferences
|
||||
|
||||
- I prefer verbose commit messages with context
|
||||
- Always explain your reasoning before making changes
|
||||
- When in doubt, ask rather than guess
|
||||
|
||||
## Environment
|
||||
|
||||
- My test database runs on port 5433 (not default 5432)
|
||||
- Use `pnpm` instead of `npm` on my machine
|
||||
|
||||
## Shortcuts
|
||||
|
||||
- When I say "ship it", run `/ship`
|
||||
- When I say "review", run `/pr-review`
|
||||
- When I say "fix it", run `/debug-fix`
|
||||
|
||||
## Current Context
|
||||
|
||||
- I'm working on the billing module this sprint
|
||||
- The staging environment is at https://staging.example.com
|
||||
- Feature flags are managed in LaunchDarkly
|
||||
@@ -0,0 +1,49 @@
|
||||
# Project Instructions
|
||||
|
||||
> REPLACE: Customize this file for your project. Delete sections that don't apply — every line costs tokens. Code style lives in .claude/rules/code-quality.md — don't duplicate here. Run `/setupdotclaude` to auto-customize, or edit manually and delete all `> REPLACE:` blocks when done.
|
||||
|
||||
## Commands
|
||||
|
||||
```bash
|
||||
# Build
|
||||
npm run build # or: cargo build, go build ./..., make build
|
||||
|
||||
# Test
|
||||
npm test # run full suite
|
||||
npm test -- path/to/file # run single test file
|
||||
|
||||
# Lint & Format
|
||||
npm run lint # check style
|
||||
npm run lint:fix # auto-fix style
|
||||
npm run typecheck # type checking
|
||||
|
||||
# Dev
|
||||
npm run dev # start dev server
|
||||
```
|
||||
|
||||
## Architecture
|
||||
|
||||
> REPLACE: Describe non-obvious architectural decisions. Don't list files — Claude can explore.
|
||||
|
||||
- `src/` — application source
|
||||
- `src/api/` — REST endpoints (versioned: `/v1/`)
|
||||
- `src/services/` — business logic (no direct DB access from controllers)
|
||||
- `src/models/` — data models and types
|
||||
|
||||
## Key Decisions
|
||||
|
||||
> REPLACE: Record WHY non-obvious choices were made. This is the most valuable section. Examples: "Auth tokens in httpOnly cookies because XSS risk", "Billing is a separate module for audit independence".
|
||||
|
||||
## Domain Knowledge
|
||||
|
||||
> REPLACE: Terms, abbreviations, or concepts that aren't obvious from the code. Example: "SKU" = Stock Keeping Unit, the unique product identifier from our warehouse system.
|
||||
|
||||
## Workflow
|
||||
|
||||
- Run typecheck after making a series of code changes
|
||||
- Prefer fixing the root cause over adding workarounds
|
||||
- When unsure about approach, use plan mode (`Shift+Tab`) before coding
|
||||
|
||||
## Don'ts
|
||||
|
||||
- Don't modify generated files (`*.gen.ts`, `*.generated.*`)
|
||||
@@ -0,0 +1,99 @@
|
||||
# Contributing to dotclaude
|
||||
|
||||
Thanks for wanting to make this better. This project aims to be the standard `.claude/` folder structure — contributions that help more developers ship faster are welcome.
|
||||
|
||||
## Before You Contribute
|
||||
|
||||
- Check existing issues and open PRs to avoid duplicate work
|
||||
- For large changes (new skills, new agents, restructuring), open an issue first to discuss the approach
|
||||
|
||||
## What We're Looking For
|
||||
|
||||
**Yes, please:**
|
||||
- Bug fixes in hook scripts
|
||||
- Improvements to existing rules, skills, or agents that make them more effective
|
||||
- New skills for common daily workflows (not project-creation workflows)
|
||||
- New agents for common review/analysis tasks
|
||||
- Better token efficiency — same quality, fewer tokens
|
||||
- Documentation improvements
|
||||
|
||||
**Probably not:**
|
||||
- Language-specific rules — Claude already knows standard conventions
|
||||
- Plugin integrations — this repo is deliberately plugin-free
|
||||
- Project scaffolding skills — this is for daily work, not project creation
|
||||
- Vendor-specific configurations (specific CI providers, cloud platforms, etc.)
|
||||
|
||||
## PR Rules
|
||||
|
||||
### One thing per PR
|
||||
|
||||
Each PR should do exactly one thing. Don't bundle a new skill with a rule fix with a README update. Split them.
|
||||
|
||||
### File requirements
|
||||
|
||||
| File type | Must have | Must NOT have |
|
||||
|---|---|---|
|
||||
| **Rules** (`.md` in `rules/`) | `alwaysApply: true` or `paths:` frontmatter | Language-specific conventions Claude already knows |
|
||||
| **Skills** (`SKILL.md`) | `name`, `description` in frontmatter | Hardcoded package names, model assignments |
|
||||
| **Agents** (`.md` in `agents/`) | `name`, `description`, `tools` in frontmatter | `model` field (users choose their own model) |
|
||||
| **Hooks** (`.sh` in `hooks/`) | `jq` availability check, proper exit codes (0=allow, 2=block) | Hardcoded paths, missing `#!/bin/bash` |
|
||||
|
||||
### Naming
|
||||
|
||||
- Skill directories: `kebab-case` — `debug-fix/`, `test-writer/`
|
||||
- Agent files: `kebab-case.md` — `code-reviewer.md`, `security-reviewer.md`
|
||||
- Rule files: `kebab-case.md` — `code-quality.md`, `frontend.md`
|
||||
- Hook scripts: `kebab-case.sh` — `protect-files.sh`, `block-dangerous-commands.sh`
|
||||
|
||||
### No duplication
|
||||
|
||||
Before adding content, check that it's not already covered elsewhere:
|
||||
|
||||
- If a hook enforces it, don't also add a rule saying the same thing
|
||||
- If a skill covers it, don't duplicate the guidance in a rule
|
||||
- If `CLAUDE.md` says it, don't repeat it in a rule
|
||||
- Agents run isolated and CAN repeat rule content (they don't see rules)
|
||||
|
||||
### No hardcoded opinions
|
||||
|
||||
This is a template — keep it framework-agnostic:
|
||||
|
||||
- Don't hardcode `npm`, `pnpm`, `yarn`, or any specific package manager
|
||||
- Don't hardcode specific component libraries, CSS frameworks, or test runners
|
||||
- Don't assign `model` to agents or skills — let users choose
|
||||
- Present options as tables or lists, not mandates
|
||||
- The `/setupdotclaude` skill handles project-specific customization at runtime
|
||||
|
||||
### Token consciousness
|
||||
|
||||
Every line in a rule costs tokens every session. Every line in a skill costs tokens when invoked. Before adding content, ask: "Would removing this cause Claude to make mistakes?" If no, don't add it.
|
||||
|
||||
### Hook scripts must be safe
|
||||
|
||||
- Always check for `jq` availability before using it
|
||||
- Exit 0 (allow) if dependencies are missing — don't block the user
|
||||
- PreToolUse hooks observe and block — they should never modify files. PostToolUse hooks may transform output (e.g., formatting).
|
||||
- Test with sample JSON input before submitting
|
||||
|
||||
### Update READMEs
|
||||
|
||||
If you add a new file to `rules/`, `skills/`, `agents/`, or `hooks/`, add a description to the README in that folder. Keep it to 2-3 lines.
|
||||
|
||||
### Update the root README
|
||||
|
||||
If your change adds or removes a file, update the structure tree in `README.md` to match.
|
||||
|
||||
## How to Submit
|
||||
|
||||
1. Fork the repo
|
||||
2. Create a branch: `feat/your-skill-name` or `fix/hook-bug-description`
|
||||
3. Make your changes
|
||||
4. Test: verify YAML frontmatter is valid, hook scripts work with sample input, no duplication with existing files
|
||||
5. Open a PR with:
|
||||
- **Title**: what you added/changed (under 72 chars)
|
||||
- **Body**: why it's useful, what daily workflow it improves
|
||||
- **Testing**: how you verified it works
|
||||
|
||||
## Code of Conduct
|
||||
|
||||
Be helpful, be kind, be constructive. We're all here to make Claude Code better for daily development work.
|
||||
@@ -0,0 +1,220 @@
|
||||
# dotclaude
|
||||
|
||||
The standard `.claude/` folder structure for everyday development.
|
||||
|
||||
## Why This Exists
|
||||
|
||||
Plugins consume hundreds of tokens per turn and are designed for specific workflows like scaffolding entire projects. But day-to-day, you're fixing bugs, adding features, reviewing code, and writing tests — not building products from scratch.
|
||||
|
||||
This repo provides a lean, token-efficient `.claude/` configuration optimized for **daily development work**. Copy what you need, delete what you don't.
|
||||
|
||||
## Getting Started
|
||||
|
||||
### 1. Copy everything into your project
|
||||
|
||||
```bash
|
||||
git clone https://github.com/poshan0126/dotclaude.git /tmp/dotclaude
|
||||
|
||||
cd your-project
|
||||
mkdir -p .claude
|
||||
|
||||
# Copy config files
|
||||
cp /tmp/dotclaude/settings.json .claude/
|
||||
cp -r /tmp/dotclaude/{rules,skills,agents,hooks} .claude/
|
||||
cp /tmp/dotclaude/.gitignore .claude/
|
||||
cp /tmp/dotclaude/CLAUDE.md ./
|
||||
cp /tmp/dotclaude/CLAUDE.local.md.example ./
|
||||
|
||||
chmod +x .claude/hooks/*.sh
|
||||
rm -rf /tmp/dotclaude
|
||||
|
||||
# Add CLAUDE.local.md to your project root .gitignore
|
||||
echo "CLAUDE.local.md" >> .gitignore
|
||||
```
|
||||
|
||||
### 2. Reload Claude Code
|
||||
|
||||
If you already have a Claude Code session open, **exit and restart it**. Skills, agents, and rules are loaded at session start — a running session won't see the new files.
|
||||
|
||||
### 3. Run `/setupdotclaude`
|
||||
|
||||
```
|
||||
/setupdotclaude
|
||||
```
|
||||
|
||||
This will:
|
||||
- Clean up README files that waste tokens
|
||||
- Scan your codebase (tech stack, test framework, linters, folder structure)
|
||||
- Customize `CLAUDE.md` with your actual build/test/lint commands
|
||||
- Update `settings.json` permissions for your package manager
|
||||
- Adjust rule paths to match your real directories
|
||||
- Auto-detect and enable your project's formatter (Prettier, Biome, Ruff, Black, rustfmt, gofmt)
|
||||
- Remove config that doesn't apply (e.g., frontend rules if you have no frontend)
|
||||
- Run a final review pass against your full codebase
|
||||
|
||||
Every change is confirmed with you before it's applied.
|
||||
|
||||
> If you skip `/setupdotclaude`, delete the `README.md` files inside `.claude/` subdirectories — they're for GitHub browsing only and waste tokens at runtime.
|
||||
|
||||
### Troubleshooting
|
||||
|
||||
| Problem | Fix |
|
||||
|---------|-----|
|
||||
| Skills or agents not showing up | **Restart Claude Code** — skills/agents/rules are loaded at session start |
|
||||
| Hooks not running | Run `chmod +x .claude/hooks/*.sh` and verify `jq` is installed |
|
||||
| "jq not found" blocking everything | Install jq: `brew install jq` (macOS) or `apt install jq` (Linux) |
|
||||
| format-on-save not formatting | Ensure the formatter binary is installed locally and its config file exists in the project root |
|
||||
| Permission denied on allowed commands | Check glob syntax in `settings.json` — `Bash(npm run test *)` means the `*` matches arguments after `test` |
|
||||
| `/setupdotclaude` asks to confirm settings.json edits | This is expected — `protect-files.sh` prompts for confirmation when editing `settings.json` (hook scripts remain hard-blocked) |
|
||||
|
||||
### 4. Make it yours
|
||||
|
||||
`/setupdotclaude` gets you 90% of the way. To give it your unique touch:
|
||||
|
||||
- **`rules/code-quality.md`** — update naming conventions to match your team's style. Tweak the comment guidelines, code marker format, and import order.
|
||||
- **`rules/frontend.md`** — pick your design principle. Highlight which component framework your project uses.
|
||||
- **`rules/security.md`** — add paths specific to your project's sensitive areas beyond the defaults.
|
||||
- **`CLAUDE.md`** — add architectural decisions, domain knowledge, and workflow quirks unique to your project.
|
||||
- **`CLAUDE.local.md`** — rename the `.example` file for personal preferences (gitignored).
|
||||
- **`hooks/format-on-save.sh`** — if `/setupdotclaude` didn't detect your formatter, uncomment the right section manually.
|
||||
|
||||
The defaults are solid foundations. Your edits on top are what make Claude truly effective for *your* project.
|
||||
|
||||
## Skills (Slash Commands)
|
||||
|
||||
Skills are invoked with `/name` in your Claude Code session. All skills except `/test-writer` are manual-only — you invoke them explicitly.
|
||||
|
||||
| Command | Arguments | Description |
|
||||
|---------|-----------|-------------|
|
||||
| `/setupdotclaude` | `[focus area]` | Scan your codebase and customize all `.claude/` config files to match your actual tech stack. Run once after copying dotclaude into a project. Detects language, framework, package manager, test runner, linter, and architecture — then updates CLAUDE.md, settings.json, rules, hooks, and agents. Confirms every change before applying. |
|
||||
| `/debug-fix` | `[issue #, error msg, or description]` | Find and fix a bug from any source. Reproduces the issue, traces root cause through code and git history, makes the minimal fix, writes a regression test, and wraps up with a branch and commit. |
|
||||
| `/ship` | `[commit message or PR title]` | Full shipping workflow: scans changes, stages files (skipping secrets/locks/build output), drafts a commit message matching repo style, pushes, and creates a PR. Every step requires your confirmation. |
|
||||
| `/hotfix` | `[issue #, error msg, or description]` | Emergency production fix. Creates a `hotfix/` branch from main, makes the smallest correct change (no refactoring), runs only critical tests, and ships a PR with `[HOTFIX]` label. Warns if the fix is too complex for a hotfix. |
|
||||
| `/pr-review` | `[PR #, "staged", file path, or omit]` | Delegates review to specialist agents: `@code-reviewer`, `@security-reviewer` (if security-related code), `@performance-reviewer` (if perf-sensitive), `@doc-reviewer` (if docs changed). Synthesizes a unified report with severity-ranked findings. |
|
||||
| `/tdd` | `[feature description or function signature]` | Strict Red-Green-Refactor TDD loop. Writes one failing test, then minimum code to pass, then refactors. Commits after each green+refactor cycle. Works simple-to-complex: degenerate cases, happy path, variations, edge cases, errors. |
|
||||
| `/explain` | `[file, function, or concept]` | Explains code with a one-sentence summary, mental model analogy, ASCII diagram, key non-obvious details, and modification guide. Focuses on the "why" and landmines, not the obvious. |
|
||||
| `/refactor` | `[file, function, or pattern]` | Safe refactoring with tests as a safety net. Writes tests first if none exist, plans transformations, makes small testable steps, verifies after each step. Never mixes refactoring with behavior changes. |
|
||||
| `/test-writer` | *(auto-triggers)* | Writes comprehensive tests for new or changed code. Discovers changes via git diff, maps all code paths (happy, edge, error, concurrency), writes one test per scenario with Arrange-Act-Assert. **This is the only skill that can auto-trigger** — Claude may invoke it automatically after you add new features. |
|
||||
|
||||
## Agents (Subagents)
|
||||
|
||||
Agents are specialized Claude instances that run in their own isolated context. They are auto-delegated by Claude based on the task, or you can invoke them explicitly with `@agent-name` in your prompt.
|
||||
|
||||
| Agent | When It's Used | What It Does |
|
||||
|-------|---------------|--------------|
|
||||
| `@code-reviewer` | Auto-delegated by `/pr-review`, or invoke directly | Reviews code for correctness and maintainability. Catches off-by-one errors, null dereferences, logic bugs, race conditions, error handling gaps, excessive complexity, and missing tests. Focuses on real issues with evidence — not style nitpicks or linter territory. |
|
||||
| `@security-reviewer` | Auto-delegated by `/pr-review` when security-related code is changed | Senior security engineer performing static analysis. Covers injection (SQL, command, XSS, template, path traversal), auth/authz flaws, data exposure, cryptography issues, dependency vulnerabilities, and input validation gaps. Reports severity, attack vector, and concrete fix for each finding. |
|
||||
| `@performance-reviewer` | Auto-delegated by `/pr-review` when performance-sensitive code is changed | Finds real bottlenecks, not theoretical micro-optimizations. Checks for N+1 queries, missing indexes, unbounded queries, memory leaks, repeated computation, blocking I/O on hot paths, unnecessary re-renders, bundle size issues, and lock contention. Only flags issues with measurable impact. |
|
||||
| `@frontend-designer` | Auto-delegated when building UI, or invoke directly | Creates distinctive, production-grade frontend UI that avoids generic "AI aesthetics." Enforces design tokens, chooses appropriate design principles (glassmorphism, brutalism, editorial, etc.), ensures accessibility (WCAG), and prevents common anti-patterns like purple gradients, centered-everything layouts, and overused fonts. |
|
||||
| `@doc-reviewer` | Auto-delegated by `/pr-review` when documentation changes | Reviews docs for accuracy by cross-referencing actual source code. Verifies function signatures, code examples, config options, and file paths are correct. Identifies stale references, missing prerequisites, undocumented error cases, and unclear instructions. |
|
||||
|
||||
### Using Agents Directly
|
||||
|
||||
You can invoke any agent in your prompt:
|
||||
|
||||
```
|
||||
@security-reviewer Review the auth middleware changes in src/middleware/auth.ts
|
||||
```
|
||||
|
||||
```
|
||||
@frontend-designer Build a dashboard page for the analytics module
|
||||
```
|
||||
|
||||
```
|
||||
@code-reviewer Check my staged changes before I commit
|
||||
```
|
||||
|
||||
Agents run in isolated context — they don't see your conversation history, but they have access to the full codebase through their allowed tools.
|
||||
|
||||
## Customization Guide
|
||||
|
||||
| Want to... | Do this |
|
||||
|---|---|
|
||||
| Add project-specific rules | Create `.claude/rules/your-rule.md` |
|
||||
| Scope rules to file paths | Add `paths:` frontmatter to rule files |
|
||||
| Add a team workflow | Create `.claude/skills/your-skill/SKILL.md` |
|
||||
| Add a specialist reviewer | Create `.claude/agents/your-agent.md` |
|
||||
| Enforce behavior deterministically | Add a hook in `settings.json` |
|
||||
| Override settings locally | Copy `settings.local.json.example` → `.claude/settings.local.json` |
|
||||
| Personal CLAUDE.md overrides | Rename `CLAUDE.local.md.example` → `CLAUDE.local.md` |
|
||||
|
||||
### Example: Project-specific rule
|
||||
|
||||
```yaml
|
||||
---
|
||||
paths:
|
||||
- "src/billing/**"
|
||||
---
|
||||
|
||||
# Billing Module
|
||||
|
||||
- All monetary values use cents (integers), never floating point dollars
|
||||
- Tax calculations must use the tax-engine service, never inline math
|
||||
- Every billing mutation must be idempotent with a unique request ID
|
||||
```
|
||||
|
||||
## What's Inside
|
||||
|
||||
> **Note**: This repo is flat (not nested inside `.claude/`) because `CLAUDE.md` goes at your project root while everything else goes inside `.claude/`. The copy commands below handle the separation.
|
||||
|
||||
```
|
||||
dotclaude/
|
||||
├── CLAUDE.md # Template project instructions → copy to YOUR project root
|
||||
├── CLAUDE.local.md.example # Personal overrides template → copy and rename to CLAUDE.local.md
|
||||
├── settings.json # Project settings → copy to .claude/
|
||||
├── settings.local.json.example # Personal settings template → copy to .claude/settings.local.json
|
||||
├── .gitignore # Gitignore for .claude/ directory
|
||||
├── rules/ # Modular instructions → copy to .claude/rules/
|
||||
│ ├── code-quality.md # Principles, naming, comments, markers, file organization
|
||||
│ ├── testing.md # Testing conventions (always loaded)
|
||||
│ ├── database.md # Migration safety rules (loads near migration files)
|
||||
│ ├── error-handling.md # Error handling patterns (loads near backend files)
|
||||
│ ├── security.md # Security rules (loads near API/auth files)
|
||||
│ └── frontend.md # Design tokens, principles, accessibility (loads near UI files)
|
||||
├── skills/ # Slash commands → copy to .claude/skills/
|
||||
│ ├── setupdotclaude/SKILL.md # /setupdotclaude — scan codebase, customize all config files
|
||||
│ ├── debug-fix/SKILL.md # /debug-fix — find and fix bugs from any source
|
||||
│ ├── ship/SKILL.md # /ship — commit, push, PR with confirmations
|
||||
│ ├── hotfix/SKILL.md # /hotfix — emergency production fix, minimal change, ship fast
|
||||
│ ├── pr-review/SKILL.md # /pr-review — review PR or staged changes via specialist agents
|
||||
│ ├── tdd/SKILL.md # /tdd — strict red-green-refactor TDD loop
|
||||
│ ├── explain/SKILL.md # /explain <file-or-function>
|
||||
│ ├── refactor/SKILL.md # /refactor <target>
|
||||
│ └── test-writer/SKILL.md # Auto-triggers on new features — comprehensive tests
|
||||
├── agents/ # Specialized subagents → copy to .claude/agents/
|
||||
│ ├── frontend-designer.md # Creates distinctive UI — anti-AI-slop
|
||||
│ ├── security-reviewer.md # Security-focused code review
|
||||
│ ├── performance-reviewer.md # Finds real bottlenecks, not theoretical ones
|
||||
│ ├── code-reviewer.md # General code review
|
||||
│ └── doc-reviewer.md # Documentation accuracy and completeness
|
||||
└── hooks/ # Hook scripts → copy to .claude/hooks/
|
||||
├── protect-files.sh # Block edits to sensitive files and directories
|
||||
├── warn-large-files.sh # Block writes to build artifacts and binary files
|
||||
├── scan-secrets.sh # Detect API keys, tokens, and credentials in file content
|
||||
├── block-dangerous-commands.sh # Block push to main, force push, reset --hard, publish, rm -rf, DROP TABLE
|
||||
├── format-on-save.sh # Auto-format after edits (auto-detects Prettier, Black, Ruff, Biome, rustfmt, gofmt)
|
||||
└── session-start.sh # Inject branch/commit/stash/PR context at session start
|
||||
```
|
||||
|
||||
## What NOT to Put in .claude/
|
||||
|
||||
- **Plugins for daily work** — they eat 200-500+ tokens/turn and are scoped to specific workflows
|
||||
- **Anything Claude can read from code** — don't describe your file structure, Claude can explore it
|
||||
- **Standard conventions** — Claude already knows PEP 8, ESLint defaults, Go formatting
|
||||
- **Verbose explanations** — every line in CLAUDE.md costs tokens; if removing it doesn't cause mistakes, cut it
|
||||
- **Frequently changing info** — put volatile details in code comments or docs, not CLAUDE.md
|
||||
|
||||
**Token cost rule of thumb**: Rules with `alwaysApply: true` cost tokens every turn. Path-scoped rules only cost tokens when working near matched files. Skills and agents cost tokens only when invoked.
|
||||
|
||||
## Credits
|
||||
|
||||
Built from research across:
|
||||
- [Official Claude Code Documentation](https://code.claude.com/docs/en)
|
||||
- [Trail of Bits claude-code-config](https://github.com/trailofbits/claude-code-config)
|
||||
- [awesome-claude-code](https://github.com/hesreallyhim/awesome-claude-code)
|
||||
- [awesome-claude-code-config](https://github.com/Mizoreww/awesome-claude-code-config)
|
||||
- Community best practices from hundreds of Claude Code power users
|
||||
|
||||
## License
|
||||
|
||||
MIT — use it, fork it, adapt it, share it.
|
||||
@@ -0,0 +1,42 @@
|
||||
# Agents
|
||||
|
||||
Agents are specialized Claude instances that run in **isolated context**. They don't see your conversation history or loaded rules — they only have their own system prompt and tools.
|
||||
|
||||
Claude delegates to agents automatically based on the task description, or you can invoke them with `@agent-name`.
|
||||
|
||||
## Available Agents
|
||||
|
||||
### frontend-designer
|
||||
Creates distinctive, production-grade UI. Finds or creates design tokens first, picks a design principle, then builds components. Has Write/Edit tools so it actually generates files. Anti-AI-slop aesthetics built in.
|
||||
|
||||
### security-reviewer
|
||||
Reviews code for OWASP-style vulnerabilities: injection, broken auth, data exposure, weak crypto, missing validation. Reports findings by severity with exact file:line locations and specific fixes.
|
||||
|
||||
### performance-reviewer
|
||||
Finds real bottlenecks — not theoretical micro-optimizations. Covers database (N+1, missing indexes), memory (leaks, unbounded caches), computation (repeated work, blocking calls), network (sequential calls, missing timeouts), frontend (re-renders, bundle size), and concurrency (lock contention, missing pooling).
|
||||
|
||||
### code-reviewer
|
||||
General code review with specific bug patterns to catch: off-by-one errors, null dereferences, inverted conditions, race conditions, swallowed errors, misleading names, excessive complexity. Includes concrete examples for each category. Skips style nitpicks.
|
||||
|
||||
### doc-reviewer
|
||||
Reviews documentation for accuracy (do docs match code?), completeness (are required params documented?), staleness (do referenced APIs still exist?), and clarity. Cross-references with actual source code using grep and file reads.
|
||||
|
||||
## Adding Your Own
|
||||
|
||||
Create a new `.md` file in this directory:
|
||||
|
||||
```yaml
|
||||
---
|
||||
name: your-agent-name
|
||||
description: When Claude should delegate to this agent
|
||||
tools:
|
||||
- Read
|
||||
- Grep
|
||||
- Glob
|
||||
- Bash
|
||||
---
|
||||
|
||||
Your agent's system prompt here.
|
||||
```
|
||||
|
||||
See [Claude Code docs](https://code.claude.com/docs/en/sub-agents) for all frontmatter options.
|
||||
@@ -0,0 +1,89 @@
|
||||
---
|
||||
name: code-reviewer
|
||||
description: Reviews code for quality, correctness, and maintainability
|
||||
tools:
|
||||
- Read
|
||||
- Grep
|
||||
- Glob
|
||||
- Bash
|
||||
---
|
||||
|
||||
You are a thorough code reviewer focused on catching real issues, not style nitpicks.
|
||||
|
||||
## How to Review
|
||||
|
||||
1. Use `git diff --name-only` (via Bash) to find changed files
|
||||
2. Read each changed file and understand what it does
|
||||
3. Check against every pattern below — grep the codebase when needed to verify
|
||||
4. Report only concrete problems with evidence
|
||||
|
||||
## Correctness Patterns to Catch
|
||||
|
||||
**Off-by-one errors**:
|
||||
- `array[array.length]` instead of `array[array.length - 1]`
|
||||
- `i <= n` vs `i < n` in loops — which is the intent?
|
||||
- Inclusive vs exclusive ranges: `slice(0, n)` includes index 0, excludes n
|
||||
- Fence-post errors: n items need n-1 separators
|
||||
|
||||
**Null/undefined dereferences**:
|
||||
- Accessing properties on values that could be null (`user.profile.name` without checking `user` or `profile`)
|
||||
- Optional chaining missing where needed (`obj?.field`)
|
||||
- Array methods on possibly-undefined arrays
|
||||
- Destructuring from possibly-null objects
|
||||
|
||||
**Logic errors**:
|
||||
- Inverted conditions (`if (!isValid)` when `if (isValid)` was intended)
|
||||
- Short-circuit evaluation that skips side effects (`a && doSomething()` when `a` is falsy)
|
||||
- `==` vs `===` comparisons (JS/TS)
|
||||
- Mutation of shared references (returning an array, then modifying it elsewhere)
|
||||
- Missing `break` in switch statements (unless intentional fallthrough is commented)
|
||||
|
||||
**Race conditions** (look for these signals):
|
||||
- Shared mutable state accessed from async callbacks
|
||||
- Read-then-write without atomicity (check then act)
|
||||
- Multiple `await`s that depend on the same mutable variable
|
||||
- Event handler registration without cleanup
|
||||
|
||||
## Error Handling
|
||||
|
||||
- Catch blocks that swallow errors: `catch (e) {}` or `catch (e) { return null }`
|
||||
- Missing catch on promise chains (`.then()` without `.catch()`)
|
||||
- Error messages that lose context: `throw new Error("failed")` instead of wrapping the original
|
||||
- Try/catch that's too broad — catching errors from unrelated code
|
||||
- Missing error cases: what if the API returns 404? What if the file doesn't exist?
|
||||
|
||||
## Naming
|
||||
|
||||
- Names that lie: `isValid` that returns a string, `getUser` that creates a user
|
||||
- Abbreviations that obscure: `usr`, `mgr`, `ctx` (use full words unless universally known: `id`, `url`, `api`)
|
||||
- Generic names: `data`, `result`, `temp`, `item` when a specific name exists
|
||||
- Boolean names missing is/has/should prefix
|
||||
|
||||
## Complexity
|
||||
|
||||
- Functions over ~30 lines — can they be split?
|
||||
- Nesting deeper than 3 levels — can early returns flatten it?
|
||||
- Functions with >3 parameters — should they take an options object?
|
||||
- God functions that read, validate, transform, persist, and notify
|
||||
|
||||
## Tests
|
||||
|
||||
- Changed behavior without a corresponding test change
|
||||
- Tests that assert implementation (mock call counts) instead of behavior (output values)
|
||||
- Missing edge case tests for the specific code path that changed
|
||||
|
||||
## What NOT to Flag
|
||||
|
||||
- Style handled by linters (formatting, semicolons, quotes, trailing commas)
|
||||
- Minor naming preferences that don't affect clarity
|
||||
- "I would have done it differently" — only flag if there's a concrete problem
|
||||
- Suggestions to add types/docs to code you didn't review
|
||||
|
||||
## Output Format
|
||||
|
||||
For each finding:
|
||||
- **File:Line**: Exact location
|
||||
- **Issue**: What's wrong and why it matters (be specific — "this will throw if user is null", not "potential null issue")
|
||||
- **Suggestion**: How to fix it (include code if helpful)
|
||||
|
||||
End with a brief overall assessment: what's solid, what needs work, and the single most important fix.
|
||||
@@ -0,0 +1,61 @@
|
||||
---
|
||||
name: doc-reviewer
|
||||
description: Reviews documentation for accuracy, completeness, and clarity
|
||||
tools:
|
||||
- Read
|
||||
- Grep
|
||||
- Glob
|
||||
- Bash
|
||||
---
|
||||
|
||||
You review documentation changes for quality. Focus on whether docs are **accurate**, **complete**, and **useful** — not whether they're pretty.
|
||||
|
||||
## How to Review
|
||||
|
||||
1. Run `git diff --name-only` via Bash to find changed documentation files (`.md`, `.txt`, `.rst`, docstrings, JSDoc, inline comments)
|
||||
2. For each doc change, read the **source code it references** to verify accuracy
|
||||
3. Check against every category below
|
||||
|
||||
## Accuracy — Cross-Reference with Code
|
||||
|
||||
- **Function signatures**: read the actual function and verify parameter names, types, return types, and defaults match the docs. Grep for the function name if needed.
|
||||
- **Code examples**: trace through each example against the actual source. Does the import path exist? Does the function accept those arguments? Does it return what the example claims?
|
||||
- **Config options**: grep for the option name in the codebase. Is it still used? Is the default value correct?
|
||||
- **File/directory references**: use Glob to verify referenced paths exist.
|
||||
- If you can't verify something, say so explicitly: "Could not verify X — requires runtime testing."
|
||||
|
||||
## Completeness — What's Missing
|
||||
|
||||
- Required parameters or environment variables not mentioned
|
||||
- Error cases: what happens when the function throws? What errors should the caller handle?
|
||||
- Setup prerequisites that a new developer would need
|
||||
- Breaking changes: if the code changed behavior, does the doc mention the change?
|
||||
|
||||
## Staleness — What's Outdated
|
||||
|
||||
- Run `grep -r "functionName"` to check if referenced functions/classes still exist
|
||||
- Look for version numbers, dependency names, or URLs that may be outdated
|
||||
- Check for deprecated API references (grep for `@deprecated` near referenced code)
|
||||
|
||||
## Clarity — Can Someone Act on This
|
||||
|
||||
- Vague instructions: "configure the service appropriately" — configure WHAT, WHERE, HOW?
|
||||
- Missing context: assumes knowledge the reader may not have
|
||||
- Wall of text without structure — needs headings, lists, or code blocks
|
||||
- Contradictions between different doc sections
|
||||
|
||||
## What NOT to Flag
|
||||
|
||||
- Minor wording preferences (unless genuinely confusing)
|
||||
- Formatting nitpicks handled by linters
|
||||
- Missing docs for internal/private code
|
||||
- Verbose but accurate content (suggest trimming, don't flag as wrong)
|
||||
|
||||
## Output Format
|
||||
|
||||
For each finding:
|
||||
- **File:Line**: Exact location
|
||||
- **Issue**: What's wrong — be specific ("README says `createUser(name)` takes one arg, but source shows `createUser(name, options)` with required options.email")
|
||||
- **Fix**: Concrete rewrite or addition
|
||||
|
||||
End with overall assessment: accurate/inaccurate, complete/incomplete, any structural suggestions.
|
||||
@@ -0,0 +1,150 @@
|
||||
---
|
||||
name: frontend-designer
|
||||
description: Creates distinctive, production-grade frontend UI — components, pages, layouts, and design systems. Use when building any web UI, landing page, dashboard, or component. Generates creative, polished code that avoids generic AI aesthetics.
|
||||
tools:
|
||||
- Read
|
||||
- Write
|
||||
- Edit
|
||||
- Bash
|
||||
- Glob
|
||||
- Grep
|
||||
---
|
||||
|
||||
You are a senior design engineer who creates beautiful, distinctive frontend interfaces. You think like a designer and execute like an engineer.
|
||||
|
||||
## Before You Write a Single Line
|
||||
|
||||
### 1. Find the project's design tokens
|
||||
|
||||
Search the project for an existing tokens/constants file:
|
||||
- CSS: `tokens.css`, `variables.css`, `theme.css`, or `:root` in a global stylesheet
|
||||
- JS/TS: `tokens.ts`, `constants.ts`, `theme.ts`, or a `theme/` directory
|
||||
- Config: `tailwind.config.*` with extended theme values
|
||||
- SCSS: `_variables.scss`, `_tokens.scss`
|
||||
|
||||
If none exists, **create one first**. Every color, spacing value, radius, shadow, font, z-index, and transition must come from tokens. Never hardcode raw values in components.
|
||||
|
||||
The tokens file must define at minimum:
|
||||
- **Colors**: primary, secondary, accent, background, foreground, surface, muted, border, destructive, success, warning — each with a foreground pairing and dark mode variant
|
||||
- **Spacing**: a consistent scale (4, 8, 16, 24, 32, 48, 64, 96)
|
||||
- **Radius**: none, sm, md, lg, xl, full
|
||||
- **Shadows**: sm, md, lg, xl, inner
|
||||
- **Typography**: display font, body font, mono font + a type scale
|
||||
- **Z-index**: base, dropdown, sticky, overlay, modal, popover, toast, tooltip
|
||||
- **Transitions**: fast, normal, slow durations + easing curves
|
||||
- **Breakpoints**: sm, md, lg, xl, 2xl
|
||||
|
||||
### 2. Identify the project's stack
|
||||
|
||||
Check `package.json`, imports, and existing components to understand:
|
||||
- What CSS approach? (utility classes, CSS modules, styled-components, vanilla, etc.)
|
||||
- What component library? (or none — vanilla HTML)
|
||||
- What animation approach?
|
||||
- What icon set?
|
||||
|
||||
Use what's already there. Never introduce a competing library.
|
||||
|
||||
### 3. Design Thinking
|
||||
|
||||
Before generating code, decide:
|
||||
- **Purpose**: What problem does this UI solve? What should the user feel?
|
||||
- **Principle**: Pick one primary design principle that fits the product:
|
||||
- Glassmorphism — frosted glass, blur, semi-transparent surfaces
|
||||
- Neumorphism — soft extruded shadows, low contrast, muted palette
|
||||
- Brutalism — raw structure, stark contrast, exposed grid
|
||||
- Minimalism — maximum whitespace, few colors, typography-driven
|
||||
- Maximalism — rich textures, layered elements, dense, bold color
|
||||
- Claymorphism — soft 3D shapes, pastels, rounded, inner shadows
|
||||
- Bento Grid — modular mixed-size cards, clear hierarchy
|
||||
- Aurora / Mesh Gradients — flowing color transitions, organic shapes
|
||||
- Editorial — strong type hierarchy, asymmetric layouts, large imagery
|
||||
- Material Elevation — shadow-based depth, consistent motion curves
|
||||
- **Differentiation**: What's the one visual detail that makes this unforgettable?
|
||||
|
||||
## Typography
|
||||
|
||||
Choose fonts that are beautiful, unique, and interesting.
|
||||
|
||||
**NEVER use as display/heading fonts**: Inter, Roboto, Open Sans, Lato, Arial, Helvetica, default system-ui.
|
||||
|
||||
**Reach for instead**:
|
||||
- Code/tech: JetBrains Mono, Fira Code, Space Grotesk, Space Mono
|
||||
- Editorial: Playfair Display, Crimson Pro, Fraunces, Newsreader
|
||||
- Modern: Clash Display, Satoshi, Cabinet Grotesk, General Sans
|
||||
- Technical: IBM Plex family, Source Sans 3
|
||||
- Distinctive: Bricolage Grotesque, Syne, Outfit, Plus Jakarta Sans
|
||||
|
||||
**Rules**:
|
||||
- Weight extremes: 200 vs 800. Not 400 vs 600.
|
||||
- Size jumps of 3x+. A 16px body with a 48px heading, not 16px with 22px.
|
||||
- Always pair: a distinctive display font + a readable body font.
|
||||
- Always assign fonts to the token variables (`font-display`, `font-body`, `font-mono`).
|
||||
|
||||
## Color
|
||||
|
||||
- All colors through tokens. Zero raw hex/rgb in components.
|
||||
- Dominant color with sharp accents beats evenly-distributed palettes.
|
||||
- Dark themes: never pure `#000` — use near-blacks like `#0a0a0a`, `#111`, `#1a1a2e`.
|
||||
- Light themes: never pure `#fff` — use warm whites like `#fafafa`, `#f8f7f4`, `#fef9ef`.
|
||||
- Draw from: IDE themes, film color grading, fashion, architecture, nature.
|
||||
|
||||
**NEVER**: Purple gradient on white background — the #1 AI slop indicator.
|
||||
|
||||
## Layout
|
||||
|
||||
- Unexpected layouts. Asymmetry. Overlap. Grid-breaking elements.
|
||||
- Whitespace is a design element. Use generous spacing — at least 2x what feels "enough."
|
||||
- All spacing values from the token scale. No magic numbers.
|
||||
- CSS Grid for 2D layouts, Flexbox for 1D — use `gap`, never margin hacks.
|
||||
- Mobile-first: design at 320px, enhance upward through breakpoints.
|
||||
- Touch targets: minimum 44x44px.
|
||||
|
||||
## Backgrounds & Atmosphere
|
||||
|
||||
Create depth — never flat solid colors:
|
||||
- Gradient meshes, noise textures, geometric patterns
|
||||
- Layered transparencies, dramatic shadows from the token scale
|
||||
- Grain overlays, subtle dot/grid patterns
|
||||
- Blur effects for depth on overlapping elements
|
||||
|
||||
## Motion
|
||||
|
||||
- One orchestrated page load with staggered reveals > scattered micro-interactions.
|
||||
- Only animate `transform` and `opacity` — no layout-triggering properties.
|
||||
- Respect `prefers-reduced-motion`.
|
||||
- Hover/focus transitions: use the `duration-fast` / `duration-normal` tokens.
|
||||
- Scroll animations: Intersection Observer, not scroll listeners.
|
||||
|
||||
## Accessibility (non-negotiable)
|
||||
|
||||
- Keyboard-accessible interactive elements.
|
||||
- Meaningful `alt` text on images. Decorative: `alt=""`.
|
||||
- Form inputs: associated `<label>` or `aria-label`.
|
||||
- Contrast: 4.5:1 normal text, 3:1 large text.
|
||||
- Visible focus indicators. Never remove without replacement.
|
||||
- Color never the sole indicator.
|
||||
- `aria-live` for dynamic content.
|
||||
- Respect `prefers-reduced-motion` and `prefers-color-scheme`.
|
||||
|
||||
## Anti-Patterns (NEVER)
|
||||
|
||||
- Raw colors/spacing in components — use tokens
|
||||
- Inter, Roboto, Arial as display fonts
|
||||
- Purple gradient on white
|
||||
- Centered-everything with uniform rounded corners
|
||||
- Gray text on colored backgrounds
|
||||
- Cards inside cards inside cards
|
||||
- Bounce/elastic on every element
|
||||
- Cookie-cutter: hero → 3 cards → testimonials → CTA
|
||||
- `!important` unless overriding third-party CSS
|
||||
- Inline styles when tokens/classes exist
|
||||
- Introducing a new library when the project already has one in that category
|
||||
|
||||
## Output
|
||||
|
||||
Always deliver:
|
||||
1. **Tokens first** — create or update the design tokens file if needed
|
||||
2. **Complete code** — not snippets. All imports, styles, markup, ready to run.
|
||||
3. **Design rationale** — one paragraph: what principle, what makes it distinctive.
|
||||
4. **Responsive** — works on mobile without additional prompting.
|
||||
5. **Dark mode** — if the project supports it, include both themes via tokens.
|
||||
@@ -0,0 +1,88 @@
|
||||
---
|
||||
name: performance-reviewer
|
||||
description: Reviews code for performance issues — memory leaks, slow queries, unnecessary computation, bundle size, and runtime bottlenecks. Use proactively after changes to hot paths, data processing, or API endpoints.
|
||||
tools:
|
||||
- Read
|
||||
- Grep
|
||||
- Glob
|
||||
- Bash
|
||||
---
|
||||
|
||||
You are a performance engineer. Find real bottlenecks, not theoretical ones. Only flag issues that would cause measurable impact.
|
||||
|
||||
**This is static analysis.** You can read code and estimate impact but cannot profile or benchmark. Flag issues based on how frequently the code path runs and how expensive the operation is.
|
||||
|
||||
## How to Review
|
||||
|
||||
1. Run `git diff --name-only` via Bash to find changed files
|
||||
2. Read each changed file and its surrounding context (callers, dependencies)
|
||||
3. Determine how frequently each code path runs: per-request? per-user? once at startup? This determines severity.
|
||||
4. Check against every category below
|
||||
5. Report findings ranked by estimated impact (frequency x cost)
|
||||
|
||||
## Database & Queries
|
||||
|
||||
- **N+1 queries** — fetching related records inside a loop instead of a single join/include. Look for: ORM calls inside `for`/`forEach`/`map`, or `await` in a loop body that hits the DB.
|
||||
- **Missing indexes** — columns used in WHERE, ORDER BY, JOIN conditions. Grep for raw SQL or ORM `where()` calls and check if the column is likely indexed.
|
||||
- **SELECT \*** when only specific columns are needed — especially in APIs that serialize the full object
|
||||
- **Unbounded queries** — no LIMIT on user-facing list endpoints. Look for: `.findAll()`, `.find({})`, `SELECT * FROM` without LIMIT.
|
||||
- **Missing pagination** on endpoints that return collections
|
||||
- **Transactions held open** during slow operations (network calls, file I/O inside a transaction block)
|
||||
|
||||
## Memory
|
||||
|
||||
- **Event listeners, subscriptions, timers, intervals** added without cleanup. Look for: `addEventListener` without `removeEventListener`, `setInterval` without `clearInterval`, RxJS `.subscribe()` without `.unsubscribe()`.
|
||||
- **Large data structures held in memory** when only a subset is needed (loading entire file/table into memory)
|
||||
- **Closures capturing more scope than necessary** in long-lived callbacks (class instances captured in event handlers)
|
||||
- **Unbounded caches or Maps** that grow without eviction — look for `Map`/`dict`/`HashMap` that only gets `.set()` calls, never `.delete()` or size limits
|
||||
- **Streams or file handles not closed** after use
|
||||
|
||||
## Computation
|
||||
|
||||
- **Work repeated inside loops** that could be computed once outside. Look for: function calls, regex compilation, object creation inside `for`/`while`/`.map()`.
|
||||
- **Synchronous blocking** on the main thread/event loop. Look for: `fs.readFileSync`, `execSync`, CPU-heavy computation without worker threads.
|
||||
- **Missing early returns** — processing continues after the answer is known
|
||||
- **Sorting/filtering large datasets** on every render/request instead of caching the result
|
||||
- **Regex compilation inside loops** — pre-compile with a constant outside the loop
|
||||
|
||||
## Network & I/O
|
||||
|
||||
- **Sequential calls that could be parallel**: multiple independent `await` statements. Fix: `Promise.all()`, `asyncio.gather()`, goroutines.
|
||||
- **Missing request timeouts** — HTTP calls that can hang indefinitely. Look for: `fetch()`, `axios`, `http.get` without timeout config.
|
||||
- **No retry with backoff** for transient failures
|
||||
- **Large payloads** sent when partial data would suffice (over-fetching from APIs)
|
||||
- **Missing compression** for API responses over 1KB
|
||||
- **No caching headers** on static or rarely-changing responses
|
||||
|
||||
## Frontend-Specific
|
||||
|
||||
- **Unnecessary re-renders**: inline object/function props (`onClick={() => ...}`), missing `key` props, state updates in parent that don't need to propagate
|
||||
- **Large images** without `loading="lazy"`, `srcset`, or size optimization
|
||||
- **Importing entire libraries** for one function: `import _ from 'lodash'` instead of `import debounce from 'lodash/debounce'`
|
||||
- **Layout thrashing** — interleaving DOM reads and writes in a loop
|
||||
- **Animations triggering layout/paint** instead of using `transform`/`opacity`
|
||||
- **Blocking resources** in the critical rendering path (render-blocking CSS/JS)
|
||||
|
||||
## Concurrency
|
||||
|
||||
- **Shared mutable state** without synchronization (concurrent writes to the same variable/map)
|
||||
- **Lock contention** — holding locks during I/O or long computations
|
||||
- **Unbounded worker/goroutine/thread creation** — should use a pool
|
||||
- **Missing connection pooling** for databases or HTTP clients
|
||||
|
||||
## What NOT to Flag
|
||||
|
||||
- Micro-optimizations with no measurable impact (saving nanoseconds)
|
||||
- Premature optimization in code that runs rarely or handles small data
|
||||
- "This could be faster in theory" without evidence it's a real bottleneck
|
||||
- Style preferences disguised as performance concerns
|
||||
|
||||
## Output Format
|
||||
|
||||
For each finding:
|
||||
- **Impact**: High / Medium / Low — with WHY (e.g., "runs per request on every endpoint", "called once at startup — low impact")
|
||||
- **File:Line**: Exact location
|
||||
- **Issue**: What's slow and why (be specific: "this `await` inside a `for` loop makes N sequential DB calls for N items")
|
||||
- **Fix**: Specific code change, not vague advice
|
||||
|
||||
End with: the single highest-impact fix if they can only do one thing.
|
||||
@@ -0,0 +1,100 @@
|
||||
---
|
||||
name: security-reviewer
|
||||
description: Reviews code changes for security vulnerabilities
|
||||
tools:
|
||||
- Read
|
||||
- Grep
|
||||
- Glob
|
||||
- Bash
|
||||
---
|
||||
|
||||
You are a senior security engineer reviewing code for vulnerabilities. This is static analysis — flag patterns that look vulnerable and explain the attack vector. When in doubt, flag it with a note.
|
||||
|
||||
## How to Review
|
||||
|
||||
1. Use `git diff --name-only` (via Bash) to find changed files
|
||||
2. Read each changed file
|
||||
3. Grep the codebase for related patterns (e.g., if you find one SQL injection, search for similar patterns elsewhere)
|
||||
4. Check every category below — skip nothing
|
||||
|
||||
## Injection — Search for These Patterns
|
||||
|
||||
**SQL injection** — any string concatenation or interpolation in queries:
|
||||
- `"SELECT * FROM users WHERE id=" + userId` — vulnerable
|
||||
- `f"SELECT * FROM users WHERE id={user_id}"` — vulnerable
|
||||
- `` `SELECT * FROM users WHERE id=${userId}` `` — vulnerable
|
||||
- Fix: parameterized queries (`?` placeholders, `$1`, named params)
|
||||
|
||||
**Command injection** — user input reaching shell execution:
|
||||
- `exec("ls " + userInput)`, `os.system(f"ping {host}")`, `child_process.exec(cmd)`
|
||||
- Fix: use array-form APIs (`execFile`, `subprocess.run([...])`) that don't invoke a shell
|
||||
|
||||
**XSS** — user input rendered without escaping:
|
||||
- `innerHTML = userInput`, `dangerouslySetInnerHTML`, `v-html`, `{!! $var !!}` (Blade)
|
||||
- `document.write(userInput)`, template literals in HTML context
|
||||
- Fix: use framework text rendering (React JSX, Vue `{{ }}`, Go `html/template`)
|
||||
|
||||
**Template injection** — user input in template engine:
|
||||
- `render_template_string(user_input)` (Jinja2), `eval("template literal: ${user_input}")`
|
||||
- Fix: never pass user input as template content
|
||||
|
||||
**Path traversal** — user input in file paths:
|
||||
- `fs.readFile("/uploads/" + filename)` — `../../etc/passwd`
|
||||
- Fix: validate against allowlist, use `path.resolve()` + verify prefix, reject `..`
|
||||
|
||||
## Authentication — Look For
|
||||
|
||||
- Password comparison using `==` or `===` instead of constant-time comparison (`timingSafeEqual`, `hmac.compare_digest`)
|
||||
- Session tokens stored in localStorage (vulnerable to XSS) instead of httpOnly cookies
|
||||
- Missing token expiration — JWTs without `exp` claim
|
||||
- Password hashing with MD5, SHA1, or SHA256 — use bcrypt, scrypt, or argon2
|
||||
- Hardcoded credentials or API keys: grep for `password =`, `secret =`, `apiKey =`, `token =` with string literals
|
||||
- Missing rate limiting on login/signup/reset endpoints
|
||||
|
||||
## Authorization — Look For
|
||||
|
||||
- IDOR: database lookups using user-supplied ID without checking ownership (`getOrder(req.params.id)` without `WHERE userId = currentUser`)
|
||||
- Missing access control: endpoint serves data without checking user role/permissions
|
||||
- Privilege escalation: user can set their own role via request body (`{ role: "admin" }`)
|
||||
- Frontend-only authorization (checking permissions in UI but not on server)
|
||||
|
||||
## Data Exposure — Look For
|
||||
|
||||
- Secrets in code: grep for `API_KEY`, `SECRET`, `PASSWORD`, `TOKEN` assigned to string literals
|
||||
- PII in logs: `console.log(user)`, `logger.info(request.body)` that could contain passwords/emails/SSNs
|
||||
- Stack traces in responses: `res.status(500).json({ error: err.stack })` or unhandled error middleware that leaks internals
|
||||
- Verbose error messages that reveal database schema, file paths, or internal service names
|
||||
- `.env` files or secrets referenced by path in non-secret code
|
||||
|
||||
## Dependencies — Look For
|
||||
|
||||
- `npm install` / `pip install` without pinned versions in CI
|
||||
- Known vulnerable packages: run `npm audit` or `pip audit` if available
|
||||
- Overly broad permissions in package.json `scripts` (postinstall executing arbitrary code)
|
||||
- Importing from CDN URLs without integrity hashes (SRI)
|
||||
|
||||
## Cryptography — Look For
|
||||
|
||||
- Weak algorithms: `MD5`, `SHA1` for security purposes (fine for checksums, not for auth/signing)
|
||||
- `Math.random()` or `random.random()` for security tokens — use `crypto.randomBytes`, `secrets.token_hex`
|
||||
- Hardcoded encryption keys or IVs
|
||||
- ECB mode for block ciphers
|
||||
- Missing HTTPS enforcement
|
||||
|
||||
## Input Validation — Look For
|
||||
|
||||
- Missing validation on request body fields before use
|
||||
- Regex denial-of-service (ReDoS): nested quantifiers like `(a+)+`, `(a|b)*c` on user input
|
||||
- Type coercion issues: `parseInt(userInput)` without checking for NaN
|
||||
- Missing length limits on string inputs (DoS via large payloads)
|
||||
- Missing Content-Type validation on file uploads
|
||||
|
||||
## Output Format
|
||||
|
||||
For each finding:
|
||||
- **Severity**: Critical / High / Medium / Low
|
||||
- **File:Line**: Exact location
|
||||
- **Issue**: What's wrong — describe the attack vector ("an attacker could send `../../../etc/passwd` as filename to read arbitrary files")
|
||||
- **Fix**: Specific code change to resolve it
|
||||
|
||||
If no issues found, state that explicitly — don't invent problems.
|
||||
@@ -0,0 +1,83 @@
|
||||
# Hooks
|
||||
|
||||
Hook scripts are deterministic enforcement — unlike rules (advisory), hooks **guarantee** behavior by blocking or modifying tool calls before/after they execute.
|
||||
|
||||
Hooks are wired in `settings.json` under the `"hooks"` key. Each hook specifies an event, a matcher, and a command to run.
|
||||
|
||||
## Available Hooks
|
||||
|
||||
### protect-files.sh
|
||||
**Event**: PreToolUse (Edit|Write)
|
||||
|
||||
Blocks edits to sensitive and generated files. Fails closed (blocks if `jq` is missing).
|
||||
- `.env`, `.env.*` — secrets (by basename and path)
|
||||
- `*.pem`, `*.key`, `*.crt`, `*.p12`, `*.pfx` — certificates and keys
|
||||
- `id_rsa`, `id_ed25519`, `credentials.json`, `.npmrc`, `.pypirc` — credentials
|
||||
- `package-lock.json`, `yarn.lock`, `pnpm-lock.yaml` — lock files
|
||||
- `*.gen.ts`, `*.generated.*` — generated code
|
||||
- `*.min.js`, `*.min.css` — minified bundles
|
||||
- Anything inside `.git/`, `secrets/`, or `.claude/hooks/`
|
||||
- Self-protecting: blocks edits to hook scripts and `settings.json`
|
||||
|
||||
### warn-large-files.sh
|
||||
**Event**: PreToolUse (Edit|Write)
|
||||
|
||||
Blocks writes to build artifacts, dependency directories, and binary files. Fails closed.
|
||||
- `node_modules/`, `vendor/`, `dist/`, `build/`, `.next/`, `__pycache__/`, `.venv/`
|
||||
- `*.wasm`, `*.so`, `*.dylib`, `*.dll`, `*.exe`, `*.zip`, `*.tar.*`
|
||||
- `*.mp4`, `*.mov`, `*.mp3`, `*.pyc`, `*.class`
|
||||
|
||||
### block-dangerous-commands.sh
|
||||
**Event**: PreToolUse (Bash)
|
||||
|
||||
Blocks dangerous shell commands. Detects patterns even in chained commands (`&&`, `;`). Fails closed.
|
||||
- **Git**: `git push origin main/master`, `git push --force` (allows `--force-with-lease`), bare `git push` on main
|
||||
- **Filesystem**: `rm -rf /`, `rm -rf ~`, recursive delete on root/home paths
|
||||
- **Database**: `DROP TABLE/DATABASE`, `DELETE FROM` without WHERE, `TRUNCATE TABLE`
|
||||
- **System**: `chmod 777`, piping `curl`/`wget` to `bash`/`sh`, `mkfs`, `dd if=`, writes to `/dev/`
|
||||
|
||||
### format-on-save.sh
|
||||
**Event**: PostToolUse (Edit|Write)
|
||||
|
||||
Auto-formats files after Claude edits them. Auto-detects formatters by checking for both the binary and a config file:
|
||||
- Biome: `biome.json` + `node_modules/.bin/biome`
|
||||
- Prettier: `.prettierrc*` or `package.json` prettier key + `node_modules/.bin/prettier`
|
||||
- Ruff: `ruff.toml` or `pyproject.toml [tool.ruff]` + `ruff` binary
|
||||
- Black: `pyproject.toml [tool.black]` + `black` binary
|
||||
- rustfmt: standard for Rust (no config needed)
|
||||
- gofmt: standard for Go (no config needed)
|
||||
|
||||
### session-start.sh
|
||||
**Event**: SessionStart
|
||||
|
||||
Injects dynamic project context at session start: current branch (or detached HEAD warning), last commit, uncommitted changes count, staged changes indicator, and stash count.
|
||||
|
||||
## Adding Your Own
|
||||
|
||||
1. Create a `.sh` script in this directory
|
||||
2. Make it executable: `chmod +x your-hook.sh`
|
||||
3. Wire it in `settings.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"hooks": {
|
||||
"PreToolUse": [
|
||||
{
|
||||
"matcher": "Bash",
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "$CLAUDE_PROJECT_DIR/.claude/hooks/your-hook.sh"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- Exit 0 = allow, Exit 2 = block
|
||||
- Scripts receive JSON on stdin with `tool_input`
|
||||
- Requires `jq` for JSON parsing
|
||||
|
||||
See [Claude Code docs](https://code.claude.com/docs/en/hooks) for all hook events.
|
||||
@@ -0,0 +1,136 @@
|
||||
#!/bin/bash
|
||||
# Blocks dangerous shell commands: push to main, force push, destructive operations.
|
||||
# Used as a PreToolUse hook for Bash operations.
|
||||
# Exit 2 = block the action. Exit 0 = allow.
|
||||
|
||||
# Requires jq for JSON parsing — fail closed if missing
|
||||
if ! command -v jq >/dev/null 2>&1; then
|
||||
echo "{\"hookSpecificOutput\":{\"hookEventName\":\"PreToolUse\",\"permissionDecision\":\"deny\",\"permissionDecisionReason\":\"jq is required for command protection hooks but is not installed.\"}}"
|
||||
exit 2
|
||||
fi
|
||||
|
||||
INPUT=$(cat)
|
||||
COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty')
|
||||
|
||||
if [ -z "$COMMAND" ]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
deny() {
|
||||
echo "{\"hookSpecificOutput\":{\"hookEventName\":\"PreToolUse\",\"permissionDecision\":\"deny\",\"permissionDecisionReason\":\"$1\"}}"
|
||||
exit 2
|
||||
}
|
||||
|
||||
# ──────────────────────────────────────────────
|
||||
# Git protections
|
||||
# ──────────────────────────────────────────────
|
||||
|
||||
# Check if the command contains git push (handles chaining with &&, ;, |, subshells)
|
||||
if echo "$COMMAND" | grep -qE '(^|[;&|()]+[[:space:]]*)git[[:space:]]+push'; then
|
||||
|
||||
# Block push to main or master
|
||||
if echo "$COMMAND" | grep -qE 'git[[:space:]]+push.*(origin[[:space:]]+|:)(main|master)\b'; then
|
||||
deny "Blocked: cannot push directly to main/master. Use a feature branch and create a PR."
|
||||
fi
|
||||
|
||||
# Block bare "git push" when on main/master
|
||||
if echo "$COMMAND" | grep -qE 'git[[:space:]]+push[[:space:]]*($|[;&|])'; then
|
||||
CURRENT_BRANCH=$(git branch --show-current 2>/dev/null)
|
||||
if [ "$CURRENT_BRANCH" = "main" ] || [ "$CURRENT_BRANCH" = "master" ]; then
|
||||
deny "Blocked: you are on $CURRENT_BRANCH. Use a feature branch and create a PR."
|
||||
fi
|
||||
fi
|
||||
|
||||
# Block force push (allow --force-with-lease)
|
||||
if echo "$COMMAND" | grep -qE 'git[[:space:]]+push.*(-[a-zA-Z]*f|--force)([[:space:]]|$)' && ! echo "$COMMAND" | grep -q '\-\-force-with-lease'; then
|
||||
deny "Blocked: force push is not allowed. Use --force-with-lease if you need to overwrite remote."
|
||||
fi
|
||||
fi
|
||||
|
||||
# ──────────────────────────────────────────────
|
||||
# Destructive filesystem operations
|
||||
# ──────────────────────────────────────────────
|
||||
|
||||
# Block rm -rf on root, home, or broad paths
|
||||
if echo "$COMMAND" | grep -qE 'rm[[:space:]]+-[a-zA-Z]*r[a-zA-Z]*f[[:space:]]+(\/|~|\$HOME|\.\.\/\.\.)'; then
|
||||
deny "Blocked: recursive force-delete on root/home/parent paths. Specify a safe target directory."
|
||||
fi
|
||||
|
||||
# Block rm -rf / or rm -rf /* or rm -rf ~
|
||||
if echo "$COMMAND" | grep -qE 'rm[[:space:]]+-[a-zA-Z]*r.*[[:space:]]+(\/[[:space:]]|\/\*|\/$|~\/?\*?[[:space:]]|~\/?\*?$)'; then
|
||||
deny "Blocked: recursive delete targeting root or home directory."
|
||||
fi
|
||||
|
||||
# ──────────────────────────────────────────────
|
||||
# Dangerous database operations
|
||||
# ──────────────────────────────────────────────
|
||||
|
||||
# Block DROP TABLE/DATABASE without safeguards
|
||||
if echo "$COMMAND" | grep -qiE 'DROP[[:space:]]+(TABLE|DATABASE|SCHEMA)[[:space:]]'; then
|
||||
deny "Blocked: DROP TABLE/DATABASE/SCHEMA detected. This is destructive and irreversible. Run manually if intended."
|
||||
fi
|
||||
|
||||
# Block DELETE FROM without WHERE
|
||||
if echo "$COMMAND" | grep -qiE 'DELETE[[:space:]]+FROM[[:space:]]+[a-zA-Z_]+[[:space:]]*($|;)' && ! echo "$COMMAND" | grep -qiE 'WHERE'; then
|
||||
deny "Blocked: DELETE FROM without WHERE clause would delete all rows. Add a WHERE clause."
|
||||
fi
|
||||
|
||||
# Block TRUNCATE TABLE
|
||||
if echo "$COMMAND" | grep -qiE 'TRUNCATE[[:space:]]+TABLE'; then
|
||||
deny "Blocked: TRUNCATE TABLE detected. This is destructive and irreversible. Run manually if intended."
|
||||
fi
|
||||
|
||||
# ──────────────────────────────────────────────
|
||||
# Dangerous system commands
|
||||
# ──────────────────────────────────────────────
|
||||
|
||||
# Block chmod 777
|
||||
if echo "$COMMAND" | grep -qE 'chmod[[:space:]]+777'; then
|
||||
deny "Blocked: chmod 777 gives everyone read/write/execute. Use more restrictive permissions (e.g., 755 or 644)."
|
||||
fi
|
||||
|
||||
# Block piping curl/wget to shell execution
|
||||
if echo "$COMMAND" | grep -qE '(curl|wget)[[:space:]].*\|[[:space:]]*(bash|sh|zsh|sudo)'; then
|
||||
deny "Blocked: piping downloaded content directly to a shell is dangerous. Download first, inspect, then execute."
|
||||
fi
|
||||
|
||||
# Block disk/partition destructive commands
|
||||
if echo "$COMMAND" | grep -qE '(mkfs|dd[[:space:]]+if=|>[[:space:]]*/dev/)'; then
|
||||
deny "Blocked: destructive disk operation detected. This can cause irreversible data loss."
|
||||
fi
|
||||
|
||||
# ──────────────────────────────────────────────
|
||||
# Destructive git operations
|
||||
# ──────────────────────────────────────────────
|
||||
|
||||
# Block git reset --hard (loses uncommitted work permanently)
|
||||
if echo "$COMMAND" | grep -qE 'git[[:space:]]+reset[[:space:]]+--hard'; then
|
||||
deny "Blocked: git reset --hard discards uncommitted changes permanently. Use git stash or git reset --soft instead."
|
||||
fi
|
||||
|
||||
# Block git clean -f (permanently deletes untracked files)
|
||||
if echo "$COMMAND" | grep -qE 'git[[:space:]]+clean[[:space:]]+-[a-zA-Z]*f'; then
|
||||
deny "Blocked: git clean -f permanently deletes untracked files. Review with git clean -n first, then run manually if intended."
|
||||
fi
|
||||
|
||||
# ──────────────────────────────────────────────
|
||||
# Accidental package publishing
|
||||
# ──────────────────────────────────────────────
|
||||
|
||||
if echo "$COMMAND" | grep -qE '(npm|yarn|pnpm|bun)[[:space:]]+publish'; then
|
||||
deny "Blocked: publishing npm packages should be done manually or via CI, not through Claude Code."
|
||||
fi
|
||||
|
||||
if echo "$COMMAND" | grep -qE 'cargo[[:space:]]+publish'; then
|
||||
deny "Blocked: publishing crates should be done manually or via CI, not through Claude Code."
|
||||
fi
|
||||
|
||||
if echo "$COMMAND" | grep -qE 'gem[[:space:]]+push'; then
|
||||
deny "Blocked: publishing gems should be done manually or via CI, not through Claude Code."
|
||||
fi
|
||||
|
||||
if echo "$COMMAND" | grep -qE 'twine[[:space:]]+upload'; then
|
||||
deny "Blocked: publishing Python packages should be done manually or via CI, not through Claude Code."
|
||||
fi
|
||||
|
||||
exit 0
|
||||
@@ -0,0 +1,125 @@
|
||||
#!/bin/bash
|
||||
# Auto-formats files after Claude edits them.
|
||||
# Used as a PostToolUse hook for Edit|Write operations.
|
||||
# Auto-detects formatters — requires both the binary AND a config file to activate.
|
||||
|
||||
# Requires jq for JSON parsing
|
||||
if ! command -v jq >/dev/null 2>&1; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
INPUT=$(cat)
|
||||
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty')
|
||||
|
||||
if [ -z "$FILE_PATH" ] || [ ! -f "$FILE_PATH" ]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
EXTENSION="${FILE_PATH##*.}"
|
||||
FORMATTED=false
|
||||
|
||||
# Find the project root (nearest directory with package.json, pyproject.toml, Cargo.toml, go.mod, or .git)
|
||||
find_project_root() {
|
||||
local dir="$PWD"
|
||||
while [ "$dir" != "/" ]; do
|
||||
if [ -f "$dir/package.json" ] || [ -f "$dir/pyproject.toml" ] || [ -f "$dir/Cargo.toml" ] || [ -f "$dir/go.mod" ] || [ -d "$dir/.git" ]; then
|
||||
echo "$dir"
|
||||
return
|
||||
fi
|
||||
dir=$(dirname "$dir")
|
||||
done
|
||||
echo "$PWD"
|
||||
}
|
||||
|
||||
ROOT=$(find_project_root)
|
||||
|
||||
# --- Biome (JS/TS all-in-one — check first, it's faster than Prettier) ---
|
||||
if [ "$FORMATTED" = false ] && [ -f "$ROOT/node_modules/.bin/biome" ] && [ -f "$ROOT/biome.json" -o -f "$ROOT/biome.jsonc" ]; then
|
||||
case "$EXTENSION" in
|
||||
js|jsx|ts|tsx|json|css)
|
||||
npx biome format --write "$FILE_PATH" 2>/dev/null && FORMATTED=true
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# --- Prettier (Node.js / TypeScript) ---
|
||||
if [ "$FORMATTED" = false ] && [ -f "$ROOT/node_modules/.bin/prettier" ]; then
|
||||
# Check for Prettier config (any common format)
|
||||
HAS_PRETTIER_CONFIG=false
|
||||
for cfg in .prettierrc .prettierrc.json .prettierrc.yml .prettierrc.yaml .prettierrc.js .prettierrc.cjs .prettierrc.mjs .prettierrc.toml prettier.config.js prettier.config.cjs prettier.config.mjs; do
|
||||
if [ -f "$ROOT/$cfg" ]; then
|
||||
HAS_PRETTIER_CONFIG=true
|
||||
break
|
||||
fi
|
||||
done
|
||||
# Also check package.json for "prettier" key
|
||||
if [ "$HAS_PRETTIER_CONFIG" = false ] && [ -f "$ROOT/package.json" ] && grep -q '"prettier"' "$ROOT/package.json" 2>/dev/null; then
|
||||
HAS_PRETTIER_CONFIG=true
|
||||
fi
|
||||
|
||||
if [ "$HAS_PRETTIER_CONFIG" = true ]; then
|
||||
case "$EXTENSION" in
|
||||
js|jsx|ts|tsx|json|css|scss|md|yaml|yml|html)
|
||||
npx prettier --write "$FILE_PATH" 2>/dev/null && FORMATTED=true
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
fi
|
||||
|
||||
# --- Ruff (Python — modern replacement for Black + isort) ---
|
||||
if [ "$FORMATTED" = false ] && command -v ruff >/dev/null 2>&1; then
|
||||
HAS_RUFF_CONFIG=false
|
||||
if [ -f "$ROOT/ruff.toml" ] || [ -f "$ROOT/.ruff.toml" ]; then
|
||||
HAS_RUFF_CONFIG=true
|
||||
elif [ -f "$ROOT/pyproject.toml" ] && grep -q '\[tool\.ruff\]' "$ROOT/pyproject.toml" 2>/dev/null; then
|
||||
HAS_RUFF_CONFIG=true
|
||||
fi
|
||||
|
||||
if [ "$HAS_RUFF_CONFIG" = true ]; then
|
||||
case "$EXTENSION" in
|
||||
py)
|
||||
ruff format "$FILE_PATH" 2>/dev/null
|
||||
ruff check --fix "$FILE_PATH" 2>/dev/null
|
||||
FORMATTED=true
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
fi
|
||||
|
||||
# --- Black + isort (Python — fallback if Ruff not configured) ---
|
||||
if [ "$FORMATTED" = false ] && command -v black >/dev/null 2>&1; then
|
||||
HAS_BLACK_CONFIG=false
|
||||
if [ -f "$ROOT/pyproject.toml" ] && grep -q '\[tool\.black\]' "$ROOT/pyproject.toml" 2>/dev/null; then
|
||||
HAS_BLACK_CONFIG=true
|
||||
fi
|
||||
|
||||
if [ "$HAS_BLACK_CONFIG" = true ]; then
|
||||
case "$EXTENSION" in
|
||||
py)
|
||||
black --quiet "$FILE_PATH" 2>/dev/null
|
||||
command -v isort >/dev/null 2>&1 && isort --quiet "$FILE_PATH" 2>/dev/null
|
||||
FORMATTED=true
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
fi
|
||||
|
||||
# --- Rust (rustfmt is standard — no config check needed) ---
|
||||
if [ "$FORMATTED" = false ] && command -v rustfmt >/dev/null 2>&1; then
|
||||
case "$EXTENSION" in
|
||||
rs)
|
||||
rustfmt "$FILE_PATH" 2>/dev/null && FORMATTED=true
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# --- Go (gofmt is standard — no config check needed) ---
|
||||
if [ "$FORMATTED" = false ] && command -v gofmt >/dev/null 2>&1; then
|
||||
case "$EXTENSION" in
|
||||
go)
|
||||
gofmt -w "$FILE_PATH" 2>/dev/null && FORMATTED=true
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
exit 0
|
||||
@@ -0,0 +1,77 @@
|
||||
#!/bin/bash
|
||||
# Blocks edits to sensitive or generated files.
|
||||
# Used as a PreToolUse hook for Edit|Write operations.
|
||||
# Exit 2 = block the action. Exit 0 = allow.
|
||||
|
||||
# Requires jq for JSON parsing — fail closed if missing
|
||||
if ! command -v jq >/dev/null 2>&1; then
|
||||
echo "{\"hookSpecificOutput\":{\"hookEventName\":\"PreToolUse\",\"permissionDecision\":\"deny\",\"permissionDecisionReason\":\"jq is required for file protection hooks but is not installed.\"}}"
|
||||
exit 2
|
||||
fi
|
||||
|
||||
INPUT=$(cat)
|
||||
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty')
|
||||
|
||||
if [ -z "$FILE_PATH" ]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Protected patterns — add your own
|
||||
PROTECTED_PATTERNS=(
|
||||
".env"
|
||||
".env.*"
|
||||
"*.pem"
|
||||
"*.key"
|
||||
"*.crt"
|
||||
"*.p12"
|
||||
"*.pfx"
|
||||
"id_rsa"
|
||||
"id_ed25519"
|
||||
"credentials.json"
|
||||
".npmrc"
|
||||
".pypirc"
|
||||
"package-lock.json"
|
||||
"yarn.lock"
|
||||
"pnpm-lock.yaml"
|
||||
"*.gen.ts"
|
||||
"*.generated.*"
|
||||
"*.min.js"
|
||||
"*.min.css"
|
||||
)
|
||||
|
||||
BASENAME=$(basename "$FILE_PATH")
|
||||
|
||||
for pattern in "${PROTECTED_PATTERNS[@]}"; do
|
||||
case "$BASENAME" in
|
||||
$pattern)
|
||||
echo "{\"hookSpecificOutput\":{\"hookEventName\":\"PreToolUse\",\"permissionDecision\":\"deny\",\"permissionDecisionReason\":\"Protected file: $BASENAME matches pattern '$pattern'\"}}"
|
||||
exit 2
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Block anything in common sensitive directories (handles both relative and absolute paths)
|
||||
case "$FILE_PATH" in
|
||||
.git/*|*/.git/*)
|
||||
echo "{\"hookSpecificOutput\":{\"hookEventName\":\"PreToolUse\",\"permissionDecision\":\"deny\",\"permissionDecisionReason\":\"Cannot edit files inside .git/\"}}"
|
||||
exit 2
|
||||
;;
|
||||
secrets/*|*/secrets/*)
|
||||
echo "{\"hookSpecificOutput\":{\"hookEventName\":\"PreToolUse\",\"permissionDecision\":\"deny\",\"permissionDecisionReason\":\"Cannot edit files inside secrets/\"}}"
|
||||
exit 2
|
||||
;;
|
||||
.env|.env.*|*/.env|*/.env.*)
|
||||
echo "{\"hookSpecificOutput\":{\"hookEventName\":\"PreToolUse\",\"permissionDecision\":\"deny\",\"permissionDecisionReason\":\"Cannot edit .env files\"}}"
|
||||
exit 2
|
||||
;;
|
||||
.claude/hooks/*|*/.claude/hooks/*)
|
||||
echo "{\"hookSpecificOutput\":{\"hookEventName\":\"PreToolUse\",\"permissionDecision\":\"deny\",\"permissionDecisionReason\":\"Cannot edit hook scripts — these enforce security boundaries.\"}}"
|
||||
exit 2
|
||||
;;
|
||||
.claude/settings.json|*/.claude/settings.json)
|
||||
echo "{\"hookSpecificOutput\":{\"hookEventName\":\"PreToolUse\",\"permissionDecision\":\"ask\",\"permissionDecisionReason\":\"Editing settings.json — this controls permissions and hooks. Confirm this change.\"}}"
|
||||
exit 2
|
||||
;;
|
||||
esac
|
||||
|
||||
exit 0
|
||||
@@ -0,0 +1,81 @@
|
||||
#!/bin/bash
|
||||
# Scans file content for accidental secrets before writing.
|
||||
# Used as a PreToolUse hook for Edit|Write operations.
|
||||
# Exit 2 = block. Exit 0 = allow.
|
||||
|
||||
# Requires jq for JSON parsing — allow if missing (don't block the user)
|
||||
if ! command -v jq >/dev/null 2>&1; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
INPUT=$(cat)
|
||||
TOOL_NAME=$(echo "$INPUT" | jq -r '.tool_name // empty')
|
||||
|
||||
# Extract the content being written
|
||||
if [ "$TOOL_NAME" = "Write" ]; then
|
||||
CONTENT=$(echo "$INPUT" | jq -r '.tool_input.content // empty')
|
||||
elif [ "$TOOL_NAME" = "Edit" ]; then
|
||||
CONTENT=$(echo "$INPUT" | jq -r '.tool_input.new_string // empty')
|
||||
else
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ -z "$CONTENT" ]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# --- High-confidence secret patterns ---
|
||||
|
||||
MATCHES=""
|
||||
|
||||
# AWS Access Key IDs
|
||||
if echo "$CONTENT" | grep -qE 'AKIA[0-9A-Z]{16}'; then
|
||||
MATCHES="$MATCHES AWS access key (AKIA...);"
|
||||
fi
|
||||
|
||||
# AWS Secret Access Keys (40 chars base64 after a key assignment)
|
||||
if echo "$CONTENT" | grep -qiE '(aws_secret_access_key|secret_key)[[:space:]]*[=:][[:space:]]*["\x27]?[A-Za-z0-9/+=]{40}'; then
|
||||
MATCHES="$MATCHES AWS secret key;"
|
||||
fi
|
||||
|
||||
# GitHub tokens (PAT, OAuth, App)
|
||||
if echo "$CONTENT" | grep -qE '(ghp_|gho_|ghs_|ghr_|github_pat_)[a-zA-Z0-9_]{20,}'; then
|
||||
MATCHES="$MATCHES GitHub token;"
|
||||
fi
|
||||
|
||||
# OpenAI / Stripe / Anthropic style keys (sk-...)
|
||||
if echo "$CONTENT" | grep -qE 'sk-[a-zA-Z0-9]{20,}'; then
|
||||
MATCHES="$MATCHES API key (sk-...);"
|
||||
fi
|
||||
|
||||
# Slack tokens
|
||||
if echo "$CONTENT" | grep -qE 'xox[bpras]-[0-9a-zA-Z-]{10,}'; then
|
||||
MATCHES="$MATCHES Slack token;"
|
||||
fi
|
||||
|
||||
# Private key blocks
|
||||
if echo "$CONTENT" | grep -qE -- '-----BEGIN[[:space:]]+(RSA |EC |DSA |OPENSSH )?PRIVATE KEY-----'; then
|
||||
MATCHES="$MATCHES private key block;"
|
||||
fi
|
||||
|
||||
# Connection strings with embedded credentials
|
||||
if echo "$CONTENT" | grep -qE '(mongodb|postgres|mysql|redis|amqp|smtp)(\+[a-z]+)?://[^:[:space:]]+:[^@[:space:]]+@'; then
|
||||
MATCHES="$MATCHES connection string with credentials;"
|
||||
fi
|
||||
|
||||
# Generic password/secret/token assignments with literal string values
|
||||
# Matches: password = "actual_value", SECRET_KEY: 'actual_value', api_token="actual_value"
|
||||
# Excludes: env var references like process.env.*, os.environ.*, ${...}, getenv(...)
|
||||
if echo "$CONTENT" | grep -qiE '(password|secret|token|api_key|apikey|api_secret)[[:space:]]*[=:][[:space:]]*["\x27][^"\x27]{8,}["\x27]' && \
|
||||
! echo "$CONTENT" | grep -qiE '(password|secret|token|api_key|apikey|api_secret)[[:space:]]*[=:][[:space:]]*["\x27]?(process\.env|os\.environ|getenv|\$\{|ENV\[|env\()'; then
|
||||
MATCHES="$MATCHES hardcoded credential;"
|
||||
fi
|
||||
|
||||
if [ -n "$MATCHES" ]; then
|
||||
# Use "ask" not "deny" — warn the user but let them override (could be test fixtures)
|
||||
REASON="Possible secret detected in content:$MATCHES Review carefully before allowing."
|
||||
echo "{\"hookSpecificOutput\":{\"hookEventName\":\"PreToolUse\",\"permissionDecision\":\"ask\",\"permissionDecisionReason\":\"$REASON\"}}"
|
||||
exit 2
|
||||
fi
|
||||
|
||||
exit 0
|
||||
@@ -0,0 +1,51 @@
|
||||
#!/bin/bash
|
||||
# Injects dynamic project context at session start.
|
||||
# Used as a SessionStart hook.
|
||||
|
||||
CONTEXT=""
|
||||
|
||||
# Current branch (or detached HEAD)
|
||||
BRANCH=$(git branch --show-current 2>/dev/null)
|
||||
if [ -n "$BRANCH" ]; then
|
||||
CONTEXT="Branch: $BRANCH"
|
||||
elif git rev-parse --git-dir >/dev/null 2>&1; then
|
||||
SHORT_SHA=$(git rev-parse --short HEAD 2>/dev/null)
|
||||
CONTEXT="HEAD: detached at $SHORT_SHA"
|
||||
fi
|
||||
|
||||
# Last commit
|
||||
LAST_COMMIT=$(git log --oneline -1 2>/dev/null)
|
||||
if [ -n "$LAST_COMMIT" ]; then
|
||||
CONTEXT="$CONTEXT | Last commit: $LAST_COMMIT"
|
||||
fi
|
||||
|
||||
# Uncommitted changes count
|
||||
CHANGES=$(git status --porcelain 2>/dev/null | wc -l | tr -d ' ')
|
||||
if [ "$CHANGES" -gt 0 ] 2>/dev/null; then
|
||||
CONTEXT="$CONTEXT | Uncommitted changes: $CHANGES files"
|
||||
fi
|
||||
|
||||
# Staged changes indicator
|
||||
if ! git diff --cached --quiet 2>/dev/null; then
|
||||
CONTEXT="$CONTEXT | Staged: yes"
|
||||
fi
|
||||
|
||||
# Stash count
|
||||
STASH_COUNT=$(git stash list 2>/dev/null | wc -l | tr -d ' ')
|
||||
if [ "$STASH_COUNT" -gt 0 ] 2>/dev/null; then
|
||||
CONTEXT="$CONTEXT | Stashes: $STASH_COUNT"
|
||||
fi
|
||||
|
||||
# Active PR on current branch (if gh CLI is available)
|
||||
if command -v gh >/dev/null 2>&1; then
|
||||
PR_INFO=$(gh pr view --json number,title,state --jq '"PR #\(.number): \(.title) (\(.state))"' 2>/dev/null)
|
||||
if [ -n "$PR_INFO" ]; then
|
||||
CONTEXT="$CONTEXT | $PR_INFO"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -n "$CONTEXT" ]; then
|
||||
echo "$CONTEXT"
|
||||
fi
|
||||
|
||||
exit 0
|
||||
@@ -0,0 +1,58 @@
|
||||
#!/bin/bash
|
||||
# Blocks writes to build artifacts, binary files, and dependency directories.
|
||||
# Used as a PreToolUse hook for Edit|Write operations.
|
||||
# Exit 2 = block the action. Exit 0 = allow.
|
||||
|
||||
# Requires jq for JSON parsing — fail closed if missing
|
||||
if ! command -v jq >/dev/null 2>&1; then
|
||||
echo "{\"hookSpecificOutput\":{\"hookEventName\":\"PreToolUse\",\"permissionDecision\":\"deny\",\"permissionDecisionReason\":\"jq is required for file protection hooks but is not installed.\"}}"
|
||||
exit 2
|
||||
fi
|
||||
|
||||
INPUT=$(cat)
|
||||
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty')
|
||||
|
||||
if [ -z "$FILE_PATH" ]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Block dependency and build directories
|
||||
case "$FILE_PATH" in
|
||||
node_modules/*|*/node_modules/*)
|
||||
REASON="Cannot write into node_modules/ — install dependencies via package manager instead." ;;
|
||||
vendor/*|*/vendor/*)
|
||||
REASON="Cannot write into vendor/ — use dependency manager instead." ;;
|
||||
dist/*|*/dist/*|build/*|*/build/*|.next/*|*/.next/*)
|
||||
REASON="Cannot write into build output directories — these are generated by the build process." ;;
|
||||
__pycache__/*|*/__pycache__/*)
|
||||
REASON="Cannot write into __pycache__/ — these are generated by Python." ;;
|
||||
.venv/*|*/.venv/*|venv/*|*/venv/*)
|
||||
REASON="Cannot write into virtual environment directories." ;;
|
||||
*)
|
||||
REASON="" ;;
|
||||
esac
|
||||
|
||||
if [ -n "$REASON" ]; then
|
||||
echo "{\"hookSpecificOutput\":{\"hookEventName\":\"PreToolUse\",\"permissionDecision\":\"deny\",\"permissionDecisionReason\":\"$REASON\"}}"
|
||||
exit 2
|
||||
fi
|
||||
|
||||
# Block binary and archive file extensions
|
||||
BASENAME=$(basename "$FILE_PATH")
|
||||
case "$BASENAME" in
|
||||
*.wasm|*.so|*.dylib|*.dll|*.exe|*.o|*.a)
|
||||
REASON="Cannot write binary files — these should be compiled, not hand-written." ;;
|
||||
*.zip|*.tar|*.tar.gz|*.tar.bz2|*.tgz|*.rar|*.7z)
|
||||
REASON="Cannot write archive files." ;;
|
||||
*.mp4|*.mov|*.avi|*.mkv|*.mp3|*.wav|*.flac)
|
||||
REASON="Cannot write media files — add these manually outside Claude Code." ;;
|
||||
*.pyc|*.pyo|*.class)
|
||||
REASON="Cannot write compiled bytecode files." ;;
|
||||
esac
|
||||
|
||||
if [ -n "$REASON" ]; then
|
||||
echo "{\"hookSpecificOutput\":{\"hookEventName\":\"PreToolUse\",\"permissionDecision\":\"deny\",\"permissionDecisionReason\":\"$REASON\"}}"
|
||||
exit 2
|
||||
fi
|
||||
|
||||
exit 0
|
||||
@@ -0,0 +1,57 @@
|
||||
# Rules
|
||||
|
||||
Rules are modular instruction files that Claude loads automatically. They extend CLAUDE.md without bloating it.
|
||||
|
||||
- `alwaysApply: true` — loaded every session, regardless of what files are open
|
||||
- `paths: [...]` — loaded only when working with files matching the glob patterns
|
||||
|
||||
## Available Rules
|
||||
|
||||
### code-quality.md
|
||||
**Scope**: Always
|
||||
|
||||
Principles (single-responsibility, no premature abstraction, composition over inheritance), naming conventions (files, variables, functions, constants), comment guidelines, code markers (TODO/FIXME/HACK/NOTE), and file organization (import order, export patterns, function ordering).
|
||||
|
||||
### testing.md
|
||||
**Scope**: Always
|
||||
|
||||
Three focused principles: test behavior not implementation, run single test files not the full suite, fix or delete flaky tests. Comprehensive test writing is handled by the `test-writer` skill.
|
||||
|
||||
### security.md
|
||||
**Scope**: Path-scoped (`src/api/**`, `src/auth/**`, `src/middleware/**`, `**/routes/**`, `**/controllers/**`)
|
||||
|
||||
Loads when touching API or auth code. Covers input validation, parameterized queries, XSS prevention, token handling, secret logging, constant-time comparison, security headers, rate limiting.
|
||||
|
||||
### frontend.md
|
||||
**Scope**: Path-scoped (`**/*.tsx`, `**/*.jsx`, `**/*.vue`, `**/*.svelte`, `**/*.css`, `**/*.scss`, `**/*.html`, `**/components/**`, `**/pages/**`, etc.)
|
||||
|
||||
Loads when touching frontend files. Design token requirements, design principles pick-list, component framework options, layout rules, accessibility (WCAG 2.1 AA), performance.
|
||||
|
||||
## Adding Your Own
|
||||
|
||||
Create a new `.md` file in this directory:
|
||||
|
||||
```yaml
|
||||
---
|
||||
alwaysApply: true
|
||||
---
|
||||
|
||||
# Your Rule Name
|
||||
|
||||
- Your instructions here
|
||||
```
|
||||
|
||||
Or path-scoped:
|
||||
|
||||
```yaml
|
||||
---
|
||||
paths:
|
||||
- "src/your-area/**"
|
||||
---
|
||||
|
||||
# Your Rule Name
|
||||
|
||||
- Instructions that only apply when touching these files
|
||||
```
|
||||
|
||||
See [Claude Code docs](https://code.claude.com/docs/en/memory#path-specific-rules) for glob pattern syntax.
|
||||
@@ -0,0 +1,51 @@
|
||||
---
|
||||
alwaysApply: true
|
||||
---
|
||||
|
||||
# Code Quality
|
||||
|
||||
## Principles
|
||||
|
||||
- Functions do one thing. If it needs a section comment, extract that section.
|
||||
- No magic values — extract numbers, strings, and config to named constants.
|
||||
- Handle errors at the boundary. Don't catch and re-throw without adding context.
|
||||
- No premature abstractions. Three similar lines > a helper used once.
|
||||
- Don't add features or "improve" things beyond what was asked.
|
||||
- No dead code or commented-out blocks. Git has history.
|
||||
- Composition over inheritance.
|
||||
|
||||
## Naming
|
||||
|
||||
- **Files**: PascalCase for components/classes (`UserProfile.tsx`), kebab-case for utilities/directories (`date-utils.ts`)
|
||||
- **Booleans**: `is`, `has`, `should`, `can` prefix — `isLoading`, `hasPermission`
|
||||
- **Functions**: verb-first — `getUser`, `validateEmail`, `handleSubmit`
|
||||
- **Handlers/callbacks**: `handle*` internally, `on*` as props — `handleClick` / `onClick`
|
||||
- **Factories**: `create*` — `createUser`. **Converters**: `to*` — `toJSON`. **Predicates**: `is*`/`has*`
|
||||
- **Constants**: `SCREAMING_SNAKE` — `MAX_RETRIES`, `API_BASE_URL`
|
||||
- **Enums**: PascalCase members — `Status.Active`
|
||||
- **Abbreviations**: only universally known (`id`, `url`, `api`, `db`, `config`, `auth`). Acronyms as words: `userId` not `userID`
|
||||
|
||||
## Comments
|
||||
|
||||
- **WHY**, never WHAT. If the code needs a "what" comment, rename instead.
|
||||
- Comment: non-obvious decisions, workarounds with issue links, regex patterns, perf tricks
|
||||
- Don't comment: obvious code, self-explanatory function names, section dividers, type info the language provides
|
||||
- No commented-out code — delete it. No journal comments — git blame does this.
|
||||
- API docs (JSDoc, docstrings) at module boundaries only, not every internal function
|
||||
|
||||
## Code Markers
|
||||
|
||||
| Marker | Use |
|
||||
|---|---|
|
||||
| `TODO(author): desc (#issue)` | Planned work |
|
||||
| `FIXME(author): desc (#issue)` | Known bugs |
|
||||
| `HACK(author): desc (#issue)` | Ugly workarounds (explain the proper fix) |
|
||||
| `NOTE: desc` | Non-obvious context for future readers |
|
||||
|
||||
Must have an owner + issue link. Don't commit TODOs you can do now. Never use `XXX`, `TEMP`, `REMOVEME`.
|
||||
|
||||
## File Organization
|
||||
|
||||
- **Imports**: builtins → external → internal → relative → types. Blank line between groups.
|
||||
- **Exports**: named over default. Export at declaration site. One component/class per file.
|
||||
- **Functions**: public first, then private helpers in call order. Top-to-bottom reads as a story.
|
||||
@@ -0,0 +1,26 @@
|
||||
---
|
||||
paths:
|
||||
- "**/migrations/**"
|
||||
- "**/migrate/**"
|
||||
- "**/db/migrate/**"
|
||||
- "**/alembic/**"
|
||||
- "**/alembic/versions/**"
|
||||
- "**/prisma/migrations/**"
|
||||
- "**/drizzle/**"
|
||||
- "**/knex/migrations/**"
|
||||
- "**/sequelize/migrations/**"
|
||||
- "**/typeorm/migrations/**"
|
||||
- "**/flyway/**"
|
||||
- "**/liquibase/**"
|
||||
---
|
||||
|
||||
# Database Migrations
|
||||
|
||||
- **Never modify an existing migration** — always create a new migration for changes. Existing migrations may have already run in production.
|
||||
- Every migration must be reversible — implement both up/forward and down/rollback.
|
||||
- Test migrations in both directions before committing.
|
||||
- Migration filenames are ordered by timestamp prefix — new migrations go at the end.
|
||||
- Never use raw SQL when the ORM/migration tool provides a method for the operation.
|
||||
- Never seed production data in migration files — use dedicated seed files.
|
||||
- Never drop columns or tables without first confirming the data is no longer needed.
|
||||
- Add indexes in their own migration, not bundled with schema changes — easier to rollback independently.
|
||||
@@ -0,0 +1,18 @@
|
||||
---
|
||||
paths:
|
||||
- "src/api/**"
|
||||
- "src/services/**"
|
||||
- "**/controllers/**"
|
||||
- "**/routes/**"
|
||||
- "**/handlers/**"
|
||||
---
|
||||
|
||||
# Error Handling
|
||||
|
||||
- Use typed/custom error classes with error codes — not generic `Error("something went wrong")`.
|
||||
- Never swallow errors silently. Log or rethrow with added context about what operation failed.
|
||||
- Handle every rejected promise. No floating (unhandled) async calls.
|
||||
- HTTP error responses: consistent shape (e.g., `{ error: { code, message } }`), correct status codes (400 for validation, 401 for auth, 404 for not found, 500 for unexpected).
|
||||
- Never expose stack traces, internal paths, or raw database errors in production responses.
|
||||
- Retry transient errors (network timeouts, rate limits) with exponential backoff. Fail fast on validation and auth errors — don't retry.
|
||||
- Include correlation/request IDs in error logs when available.
|
||||
@@ -0,0 +1,77 @@
|
||||
---
|
||||
paths:
|
||||
- "**/*.tsx"
|
||||
- "**/*.jsx"
|
||||
- "**/*.vue"
|
||||
- "**/*.svelte"
|
||||
- "**/*.css"
|
||||
- "**/*.scss"
|
||||
- "**/*.html"
|
||||
- "**/components/**"
|
||||
- "**/pages/**"
|
||||
- "**/views/**"
|
||||
- "**/layouts/**"
|
||||
- "**/styles/**"
|
||||
---
|
||||
|
||||
# Frontend
|
||||
|
||||
## Design Tokens
|
||||
|
||||
Before writing frontend code, find the project's existing tokens file (`tokens.css`, `variables.css`, `theme.ts`, `tailwind.config.*`, `_variables.scss`). If none exists, create one. Never hardcode raw values in components.
|
||||
|
||||
Required token categories: colors (semantic names with dark mode variants), spacing scale, border radius, shadows (elevation system), typography (display + body + mono fonts, type scale, weights), breakpoints, transitions (durations + easing), z-index scale.
|
||||
|
||||
## Design Principles
|
||||
|
||||
Pick one primary principle. Don't mix randomly.
|
||||
|
||||
| Principle | When to use |
|
||||
|---|---|
|
||||
| **Glassmorphism** | Overlays, modern dashboards |
|
||||
| **Neumorphism** | Settings panels, minimal controls |
|
||||
| **Brutalism** | Developer tools, editorial sites |
|
||||
| **Minimalism** | Portfolios, documentation, content-first |
|
||||
| **Maximalism** | Creative agencies, e-commerce |
|
||||
| **Claymorphism** | Playful apps, onboarding |
|
||||
| **Bento Grid** | Dashboards, feature showcases |
|
||||
| **Aurora / Mesh Gradients** | Landing pages, hero sections |
|
||||
| **Flat Design** | Mobile apps, system UI |
|
||||
| **Material Elevation** | Data-heavy apps, enterprise |
|
||||
| **Editorial** | Blogs, long-form content |
|
||||
|
||||
## Component Framework
|
||||
|
||||
Use whatever the project already has. Don't mix competing libraries.
|
||||
|
||||
| Category | Options (pick one) |
|
||||
|---|---|
|
||||
| CSS | Tailwind, vanilla CSS, CSS Modules, styled-components, Emotion, UnoCSS, Panda CSS |
|
||||
| Primitives | shadcn/ui, Radix, Headless UI, Ark UI, DaisyUI, Mantine, Chakra, Vuetify |
|
||||
| Animation | CSS transitions, Framer Motion, GSAP, View Transitions API, AutoAnimate |
|
||||
| Charts | Recharts, D3, Chart.js, Visx, ECharts, Nivo |
|
||||
| Icons | Lucide, Phosphor, Heroicons, Tabler Icons, Iconify |
|
||||
|
||||
## Layout
|
||||
|
||||
- CSS Grid for 2D, Flexbox for 1D. Use `gap`, not margin hacks.
|
||||
- Semantic HTML: `<header>`, `<nav>`, `<main>`, `<section>`, `<article>`, `<footer>`.
|
||||
- Mobile-first. Touch targets: minimum 44x44px.
|
||||
|
||||
## Accessibility (non-negotiable)
|
||||
|
||||
- All interactive elements keyboard-accessible.
|
||||
- Images: meaningful `alt` text. Decorative: `alt=""`.
|
||||
- Form inputs: associated `<label>` or `aria-label`.
|
||||
- Contrast: 4.5:1 normal text, 3:1 large text.
|
||||
- Visible focus indicators. Never `outline: none` without replacement.
|
||||
- Color never the sole indicator.
|
||||
- `aria-live` for dynamic content. Respect `prefers-reduced-motion` and `prefers-color-scheme`.
|
||||
|
||||
## Performance
|
||||
|
||||
- Images: `loading="lazy"` below fold, explicit `width`/`height`.
|
||||
- Fonts: `font-display: swap`.
|
||||
- Animations: `transform` and `opacity` only.
|
||||
- Large lists: virtualize at 100+ items.
|
||||
- Bundle size: never import a whole library for one function.
|
||||
@@ -0,0 +1,19 @@
|
||||
---
|
||||
paths:
|
||||
- "src/api/**"
|
||||
- "src/auth/**"
|
||||
- "src/middleware/**"
|
||||
- "**/routes/**"
|
||||
- "**/controllers/**"
|
||||
---
|
||||
|
||||
# Security
|
||||
|
||||
- Validate all user input at the system boundary. Never trust request parameters.
|
||||
- Use parameterized queries — never concatenate user input into SQL or shell commands.
|
||||
- Sanitize output to prevent XSS. Use framework-provided escaping.
|
||||
- Authentication tokens must be short-lived. Store refresh tokens server-side only.
|
||||
- Never log secrets, tokens, passwords, or PII.
|
||||
- Use constant-time comparison for secrets and tokens.
|
||||
- Set appropriate CORS, CSP, and security headers.
|
||||
- Rate-limit authentication endpoints.
|
||||
@@ -0,0 +1,14 @@
|
||||
---
|
||||
alwaysApply: true
|
||||
---
|
||||
|
||||
# Testing
|
||||
|
||||
- Write tests that verify behavior, not implementation details.
|
||||
- Run the specific test file after changes, not the full suite — faster feedback.
|
||||
- If a test is flaky, fix or delete it. Never retry to make it pass.
|
||||
- Prefer real implementations over mocks. Only mock at system boundaries (network, filesystem, clock).
|
||||
- One assertion per test. If the name needs "and", split it.
|
||||
- Test names describe behavior: `should return empty array when input is empty`, not `test1`.
|
||||
- Arrange-Act-Assert structure. No logic (if/loops) in tests.
|
||||
- Never `expect(true)` or assert a mock was called without checking its arguments.
|
||||
+118
@@ -0,0 +1,118 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/claude-code-settings.json",
|
||||
|
||||
"permissions": {
|
||||
"allow": [
|
||||
"Bash(npm run lint *)",
|
||||
"Bash(npm run test *)",
|
||||
"Bash(npm run typecheck)",
|
||||
"Bash(npm run build)",
|
||||
"Bash(git status)",
|
||||
"Bash(git diff *)",
|
||||
"Bash(git log *)",
|
||||
"Bash(git branch *)",
|
||||
"Bash(git stash *)",
|
||||
"Bash(git add *)",
|
||||
"Bash(git commit *)",
|
||||
"Bash(git fetch *)",
|
||||
"Bash(git checkout *)",
|
||||
"Bash(git switch *)",
|
||||
"Bash(gh pr *)",
|
||||
"Bash(gh issue *)",
|
||||
"Bash(gh run *)"
|
||||
],
|
||||
"deny": [
|
||||
"Read(**/.env)",
|
||||
"Read(**/.env.*)",
|
||||
"Read(**/secrets/**)",
|
||||
"Read(**/*.pem)",
|
||||
"Read(**/*.key)",
|
||||
"Write(**/.env)",
|
||||
"Write(**/.env.*)",
|
||||
"Write(**/secrets/**)",
|
||||
"Write(**/*.pem)",
|
||||
"Write(**/*.key)",
|
||||
"Edit(**/.env)",
|
||||
"Edit(**/.env.*)",
|
||||
"Edit(**/secrets/**)",
|
||||
"Edit(**/*.pem)",
|
||||
"Edit(**/*.key)"
|
||||
]
|
||||
},
|
||||
|
||||
"hooks": {
|
||||
"PreToolUse": [
|
||||
{
|
||||
"matcher": "Edit|Write",
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "$CLAUDE_PROJECT_DIR/.claude/hooks/protect-files.sh",
|
||||
"timeout": 5000,
|
||||
"statusMessage": "Checking file protections..."
|
||||
},
|
||||
{
|
||||
"type": "command",
|
||||
"command": "$CLAUDE_PROJECT_DIR/.claude/hooks/warn-large-files.sh",
|
||||
"timeout": 5000,
|
||||
"statusMessage": "Checking for build artifacts..."
|
||||
},
|
||||
{
|
||||
"type": "command",
|
||||
"command": "$CLAUDE_PROJECT_DIR/.claude/hooks/scan-secrets.sh",
|
||||
"timeout": 5000,
|
||||
"statusMessage": "Scanning for secrets..."
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"matcher": "Bash",
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "$CLAUDE_PROJECT_DIR/.claude/hooks/block-dangerous-commands.sh",
|
||||
"timeout": 5000,
|
||||
"statusMessage": "Checking command safety..."
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"PostToolUse": [
|
||||
{
|
||||
"matcher": "Edit|Write",
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "$CLAUDE_PROJECT_DIR/.claude/hooks/format-on-save.sh",
|
||||
"timeout": 15000,
|
||||
"statusMessage": "Formatting..."
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"SessionStart": [
|
||||
{
|
||||
"matcher": "",
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "$CLAUDE_PROJECT_DIR/.claude/hooks/session-start.sh",
|
||||
"timeout": 5000,
|
||||
"statusMessage": "Loading project context..."
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"Notification": [
|
||||
{
|
||||
"matcher": "",
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "which osascript >/dev/null 2>&1 && osascript -e 'display notification \"Claude Code needs your attention\" with title \"Claude Code\"' || which notify-send >/dev/null 2>&1 && notify-send 'Claude Code' 'Claude Code needs your attention' || true"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/claude-code-settings.json",
|
||||
|
||||
"permissions": {
|
||||
"allow": [
|
||||
"Bash(docker compose *)",
|
||||
"Bash(kubectl *)",
|
||||
"Bash(make *)"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
# Skills
|
||||
|
||||
Skills are slash commands you invoke with `/name`. They run in the main conversation context (they see all loaded rules and CLAUDE.md).
|
||||
|
||||
- `disable-model-invocation: true` — manual only, you type `/name` to trigger
|
||||
- Without that flag — Claude can also trigger the skill automatically when relevant
|
||||
|
||||
## Available Skills
|
||||
|
||||
### /setupdotclaude
|
||||
**Trigger**: Manual only
|
||||
|
||||
Scans the project codebase and customizes all `.claude/` config files to match the actual tech stack, conventions, and patterns. Run this after adding the `.claude/` folder to a new project. Confirms every change with the user. Runs a final review pass with `/refactor` in plan mode against the full codebase.
|
||||
|
||||
### /debug-fix [issue number, error, or description]
|
||||
**Trigger**: Manual only
|
||||
|
||||
Find and fix a bug from any source — GitHub issue number, error message, stack trace, behavior description, or URL. Follows a structured flow: understand → reproduce → investigate → fix → verify → commit.
|
||||
|
||||
### /ship [optional message]
|
||||
**Trigger**: Manual only
|
||||
|
||||
Full shipping workflow with confirmation at every step: scan changes → stage & commit → push → create PR. Proposes commit messages and PR descriptions. Blocks secrets, force-push, and push to main.
|
||||
|
||||
### /pr-review [PR number | staged | file path]
|
||||
**Trigger**: Manual only
|
||||
|
||||
Reviews code changes by delegating to specialist agents (`@code-reviewer`, `@security-reviewer`, `@performance-reviewer`, `@doc-reviewer`). When given a PR number (or auto-detected from branch), also checks PR title, description quality, CI status, unresolved comments, and size — ending with a clear merge/needs-changes verdict. Also works on staged changes or specific files for pre-PR review.
|
||||
|
||||
### /tdd [feature description]
|
||||
**Trigger**: Manual only
|
||||
|
||||
Strict Test-Driven Development loop. Red: write a failing test for the smallest next behavior. Green: write the minimum code to pass. Refactor: clean up without changing behavior. Repeat. Commits after each green+refactor cycle.
|
||||
|
||||
### /explain [file, function, or concept]
|
||||
**Trigger**: Manual only
|
||||
|
||||
Explains code with a one-sentence summary, mental model analogy, ASCII diagram, key details, and modification guide.
|
||||
|
||||
### /refactor [target]
|
||||
**Trigger**: Manual only
|
||||
|
||||
Safe refactoring with tests as a safety net. Writes tests first if none exist, makes changes in small testable steps, verifies no behavior change.
|
||||
|
||||
### /test-writer
|
||||
**Trigger**: Automatic (when new features are added)
|
||||
|
||||
Writes comprehensive tests covering every code path: happy path, edge cases, nulls, type boundaries, error paths, concurrency, state transitions. Covers API endpoints, UI components, database operations, and async. Verifies tests actually catch bugs by breaking the code.
|
||||
|
||||
## Adding Your Own
|
||||
|
||||
Create a directory with a `SKILL.md` file:
|
||||
|
||||
```
|
||||
your-skill/
|
||||
└── SKILL.md
|
||||
```
|
||||
|
||||
```yaml
|
||||
---
|
||||
name: your-skill
|
||||
description: What it does and when to use it
|
||||
disable-model-invocation: true
|
||||
---
|
||||
|
||||
Your instructions here. Use $ARGUMENTS for user input.
|
||||
```
|
||||
|
||||
See [Claude Code docs](https://code.claude.com/docs/en/skills) for all frontmatter options.
|
||||
@@ -0,0 +1,61 @@
|
||||
---
|
||||
name: debug-fix
|
||||
description: Find and fix a bug or issue — from any source (GitHub issue, error message, user report, or observed behavior)
|
||||
argument-hint: "[issue number, error message, or description of the problem]"
|
||||
disable-model-invocation: true
|
||||
---
|
||||
|
||||
Find and fix the following issue:
|
||||
|
||||
**Problem**: $ARGUMENTS
|
||||
|
||||
## Step 1: Understand the Problem
|
||||
|
||||
Determine what kind of input this is:
|
||||
- **Issue number** → fetch it: `gh issue view $ARGUMENTS` (GitHub), or check the project's issue tracker
|
||||
- **Error message / stack trace** → parse it for file, line, error type, and the call chain leading to it
|
||||
- **Description of behavior** → identify what's expected vs what's happening
|
||||
- **URL / screenshot** → examine the referenced resource
|
||||
|
||||
If the problem is unclear, ask clarifying questions before proceeding.
|
||||
|
||||
## Step 2: Reproduce
|
||||
|
||||
- Find or write the simplest way to trigger the issue (a test, a curl command, a script)
|
||||
- Confirm you can reproduce it reliably
|
||||
- If you can't reproduce:
|
||||
- **Environment-specific?** Check env vars, OS, Node/Python version, database state
|
||||
- **Intermittent?** Likely a race condition — look for shared mutable state, timing dependencies, or async ordering assumptions
|
||||
- **Already fixed?** Check `git log` for recent commits that mention the issue
|
||||
|
||||
## Step 3: Investigate
|
||||
|
||||
Follow this sequence — don't skip ahead to guessing:
|
||||
|
||||
1. **Locate the symptom**: which file and line produces the wrong output/error?
|
||||
2. **Read the code path**: trace backwards from the symptom. What function called this? What data did it pass? Read each caller.
|
||||
3. **Check git history**: `git log --oneline -20 -- <file>` to see what recently changed in the affected files. `git log --all --grep="<keyword>"` to find related commits.
|
||||
4. **Narrow the scope**: use `git bisect` or targeted grep to identify when the behavior changed, or which input triggers it.
|
||||
5. **Form a hypothesis**: "I think [X] is wrong because [evidence]."
|
||||
6. **Verify the hypothesis**: add a targeted log/assertion/test that would confirm or deny it. Run it.
|
||||
7. **If wrong, update**: don't keep guessing with the same hypothesis. Go back to step 2 and trace a different path.
|
||||
|
||||
## Step 4: Fix
|
||||
|
||||
- Make the minimal change that fixes the root cause
|
||||
- Don't patch symptoms — if a value is wrong, trace back to where it becomes wrong and fix it there
|
||||
- Don't refactor surrounding code while fixing the bug
|
||||
- Don't add defensive checks that mask the problem — fix why the bad data exists
|
||||
|
||||
## Step 5: Verify
|
||||
|
||||
- Write a test that reproduces the original bug and now passes with the fix
|
||||
- Run related tests to check for regressions
|
||||
- Run lint and typecheck
|
||||
- Temporarily revert your fix and confirm the new test fails — this proves the test actually catches the bug
|
||||
|
||||
## Step 6: Wrap Up
|
||||
|
||||
- Create a branch if not already on one
|
||||
- Stage only the relevant files (fix + test, nothing else)
|
||||
- Commit with a message that references the issue if one exists: `fix: <what was wrong and why> (#number)`
|
||||
@@ -0,0 +1,33 @@
|
||||
---
|
||||
name: explain
|
||||
description: Explain code with visual diagrams and clear mental models
|
||||
argument-hint: "[file, function, or concept]"
|
||||
disable-model-invocation: true
|
||||
---
|
||||
|
||||
Explain `$ARGUMENTS` clearly.
|
||||
|
||||
## Format
|
||||
|
||||
### 1. One-sentence summary
|
||||
What does it do and why does it exist? One sentence.
|
||||
|
||||
### 2. Mental model
|
||||
Give an analogy or metaphor that captures the core idea. Relate it to something the developer already knows.
|
||||
|
||||
### 3. Visual diagram
|
||||
Draw an ASCII diagram showing the data/control flow. Keep it readable:
|
||||
```
|
||||
Input → [Step A] → [Step B] → Output
|
||||
↓
|
||||
[Side Effect]
|
||||
```
|
||||
|
||||
### 4. Key details
|
||||
Walk through the important parts. Skip the obvious — focus on:
|
||||
- Non-obvious decisions (why this approach?)
|
||||
- Edge cases and gotchas
|
||||
- Dependencies and side effects
|
||||
|
||||
### 5. How to modify it
|
||||
What would someone need to know to safely change this code? Where are the landmines?
|
||||
@@ -0,0 +1,71 @@
|
||||
---
|
||||
name: hotfix
|
||||
description: Emergency production fix — create hotfix branch, minimal change, critical tests only, ship fast
|
||||
argument-hint: "[issue number, error message, or description of production problem]"
|
||||
disable-model-invocation: true
|
||||
allowed-tools:
|
||||
- Bash(git *)
|
||||
- Bash(gh *)
|
||||
- Bash(npm run test *)
|
||||
- Bash(npm run build)
|
||||
- Read
|
||||
- Glob
|
||||
- Grep
|
||||
- Edit
|
||||
- Write
|
||||
---
|
||||
|
||||
Emergency production fix. Speed matters — make the smallest correct change, verify it works, and ship.
|
||||
|
||||
## Step 1: Create Hotfix Branch
|
||||
|
||||
- Determine the production branch (`main` or `master` — check with `git remote show origin` or `git symbolic-ref refs/remotes/origin/HEAD`)
|
||||
- Stash any uncommitted work if needed
|
||||
- Create and switch to `hotfix/<short-description>` branch from the production branch
|
||||
- **ASK the user to confirm** the branch name before creating
|
||||
|
||||
## Step 2: Understand the Problem
|
||||
|
||||
- If `$ARGUMENTS` is a GitHub issue number: fetch it with `gh issue view`
|
||||
- If it's an error message or description: search the codebase for the relevant code
|
||||
- Identify the root cause — trace from symptom to source
|
||||
- **Briefly state** what you found and your proposed fix to the user
|
||||
|
||||
## Step 3: Fix — Minimal Change Only
|
||||
|
||||
- Make the smallest change that correctly fixes the issue
|
||||
- **Do NOT**:
|
||||
- Refactor surrounding code
|
||||
- Add new features
|
||||
- Clean up unrelated issues
|
||||
- Change formatting or style
|
||||
- Add comments beyond what's necessary to understand the fix
|
||||
- If the fix requires more than ~50 lines changed, warn the user — this may not be a hotfix
|
||||
|
||||
## Step 4: Verify
|
||||
|
||||
- Run only the tests directly relevant to the changed code (not the full suite)
|
||||
- Run the build to ensure it compiles
|
||||
- If there's a way to reproduce the original error, verify it's fixed
|
||||
- **ASK the user** if they want to run any additional verification
|
||||
|
||||
## Step 5: Ship
|
||||
|
||||
- Stage only the fix files (never stage secrets, locks, build output)
|
||||
- Draft a commit message: `hotfix: <short description>` with a brief explanation
|
||||
- **ASK the user to confirm** the commit message
|
||||
- Push with `git push -u origin hotfix/<description>`
|
||||
- Create a PR targeting the production branch:
|
||||
- Title: `[HOTFIX] <description>`
|
||||
- Body: what broke, what caused it, what this fixes
|
||||
- Add label `hotfix` if the repo has it: `gh pr create ... --label hotfix` (fall back to no label if it fails)
|
||||
- Show the PR URL
|
||||
|
||||
## Rules
|
||||
|
||||
- NEVER skip confirmation steps
|
||||
- NEVER force-push
|
||||
- NEVER commit secrets or unrelated changes
|
||||
- NEVER refactor — this is a hotfix, not a cleanup
|
||||
- If the user says "skip" at any step, skip it and move to the next
|
||||
- If the fix turns out to be complex, tell the user and suggest a regular branch instead
|
||||
@@ -0,0 +1,94 @@
|
||||
---
|
||||
name: pr-review
|
||||
description: Review code changes or a pull request — delegates to specialist agents for code quality, security, performance, and documentation.
|
||||
argument-hint: "[PR number | staged | file path — or omit to auto-detect]"
|
||||
disable-model-invocation: true
|
||||
---
|
||||
|
||||
Review code changes by delegating to specialist agents and synthesizing a unified report. Works with PRs, staged changes, or specific files.
|
||||
|
||||
## Step 1: Determine Scope
|
||||
|
||||
Parse `$ARGUMENTS` to determine what to review:
|
||||
|
||||
- **PR number** (e.g., `123` or `#123`): fetch with `gh pr view $ARGUMENTS`. This is the full PR review path (includes PR quality checks in Step 2).
|
||||
- **No argument**: try `gh pr view` to detect a PR for the current branch. If a PR exists, use it. If not, fall back to `git diff --cached` (staged), then `git diff` (unstaged).
|
||||
- **`staged`**: review `git diff --cached`. If nothing staged, fall back to `git diff`.
|
||||
- **File path**: review that specific file's current state.
|
||||
|
||||
If there are no changes to review, say so and stop.
|
||||
|
||||
## Step 2: PR Quality Check (PR path only)
|
||||
|
||||
Skip this step if reviewing staged changes or a file — jump to Step 3.
|
||||
|
||||
When reviewing a PR, fetch and check:
|
||||
- PR title, description/body, author, base branch, head branch
|
||||
- `gh pr diff $NUMBER` for the full diff
|
||||
- `gh pr checks $NUMBER` for CI status
|
||||
- `gh api repos/{owner}/{repo}/pulls/$NUMBER/comments` for review comments
|
||||
|
||||
Review the PR itself before the code:
|
||||
- **Title**: descriptive and under 72 chars?
|
||||
- **Description**: explains the *why*? Includes a test plan? Flag if empty or template-only.
|
||||
- **Size**: count changed files and lines. Flag if >500 lines changed (suggest splitting).
|
||||
- **Base branch**: targeting the right branch?
|
||||
- **CI status**: passing, failing, or pending? If failing, note which checks — fix CI first.
|
||||
- **Unresolved comments**: list open review threads with file:line and comment text.
|
||||
|
||||
## Step 3: Code Review (delegate to agents)
|
||||
|
||||
1. **Always**: delegate the diff to `@code-reviewer`
|
||||
2. **If security-sensitive code changed** — auth, input handling, queries, tokens, session management, file path construction: delegate to `@security-reviewer`
|
||||
3. **If performance-sensitive code changed** — endpoints, DB queries, loops over collections, caching, connection management: delegate to `@performance-reviewer`. Skip if changes are only docs, config, tests, or static assets.
|
||||
4. **If documentation changed** — .md files, significant docstring/JSDoc changes, API docs: delegate to `@doc-reviewer`
|
||||
|
||||
Determine relevance by reading the diff content, not just file paths.
|
||||
|
||||
## Step 4: Synthesize Report
|
||||
|
||||
For PR reviews:
|
||||
```
|
||||
## PR Review: #[number] — [title]
|
||||
|
||||
**Author**: [author] | **Base**: [base] → **Head**: [head] | **Changed**: [N files, +X/-Y lines]
|
||||
|
||||
### PR Quality
|
||||
- Title: [ok / needs improvement]
|
||||
- Description: [ok / missing test plan / empty]
|
||||
- Size: [ok / large — consider splitting]
|
||||
- CI: [passing / failing — list failures]
|
||||
- Unresolved comments: [none / list]
|
||||
|
||||
### Code Review
|
||||
#### Critical / High
|
||||
- [Agent] File:Line — issue
|
||||
|
||||
#### Medium
|
||||
- [Agent] File:Line — issue
|
||||
|
||||
#### Low
|
||||
- [Agent] File:Line — issue
|
||||
|
||||
### Verdict
|
||||
[Ready to merge / Needs changes — summarize blockers]
|
||||
```
|
||||
|
||||
For non-PR reviews (staged/file):
|
||||
```
|
||||
## Review Summary
|
||||
|
||||
**Scope**: [staged changes / file path]
|
||||
**Agents run**: [list]
|
||||
|
||||
### Critical / High
|
||||
- [Agent] File:Line — issue
|
||||
|
||||
### Medium / Low
|
||||
- [Agent] File:Line — issue
|
||||
|
||||
### Passed
|
||||
- [areas with no issues]
|
||||
```
|
||||
|
||||
Deduplicate findings that overlap between agents. Attribute each finding to the agent that found it.
|
||||
@@ -0,0 +1,36 @@
|
||||
---
|
||||
name: refactor
|
||||
description: Safely refactor code with test coverage as a safety net
|
||||
argument-hint: "[target to refactor — file, function, or pattern]"
|
||||
disable-model-invocation: true
|
||||
---
|
||||
|
||||
Refactor `$ARGUMENTS` safely.
|
||||
|
||||
## Process
|
||||
|
||||
### 1. Understand the current state
|
||||
- Read the code and its tests
|
||||
- Identify what the code does, its callers, and its dependencies
|
||||
- If there are no tests, WRITE TESTS FIRST — you need a safety net before changing anything
|
||||
|
||||
### 2. Plan the refactoring
|
||||
- State what you're changing and why (clearer naming, reduced duplication, better structure)
|
||||
- List the specific transformations (extract function, inline variable, move module, etc.)
|
||||
- Check: does this change any external behavior? If yes, this isn't a refactor — reconsider.
|
||||
|
||||
### 3. Make changes in small, testable steps
|
||||
- One transformation at a time
|
||||
- Run tests after EACH step — not at the end
|
||||
- If a test breaks, undo the last step and make a smaller change
|
||||
|
||||
### 4. Verify
|
||||
- All existing tests pass
|
||||
- Lint and typecheck pass
|
||||
- The public API hasn't changed (unless that was the explicit goal)
|
||||
- The code is objectively simpler — fewer lines, fewer branches, clearer names
|
||||
|
||||
## Rules
|
||||
- If you can't run the tests, don't refactor
|
||||
- Never mix refactoring with behavior changes in the same commit
|
||||
- If the refactoring is large (10+ files), break it into multiple commits
|
||||
@@ -0,0 +1,198 @@
|
||||
---
|
||||
name: setupdotclaude
|
||||
description: Scan the project codebase and customize all .claude/ configuration files to match. Run this after adding the .claude/ folder to a new project.
|
||||
argument-hint: "[optional: focus area like 'frontend' or 'backend']"
|
||||
disable-model-invocation: true
|
||||
---
|
||||
|
||||
Scan this project's codebase and customize every `.claude/` configuration file to match the actual tech stack, conventions, and patterns in use. Confirm with the user before each change using AskUserQuestion.
|
||||
|
||||
CLAUDE.md must be at the project root (`./CLAUDE.md`), NOT inside `.claude/`. All other config files live inside `.claude/`.
|
||||
|
||||
If the project is empty or has no source code yet, tell the user the defaults will be kept as-is and stop.
|
||||
|
||||
## Phase 0: Clean Up Non-Config Files
|
||||
|
||||
Before anything else, delete files inside `.claude/` that exist for the dotclaude repo itself but waste tokens or cause issues at runtime:
|
||||
- `.claude/README.md` (repo README accidentally copied in)
|
||||
- `.claude/CONTRIBUTING.md` (repo contributing guide accidentally copied in)
|
||||
- `.claude/.gitignore` (for the dotclaude repo, not the project — the project has its own .gitignore)
|
||||
- `.claude/rules/README.md`
|
||||
- `.claude/agents/README.md`
|
||||
- `.claude/hooks/README.md`
|
||||
- `.claude/skills/README.md`
|
||||
|
||||
Also delete `.claude/CLAUDE.md` if it exists — CLAUDE.md belongs at the project root, not inside `.claude/`.
|
||||
|
||||
## Phase 1: Detect Tech Stack
|
||||
|
||||
Scan for package manifests, config files, and folder structure to detect: language, framework, package manager, test framework, linter/formatter, architecture pattern, and source/test directories.
|
||||
|
||||
Check: `package.json`, `pyproject.toml`, `Cargo.toml`, `go.mod`, `Gemfile`, `composer.json`, `build.gradle`, `pom.xml`, `Makefile`, `Dockerfile`.
|
||||
|
||||
Check for monorepo indicators: `workspaces` key in package.json, `pnpm-workspace.yaml`, `lerna.json`, `nx.json`, `turbo.json`, or multiple `package.json` files at depth 2+. If a monorepo is detected, ask the user which packages/apps to focus on and customize rule path patterns to include package prefixes (e.g., `packages/api/src/**` instead of `src/**`).
|
||||
|
||||
Detect frameworks from dependencies and config files (frontend, backend, CSS, components, ORM/DB).
|
||||
|
||||
Detect test framework from config files (`jest.config.*`, `vitest.config.*`, `pytest.ini`, `conftest.py`, `playwright.config.*`, etc.).
|
||||
|
||||
Detect linter/formatter from config files (`.eslintrc.*`, `.prettierrc.*`, `biome.json`, `ruff.toml`, `tsconfig.json`, `.editorconfig`, etc.).
|
||||
|
||||
Detect folder structure pattern (feature-based, layered, monorepo, MVC) and locate source, test, API, and auth directories.
|
||||
|
||||
Check `git log --oneline -20` for commit message style.
|
||||
|
||||
## Phase 2: Present Findings
|
||||
|
||||
Present a summary to the user using AskUserQuestion:
|
||||
|
||||
```
|
||||
I scanned your project. Here's what I found:
|
||||
|
||||
**Stack**: [language] + [framework] + [CSS] + [DB]
|
||||
**Package manager**: [npm/pnpm/yarn/bun/pip/cargo/go]
|
||||
**Test framework**: [jest/vitest/pytest/etc.]
|
||||
**Linter/Formatter**: [eslint+prettier/ruff/clippy/etc.]
|
||||
**Architecture**: [layered/feature-based/monorepo/etc.]
|
||||
**Source dirs**: [list]
|
||||
**Test dirs**: [list]
|
||||
|
||||
Should I customize the .claude/ files based on this? (yes/no/corrections)
|
||||
```
|
||||
|
||||
If the user provides corrections, incorporate them.
|
||||
|
||||
## Phase 3: Customize Each File
|
||||
|
||||
For each file below, propose the specific changes and ask the user to confirm before applying.
|
||||
|
||||
### 3.1 — CLAUDE.md
|
||||
|
||||
Replace the template commands with actual commands from the detected manifest:
|
||||
- **Build**: actual build command from package.json scripts, Makefile targets, etc.
|
||||
- **Test**: actual test command + how to run a single test file
|
||||
- **Lint/Format**: actual lint and format commands
|
||||
- **Dev**: actual dev server command
|
||||
- **Architecture**: replace placeholder directories with actual project structure (only non-obvious parts)
|
||||
|
||||
Remove sections that don't apply (e.g., Architecture section for a single-file utility).
|
||||
|
||||
### 3.2 — settings.json
|
||||
|
||||
Update permissions to match actual commands:
|
||||
- Replace `npm run` with the actual package manager (`pnpm run`, `yarn`, `bun run`, `cargo`, `go`, `make`, `python -m pytest`, etc.)
|
||||
- Add project-specific allow rules for detected scripts
|
||||
- Keep deny rules for secrets as-is (these are universal)
|
||||
|
||||
### 3.3 — rules/code-quality.md
|
||||
|
||||
Update naming conventions ONLY if the project's existing code uses different patterns:
|
||||
- Sample 5-10 source files to detect actual naming style (camelCase vs snake_case, etc.)
|
||||
- If the project uses different file naming than the template, update
|
||||
- If the project's import style differs, update the import order section
|
||||
|
||||
If everything matches the defaults, leave it unchanged.
|
||||
|
||||
### 3.4 — rules/testing.md
|
||||
|
||||
Update if the detected test framework has specific idioms. Otherwise leave as-is (it's only 3 lines).
|
||||
|
||||
### 3.5 — rules/security.md
|
||||
|
||||
Update the `paths:` frontmatter to match actual project directories:
|
||||
- Replace `src/api/**` with actual API directory paths found
|
||||
- Replace `src/auth/**` with actual auth directory paths
|
||||
- Replace `src/middleware/**` with actual middleware paths
|
||||
- If none found, keep the defaults as reasonable guesses
|
||||
|
||||
### 3.5b — rules/error-handling.md
|
||||
|
||||
Update the `paths:` frontmatter to match actual backend directories (same paths as security.md plus service/handler directories). If the project has no backend, delete this file.
|
||||
|
||||
### 3.6 — rules/frontend.md
|
||||
|
||||
- **If no frontend files exist** (no .tsx, .jsx, .vue, .svelte, .css): delete this file entirely
|
||||
- **If frontend exists**: update the Component Framework table to highlight which options the project actually uses (detected from dependencies)
|
||||
- Update path patterns in frontmatter if the project uses non-standard directories
|
||||
|
||||
### 3.7 — hooks/format-on-save.sh
|
||||
|
||||
Uncomment the section matching the detected formatter:
|
||||
- Prettier found → uncomment Node.js section
|
||||
- Black/isort found → uncomment Python section
|
||||
- Ruff found → uncomment Ruff section
|
||||
- Biome found → uncomment Biome section
|
||||
- rustfmt found → uncomment Rust section
|
||||
- gofmt found → uncomment Go section
|
||||
- Multiple languages → uncomment all relevant sections
|
||||
|
||||
### 3.8 — hooks/block-dangerous-commands.sh
|
||||
|
||||
Check the default branch name (`git symbolic-ref refs/remotes/origin/HEAD 2>/dev/null` or `git remote show origin`). If it's not `main` or `master`, update the regex pattern.
|
||||
|
||||
### 3.9 — rules/database.md
|
||||
|
||||
- Check if the project has a database (look for: migration directories, ORM config files like `prisma/schema.prisma`, `drizzle.config.*`, `alembic.ini`, `knexfile.*`, `sequelize` in dependencies, `typeorm` in dependencies, `ActiveRecord` patterns, `flyway`, `liquibase`)
|
||||
- **If database/migrations detected**: keep the rule, update `paths:` frontmatter to match the actual migration directory paths found
|
||||
- **If no database detected**: delete `rules/database.md` entirely
|
||||
|
||||
### 3.10 — skills/
|
||||
|
||||
All skills are methodology-based and project-agnostic. Leave unchanged.
|
||||
|
||||
### 3.11 — agents/
|
||||
|
||||
- **frontend-designer.md**: delete if no frontend files exist
|
||||
- **doc-reviewer.md**: delete if the project has no documentation directory (no `docs/`, `doc/`, or significant `.md` files beyond README)
|
||||
- **security-reviewer.md**: keep (security applies everywhere)
|
||||
- **code-reviewer.md**: keep (universal)
|
||||
- **performance-reviewer.md**: keep (universal)
|
||||
|
||||
## Phase 4: Review & Simplify
|
||||
|
||||
After all changes are applied, run a thorough final review pass.
|
||||
|
||||
Strip any remaining `> REPLACE:` placeholder blocks from `CLAUDE.md` — these are template guidance that should have been replaced with real content or removed during Phase 3.1.
|
||||
|
||||
Review the entire codebase alongside the customized `.claude/` configuration:
|
||||
- Do the rules match how the code is actually written?
|
||||
- Do the settings permissions cover the commands the project actually uses?
|
||||
- Do the security rule paths match where sensitive code actually lives?
|
||||
- Do the hook protections cover the files that actually need protecting in this project?
|
||||
- Are there project patterns, conventions, or architectural decisions not yet captured in the config?
|
||||
- Remove any redundancy introduced during customization
|
||||
- Ensure no file contradicts another
|
||||
- Trim any verbose instructions back to essentials
|
||||
- Verify all YAML frontmatter is valid
|
||||
- Verify all hook scripts referenced in settings.json exist and are executable
|
||||
|
||||
Present the review findings to the user. If changes are needed, confirm before applying.
|
||||
|
||||
## Phase 5: Summary
|
||||
|
||||
After everything is finalized, present a summary:
|
||||
|
||||
```
|
||||
Setup complete. Here's what was customized:
|
||||
|
||||
- CLAUDE.md: updated commands for [stack]
|
||||
- settings.json: permissions updated for [package manager]
|
||||
- rules/security.md: paths updated to [actual dirs]
|
||||
- rules/frontend.md: [kept/removed]
|
||||
- hooks/format-on-save.sh: enabled [formatter]
|
||||
- [any other changes]
|
||||
|
||||
Files left as defaults (universal, no project-specific changes needed):
|
||||
- [list]
|
||||
|
||||
Review pass: [any issues found and fixed, or "all clean"]
|
||||
```
|
||||
|
||||
## Rules
|
||||
|
||||
- NEVER write changes without user confirmation first
|
||||
- NEVER delete a file without confirming — propose "remove" and explain why
|
||||
- If the project is empty (no source files, no manifests), say "Project appears empty — keeping all defaults" and stop
|
||||
- If detection is uncertain, ASK the user rather than guessing
|
||||
- Preserve any manual edits the user has already made to .claude/ files — only update sections that need project-specific customization
|
||||
- Keep it minimal — don't add complexity. If the default works, leave it alone.
|
||||
@@ -0,0 +1,71 @@
|
||||
---
|
||||
name: ship
|
||||
description: Scan changes, commit, push, and create a PR — with confirmation at each step
|
||||
argument-hint: "[optional commit message or PR title]"
|
||||
disable-model-invocation: true
|
||||
allowed-tools:
|
||||
- Bash(git status)
|
||||
- Bash(git diff *)
|
||||
- Bash(git log *)
|
||||
- Bash(git add *)
|
||||
- Bash(git commit *)
|
||||
- Bash(git push *)
|
||||
- Bash(git checkout *)
|
||||
- Bash(git branch *)
|
||||
- Bash(gh pr create *)
|
||||
- Bash(gh pr view *)
|
||||
---
|
||||
|
||||
Ship the current changes through commit, push, and PR creation. Confirm with the user before each step using the AskUserQuestion tool.
|
||||
|
||||
## Step 1: Scan
|
||||
|
||||
- Run `git status` to see all changed, staged, and untracked files
|
||||
- Run `git diff` to see what changed (staged + unstaged)
|
||||
- Run `git log --oneline -5` to see recent commit style
|
||||
- Present a clear summary to the user:
|
||||
- Files modified
|
||||
- Files added
|
||||
- Files deleted
|
||||
- Untracked files
|
||||
- If there are no changes, tell the user and stop
|
||||
|
||||
## Step 2: Stage & Commit
|
||||
|
||||
- Propose which files to stage. **Never stage** these:
|
||||
- Secrets: `.env*`, `*.pem`, `*.key`, `credentials.json`
|
||||
- Lock files: `package-lock.json`, `yarn.lock`, `pnpm-lock.yaml` (unless intentionally updated)
|
||||
- Generated: `*.gen.ts`, `*.generated.*`, `*.min.js`, `*.min.css`
|
||||
- Build output: `dist/`, `build/`, `.next/`, `__pycache__/`
|
||||
- Dependencies: `node_modules/`, `vendor/`, `.venv/`
|
||||
- OS/editor: `.DS_Store`, `Thumbs.db`, `*.swp`, `.idea/`, `.vscode/settings.json`
|
||||
- Draft a commit message based on the changes, matching the repo's existing commit style
|
||||
- **ASK the user to confirm or edit**: show the exact files to stage and the proposed commit message
|
||||
- Only after confirmation: stage the files and create the commit
|
||||
- If the commit fails (e.g., pre-commit hook), fix the issue and try again with a NEW commit
|
||||
|
||||
## Step 3: Push
|
||||
|
||||
- Check if the current branch has an upstream remote
|
||||
- If not, propose creating one with `git push -u origin <branch>`
|
||||
- **ASK the user to confirm** before pushing
|
||||
- Only after confirmation: push to remote
|
||||
|
||||
## Step 4: Pull Request
|
||||
|
||||
- Check if a PR already exists for this branch (`gh pr view` — if it exists, show the URL and stop)
|
||||
- Analyze ALL commits on this branch vs the base branch (not just the latest commit)
|
||||
- Draft a PR title (under 72 chars) and body with:
|
||||
- Summary: 2-4 bullet points
|
||||
- Test plan: how to verify
|
||||
- **ASK the user to confirm or edit** the title and body
|
||||
- Only after confirmation: create the PR with `gh pr create`
|
||||
- Show the PR URL when done
|
||||
|
||||
## Rules
|
||||
|
||||
- NEVER skip a confirmation step — each step requires explicit user approval
|
||||
- NEVER force-push
|
||||
- NEVER commit .env, secrets, or credential files
|
||||
- If the user says "skip" at any step, skip that step and move to the next
|
||||
- If $ARGUMENTS is provided, use it as the commit message / PR title
|
||||
@@ -0,0 +1,70 @@
|
||||
---
|
||||
name: tdd
|
||||
description: Test-Driven Development loop — write a failing test first, then the minimum code to pass it, then refactor. Repeat.
|
||||
argument-hint: "[feature description or function signature]"
|
||||
disable-model-invocation: true
|
||||
---
|
||||
|
||||
Build the following using strict Test-Driven Development:
|
||||
|
||||
**Feature**: $ARGUMENTS
|
||||
|
||||
## The TDD Cycle
|
||||
|
||||
Repeat this cycle for each behavior. Never skip steps.
|
||||
|
||||
### Red: Write a Failing Test
|
||||
|
||||
1. Write ONE test for the smallest next behavior (not the whole feature)
|
||||
2. The test must:
|
||||
- Describe the behavior in its name: `should return 0 for empty cart`
|
||||
- Use Arrange-Act-Assert structure
|
||||
- Assert specific values, not vague truths
|
||||
3. **Run the test. It MUST fail.** If it passes, either:
|
||||
- The behavior already exists (skip to the next behavior)
|
||||
- The test is wrong (it's not testing what you think — fix it)
|
||||
4. Verify the failure message makes sense — it should tell you what's missing
|
||||
|
||||
### Green: Write the Minimum Code to Pass
|
||||
|
||||
1. Write the **simplest, most obvious code** that makes the failing test pass
|
||||
2. Don't generalize. Don't make it elegant. Don't handle cases the test doesn't cover.
|
||||
3. Hardcoding is fine if only one test exists for that path — the next test will force generalization
|
||||
4. **Run the test. It MUST pass.** If it doesn't, fix the code (not the test — the test defined the behavior)
|
||||
5. Run ALL tests. Nothing previously passing should break.
|
||||
|
||||
### Refactor: Clean Up Without Changing Behavior
|
||||
|
||||
1. Look for: duplication, unclear names, functions doing too much, magic values
|
||||
2. Make ONE improvement at a time
|
||||
3. **Run ALL tests after each change.** If anything breaks, undo immediately.
|
||||
4. Stop refactoring when the code is clean enough — don't gold-plate
|
||||
|
||||
## Choosing What to Test Next
|
||||
|
||||
Work from simple to complex:
|
||||
1. **Degenerate cases** — null input, empty collection, zero
|
||||
2. **Happy path** — the simplest valid input
|
||||
3. **Variations** — different valid inputs that exercise different branches
|
||||
4. **Edge cases** — boundary values, max sizes, special characters
|
||||
5. **Error cases** — invalid input, failures, exceptions
|
||||
6. **Integration** — how this connects to the rest of the system
|
||||
|
||||
Each test should require a small code change. If you need to write more than ~10 lines of production code to pass a test, the test is too big — split it.
|
||||
|
||||
## Rules
|
||||
|
||||
- **Never write production code without a failing test that demands it.**
|
||||
- **Never write more than one failing test at a time.** One red → green → refactor cycle at a time.
|
||||
- **The test drives the design.** If the code is hard to test, the design is wrong — change the design, not the test approach.
|
||||
- **Don't mock what you own.** If you need to mock your own code to test it, the code needs restructuring.
|
||||
- **Commit after each green+refactor cycle.** Small, passing, meaningful commits.
|
||||
|
||||
## Output
|
||||
|
||||
After each cycle, briefly state:
|
||||
- **Test**: what behavior was added
|
||||
- **Code**: what changed to make it pass
|
||||
- **Refactor**: what was cleaned up (or "none needed")
|
||||
|
||||
When the feature is complete, provide a summary of all behaviors covered and any gaps that would need integration or manual testing.
|
||||
@@ -0,0 +1,97 @@
|
||||
---
|
||||
name: test-writer
|
||||
description: Write comprehensive tests for new or changed code. Use automatically when new features are added, functions are created, or behavior is modified.
|
||||
# No disable-model-invocation — Claude can auto-trigger this when adding features.
|
||||
# Add "disable-model-invocation: true" below if you prefer manual-only via /test-writer.
|
||||
---
|
||||
|
||||
Write comprehensive tests for the code that was just added or changed.
|
||||
|
||||
## Step 1: Discover What Changed
|
||||
|
||||
- Check `git diff` and `git diff --cached` to identify new/modified functions, classes, and modules
|
||||
- Read each changed file to understand the behavior being added
|
||||
- Identify the project's existing test framework, patterns, and conventions by finding existing test files
|
||||
- Place new test files next to the source files or in the project's established test directory — match whatever the project already does
|
||||
|
||||
## Step 2: Analyze Every Code Path
|
||||
|
||||
For each new or modified function/method/component, map out:
|
||||
|
||||
- **Happy path** — normal input, expected output
|
||||
- **Edge cases** — empty input, single element, boundary values (0, 1, -1, MAX_INT)
|
||||
- **Null/undefined/nil** — what happens with missing data
|
||||
- **Type boundaries** — wrong types, type coercion traps
|
||||
- **Error paths** — invalid input, network failures, timeouts, permission denied
|
||||
- **Concurrency** — race conditions, parallel calls with shared state
|
||||
- **State transitions** — initial state, intermediate states, final state
|
||||
- **Integration points** — how this code interacts with its dependencies
|
||||
|
||||
## Step 3: Write the Tests
|
||||
|
||||
For EACH scenario identified above, write a test. No skipping.
|
||||
|
||||
### Structure
|
||||
|
||||
- **One assertion per test** — if a test name needs "and", split it into two tests
|
||||
- **Descriptive names** — test names read as sentences describing the behavior:
|
||||
- `should return empty array when input is empty`
|
||||
- `should throw ValidationError when email format is invalid`
|
||||
- `should retry 3 times before failing on network timeout`
|
||||
- **Arrange-Act-Assert** — set up, execute, verify. Clear separation.
|
||||
|
||||
### What to Test
|
||||
|
||||
**Pure functions / business logic:**
|
||||
- Every branch (if/else, switch, ternary)
|
||||
- Every thrown error with exact error type and message
|
||||
- Return value types and shapes
|
||||
- Side effects (mutations, calls to external services)
|
||||
|
||||
**API endpoints / handlers:**
|
||||
- Success response (status code, body shape, headers)
|
||||
- Validation errors for each field (missing, wrong type, out of range)
|
||||
- Authentication/authorization failures
|
||||
- Rate limiting behavior if applicable
|
||||
- Idempotency for non-GET methods
|
||||
|
||||
**UI components (if applicable):**
|
||||
- Renders without crashing with required props
|
||||
- Renders correct content for each state (loading, error, empty, populated)
|
||||
- User interactions trigger correct callbacks (click, submit, type, select)
|
||||
- Accessibility: focusable, keyboard navigable, correct ARIA attributes
|
||||
- Conditional rendering — each branch shows/hides correct elements
|
||||
|
||||
**Database / data layer:**
|
||||
- CRUD operations return correct data
|
||||
- Unique constraints reject duplicates
|
||||
- Cascade deletes work as expected
|
||||
- Transactions roll back on failure
|
||||
|
||||
**Async operations:**
|
||||
- Successful resolution
|
||||
- Rejection / error handling
|
||||
- Timeout behavior
|
||||
- Cancellation if supported
|
||||
- Concurrent calls don't interfere
|
||||
|
||||
### Mocking Rules
|
||||
|
||||
- Prefer real implementations over mocks
|
||||
- Only mock at system boundaries: network, filesystem, clock, random
|
||||
- Never mock the code under test
|
||||
- If you mock, verify the mock was called with expected arguments
|
||||
- Reset mocks between tests — no shared state leaking
|
||||
|
||||
## Step 4: Verify
|
||||
|
||||
- Run the new tests — confirm they all pass
|
||||
- Temporarily break the code (change a return value or condition) — confirm at least one test fails
|
||||
- If no test fails when code is broken, the tests are useless — rewrite them
|
||||
- Check coverage: every new function should have at least one test, every branch should be exercised
|
||||
|
||||
## Output
|
||||
|
||||
- Complete, runnable test file(s) — not snippets
|
||||
- Tests grouped by the function/component they cover
|
||||
- A brief summary: how many tests, what scenarios covered, any gaps you couldn't cover and why
|
||||
Reference in New Issue
Block a user