From e248491a4389d02e7e7e96080b3f26d4a561cb02 Mon Sep 17 00:00:00 2001 From: Cassiano Montanari Date: Tue, 3 Mar 2026 23:40:44 +0100 Subject: [PATCH] refactor: improved generation prompt --- skills/claude-code-starter/SKILL.md | 304 -- .../references/analysis-prompt.md | 253 -- .../references/settings-patterns.md | 228 -- .../references/templates-agents.md | 154 - .../references/templates-commands.md | 222 -- .../references/templates-rules.md | 176 -- .../references/templates-skills.md | 2478 ----------------- src/cli.test.ts | 225 +- src/cli.ts | 75 +- src/generator.ts | 9 +- src/prompt.ts | 216 +- 11 files changed, 106 insertions(+), 4234 deletions(-) delete mode 100644 skills/claude-code-starter/SKILL.md delete mode 100644 skills/claude-code-starter/references/analysis-prompt.md delete mode 100644 skills/claude-code-starter/references/settings-patterns.md delete mode 100644 skills/claude-code-starter/references/templates-agents.md delete mode 100644 skills/claude-code-starter/references/templates-commands.md delete mode 100644 skills/claude-code-starter/references/templates-rules.md delete mode 100644 skills/claude-code-starter/references/templates-skills.md diff --git a/skills/claude-code-starter/SKILL.md b/skills/claude-code-starter/SKILL.md deleted file mode 100644 index b3e89b7..0000000 --- a/skills/claude-code-starter/SKILL.md +++ /dev/null @@ -1,304 +0,0 @@ ---- -name: claude-code-starter -description: > - Intelligent AI-assisted development setup that analyzes a repository's tech stack - and generates comprehensive .claude/ configuration including CLAUDE.md, skills, agents, - rules, commands, and settings.json. Use when the user wants to set up Claude Code for - a project, initialize .claude configuration, bootstrap a new project with Claude, - generate a CLAUDE.md, or run /claude-code-starter. ---- - -# Claude Code Starter - -Generate a complete `.claude/` configuration for any project by analyzing its tech stack. - -## Overview - -This skill performs 6 steps: -1. **Detect** the project's tech stack (languages, frameworks, tools) -2. **Check** for existing `.claude/` configuration -3. **Generate** `settings.json` with stack-specific permissions -4. **Generate** skills, agents, rules, and commands from templates -5. **Analyze** the codebase deeply and write `CLAUDE.md` -6. **Summarize** all files created - ---- - -## Step 1: Detect Tech Stack - -Analyze the current project root to detect languages, frameworks, and tools. - -### Languages - -Check for these files and extensions at the project root: - -| Language | Detection Files | -|----------|----------------| -| TypeScript | `tsconfig.json`, `tsconfig.base.json`, `typescript` in devDependencies, `.ts`/`.tsx` files | -| JavaScript | `package.json`, `.js`/`.mjs`/`.cjs` files (only if TypeScript not detected) | -| Python | `pyproject.toml`, `setup.py`, `requirements.txt`, `Pipfile`, `.py` files | -| Go | `go.mod`, `go.sum` | -| Rust | `Cargo.toml`, `Cargo.lock` | -| Ruby | `Gemfile`, `Gemfile.lock` | -| Java | `pom.xml`, `build.gradle`, `build.gradle.kts` | -| Kotlin | `.kt`/`.kts` files | -| C# | `.csproj`/`.sln` files | -| Swift | `Package.swift`, `.swift` files | -| PHP | `composer.json`, `.php` files | -| C/C++ | `.c`/`.cpp`/`.cc`/`.cxx`/`.h`/`.hpp` files | - -The first detected language is the **primary language**. - -### Frameworks - -**JS/TS** (from `package.json` dependencies/devDependencies, order matters — first match wins for frontend): -- Frontend (mutually exclusive, check in order): `next` -> Next.js, `nuxt`/`nuxt3` -> Nuxt, `@sveltejs/kit` -> SvelteKit, `svelte` -> Svelte, `astro` -> Astro, `@remix-run/react` -> Remix, `gatsby` -> Gatsby, `solid-js` -> Solid, `@angular/core` -> Angular, `vue` -> Vue, `react` -> React -- Backend (additive): `@nestjs/core` -> NestJS, `express` -> Express, `fastify` -> Fastify, `hono` -> Hono, `elysia` -> Elysia, `koa` -> Koa -- CSS/UI (additive): `tailwindcss` -> Tailwind, `components.json` file -> shadcn, `@chakra-ui/react` -> Chakra, `@mui/material` -> MUI -- Database/ORM (additive): `prisma`/`@prisma/client` -> Prisma, `drizzle-orm` -> Drizzle, `typeorm` -> TypeORM, `sequelize` -> Sequelize, `mongoose` -> Mongoose - -**Python** (from `requirements.txt` or `pyproject.toml`): fastapi, django, flask, starlette, sqlalchemy - -**Ruby** (from `Gemfile`): rails, sinatra - -**Go** (from `go.mod`): gin-gonic -> Gin, labstack/echo -> Echo, gofiber -> Fiber - -**Rust** (from `Cargo.toml`): actix, axum, rocket - -**Swift/iOS**: Check `Package.swift` for `vapor`. Check `.xcodeproj`/`.xcworkspace` + Swift files for SwiftUI indicators (`ContentView`, `App.swift`, `@main struct`) and UIKit indicators (`ViewController`, `AppDelegate`, `SceneDelegate`). Scan first 10 Swift files for `import SwiftData`/`@Model` and `import Combine`/`PassthroughSubject`. - -**Android/Kotlin** (from `build.gradle`/`build.gradle.kts` including `app/` variants): Check for `com.android`/`android {`, then `compose`/`androidx.compose` -> Jetpack Compose (else Android Views), `room`/`androidx.room` -> Room, `hilt`/`dagger.hilt` -> Hilt, `ktor` -> Ktor. Also check for `spring` -> Spring, `quarkus` -> Quarkus. - -### Tools - -**Package Manager** (check lock files in order): `bun.lockb`/`bun.lock` -> bun, `pnpm-lock.yaml` -> pnpm, `yarn.lock` -> yarn, `package-lock.json` -> npm, `poetry.lock` -> poetry, `Pipfile.lock`/`requirements.txt` -> pip, `Cargo.lock` -> cargo, `go.sum` -> go, `Gemfile.lock` -> bundler, `pom.xml` -> maven, `build.gradle`/`.kts` -> gradle - -**Testing** (from dependencies/config files): vitest, jest, mocha, @playwright/test, cypress, `bun test` in scripts -> bun-test, `pytest.ini`/`conftest.py` -> pytest, `go.mod` -> go-test, `Cargo.toml` -> rust-test, `Gemfile` -> rspec - -**Linter** (check config files first, then dependencies): `eslint.config.*`/`.eslintrc*` -> eslint, `biome.json`/`biome.jsonc` -> biome, `ruff.toml`/`.ruff.toml` -> ruff, `.flake8`/`setup.cfg` -> flake8 - -**Formatter**: `.prettierrc*`/`prettier.config.*` -> prettier, `biome.json`/`biome.jsonc` -> biome, `pyproject.toml` -> black - -**Bundler**: `vite.config.*` -> vite, `webpack.config.*` -> webpack, `tsup.config.*` -> tsup, `rollup.config.*` -> rollup, `esbuild*` -> esbuild; from deps: parcel, `@vercel/turbopack` -> turbopack, `@rspack/core` -> rspack - -**CI/CD**: `.github/workflows/` dir -> github-actions, `.gitlab-ci.yml` -> gitlab-ci, `.circleci/` dir -> circleci, `.travis.yml` -> travis, `azure-pipelines.yml` -> azure-devops, `Jenkinsfile` -> jenkins - -**Docker**: `Dockerfile`, `docker-compose.yml`, `docker-compose.yaml` - -**Monorepo**: `pnpm-workspace.yaml`, `lerna.json`, `nx.json`, `turbo.json`, `workspaces` in package.json, `packages/` or `apps/` directories - ---- - -## Step 2: Check Existing Configuration - -1. Check if `.claude/` directory exists -2. If it exists, ask the user: **Update** (preserve existing task state) or **Overwrite** (replace all)? -3. If `.claude/state/task.md` exists, **always preserve it** regardless of user choice - ---- - -## Step 3: Generate Settings - -Create `.claude/settings.json` using the permission patterns from [settings-patterns.md](references/settings-patterns.md). - -1. Start with **base permissions** (always included) -2. Add **language-specific** permissions for each detected language -3. Add **testing framework** permissions -4. Add **linter** and **formatter** permissions -5. Add **Docker** permissions if Docker detected -6. **Deduplicate** the final array - ---- - -## Step 4: Generate Skills, Agents, Rules, Commands - -Use the templates from the reference files to generate all applicable files. - -### Skills - -See [templates-skills.md](references/templates-skills.md) for all skill templates. - -**Always generate** (8 core skills): -- `.claude/skills/pattern-discovery.md` -- `.claude/skills/systematic-debugging.md` -- `.claude/skills/testing-methodology.md` (dynamic: uses detected testing framework) -- `.claude/skills/iterative-development.md` (dynamic: uses detected test/lint commands) -- `.claude/skills/commit-hygiene.md` -- `.claude/skills/code-deduplication.md` -- `.claude/skills/simplicity-rules.md` -- `.claude/skills/security.md` (dynamic: JS/TS and Python sections are conditional) - -**Conditionally generate** (framework skills): -- `.claude/skills/nextjs-patterns.md` (if Next.js detected) -- `.claude/skills/react-components.md` (if React detected AND Next.js NOT detected) -- `.claude/skills/fastapi-patterns.md` (if FastAPI detected) -- `.claude/skills/nestjs-patterns.md` (if NestJS detected) -- `.claude/skills/swiftui-patterns.md` (if SwiftUI detected) -- `.claude/skills/uikit-patterns.md` (if UIKit detected) -- `.claude/skills/vapor-patterns.md` (if Vapor detected) -- `.claude/skills/compose-patterns.md` (if Jetpack Compose detected) -- `.claude/skills/android-views-patterns.md` (if Android Views detected) - -### Agents - -See [templates-agents.md](references/templates-agents.md) for agent templates. - -**Always generate** (2 agents): -- `.claude/agents/code-reviewer.md` (dynamic: lint command based on detected linter) -- `.claude/agents/test-writer.md` (dynamic: test command based on detected framework) - -### Rules - -See [templates-rules.md](references/templates-rules.md) for rule templates. - -- `.claude/rules/typescript.md` (if TypeScript detected) -- `.claude/rules/python.md` (if Python detected) -- `.claude/rules/code-style.md` (always — references detected formatter/linter) - -### Commands - -See [templates-commands.md](references/templates-commands.md) for command templates. - -**Always generate** (5 commands): -- `.claude/commands/task.md` -- `.claude/commands/status.md` -- `.claude/commands/done.md` -- `.claude/commands/analyze.md` -- `.claude/commands/code-review.md` - -### State - -- Create `.claude/state/task.md` with empty initial state (**only if it does not already exist**) - ---- - -## Step 5: Deep Codebase Analysis - -Perform the full codebase analysis described in [analysis-prompt.md](references/analysis-prompt.md). - -This is the most critical step. Follow ALL phases: -1. **Phase 1: Discovery** — Read actual project files to gather specific information -2. **Phase 2: Generate** — Write `.claude/CLAUDE.md` using ONLY discovered information -3. **Phase 3: Verify** — Check quality before finalizing - -The CLAUDE.md must include the detected tech stack summary table and reference the generated skills, agents, rules, and commands in its structure. Include actual commands from `package.json` scripts (or equivalent), real file paths, and observed code conventions. - -**The CLAUDE.md MUST reference**: -- The project name and description (from package.json/README/equivalent) -- The detected tech stack with specific configuration notes -- Actual directory structure (depth 3) -- Real commands from scripts -- Code conventions observed from reading source files -- The generated skills, agents, and commands - ---- - -## Step 6: Summary - -Output a summary to the user: - -``` -## Claude Code Starter - Setup Complete - -### Tech Stack Detected -- **Language**: {primary language} -- **Framework**: {primary framework} -- **Package Manager**: {package manager} -- **Testing**: {testing framework} -- **Linter**: {linter} -- **Formatter**: {formatter} - -### Files Created -{list all files created/updated with paths} - -### Framework-Specific Skills -{list any conditional skills that were generated} - -### Next Steps -1. Review `.claude/CLAUDE.md` and adjust any inaccuracies -2. Review `.claude/settings.json` permissions -3. Try `/task ` to start your first task -4. Use `/status` to check progress -5. Use `/done` to mark tasks complete -``` - ---- - -## Dynamic Value Reference - -### Test Commands - -| Testing Framework | Package Manager | Command | -|---|---|---| -| vitest/jest | npm | `npm run test` | -| vitest/jest | bun | `bun test` | -| vitest/jest | pnpm | `pnpm test` | -| vitest/jest | yarn | `yarn test` | -| bun-test | any | `bun test` | -| pytest | any | `pytest` | -| go-test | any | `go test ./...` | -| rust-test | any | `cargo test` | -| fallback | any | `{packageManager} test` | - -### Lint Commands - -| Linter | Package Manager | Command | -|---|---|---| -| eslint | bun | `bun eslint .` | -| eslint | other | `npx eslint .` | -| biome | bun | `bun biome check .` | -| biome | other | `npx biome check .` | -| ruff | any | `ruff check .` | -| none | any | (omit) | - -### State File Initial Content - -For **existing projects** (source files detected): - -```markdown -# Current Task - -## Status: Ready - -No active task. Start one with `/task `. - -## Project Summary - -{project name}{if description: - description} - -**Tech Stack:** {summarized tech stack} - -## Quick Commands - -- `/task` - Start working on something -- `/status` - See current state -- `/analyze` - Deep dive into code -- `/done` - Mark task complete -``` - -For **new/empty projects**: - -```markdown -# Current Task - -## Status: In Progress - -**Task:** {description or "Explore and set up project"} - -## Context - -New project - setting up from scratch. - -{if framework: **Framework:** formatted name} -{if language: **Language:** formatted name} - -## Next Steps - -1. Define project structure -2. Set up development environment -3. Start implementation - -## Decisions - -(None yet - starting fresh) -``` diff --git a/skills/claude-code-starter/references/analysis-prompt.md b/skills/claude-code-starter/references/analysis-prompt.md deleted file mode 100644 index 03ce7ef..0000000 --- a/skills/claude-code-starter/references/analysis-prompt.md +++ /dev/null @@ -1,253 +0,0 @@ -# Deep Codebase Analysis Prompt - -Use this prompt to perform a comprehensive codebase analysis and generate the `.claude/CLAUDE.md` file. - ---- - -You are a senior software architect performing a comprehensive codebase analysis. -Your goal is to generate a professional `.claude/CLAUDE.md` file that gives Claude -complete context to work effectively in this project. - -**This is NOT a generic template.** Every section must contain information specific to THIS -project, discovered through actual file reading and analysis. If you cannot determine -something, omit that section entirely - do not fill in generic boilerplate. - ---- - -## Phase 1: Discovery (Read Before You Write) - -Perform these analysis steps IN ORDER. Do not skip any step. Do not start writing -the CLAUDE.md until all discovery is complete. - -### 1.1 Project Identity - -- Read `package.json`, `pyproject.toml`, `Cargo.toml`, `go.mod`, `Gemfile`, or equivalent -- Extract: project name, version, description, author, license -- Read `README.md` if it exists - extract the project's purpose in one sentence -- Check for a `docs/` folder and scan for architecture docs - -### 1.2 Directory Structure Map - -- List the top-level directories and their purposes -- Identify the source code root (`src/`, `lib/`, `app/`, `pkg/`, etc.) -- Identify test directories (`tests/`, `__tests__/`, `spec/`, `test/`, etc.) -- Identify configuration directories (`.github/`, `.vscode/`, `config/`, etc.) -- Note any monorepo structure (`packages/`, `apps/`, `services/`) -- Map the directory tree to a max depth of 3 levels (excluding `node_modules`, `.git`, `dist`, `build`, `__pycache__`, `.next`, `target`) - -### 1.3 Tech Stack Deep Scan - -Go beyond just detecting names. For each technology found, note HOW it is used: - -- **Languages**: Primary and secondary. Check config files for strictness settings -- **Frameworks**: Read the main entry point to confirm framework usage patterns -- **Package Manager**: Check lock files -- **Database**: Check for ORM configs, connection strings in env examples, database drivers -- **Authentication**: Look for auth libraries, auth middleware, session configs -- **API Layer**: REST routes, GraphQL schemas, tRPC routers, gRPC proto files -- **State Management**: Redux, Zustand, Pinia, Context API patterns -- **Styling**: CSS modules, Tailwind config, styled-components, Sass -- **Build Tools**: Check build configs -- **CI/CD**: Read workflow files -- **Infrastructure**: Docker, Terraform, Kubernetes manifests - -### 1.4 Architecture Pattern Recognition - -Read 5-10 key source files to identify: - -- **Architecture Style**: MVC, Clean Architecture, Hexagonal, Microservices, Monolith, Serverless -- **Code Organization**: Feature-based, Layer-based, Domain-based -- **Dependency Injection**: How dependencies are wired -- **Data Flow**: How data moves through the application -- **Error Handling Pattern**: How errors are caught, transformed, and reported -- **API Pattern**: RESTful conventions, GraphQL resolvers, RPC style - -### 1.5 Entry Points & Key Files - -Identify and read these critical files: - -- **Application Entry**: main.ts, index.ts, app.ts, server.ts, main.py, app.py, main.go, main.rs -- **Route/API Definitions**: Where routes/endpoints are registered -- **Configuration**: Environment loading, app config -- **Database Schema**: Models, migrations, schema definitions -- **Middleware Chain**: Authentication, logging, error handling -- **Type Definitions**: Shared types, interfaces, schemas -- **Constants**: Shared constants, status codes, error codes - -### 1.6 Code Conventions (Read Actual Code) - -Read at least 3-5 source files and document the ACTUAL patterns used: - -- **Naming**: camelCase vs snake_case, file naming, component naming -- **Imports**: Absolute vs relative, import ordering, barrel exports -- **Exports**: Default vs named exports, re-export patterns -- **Function Style**: Arrow functions vs function declarations, async/await patterns -- **Error Handling**: try/catch style, Result types, error-first callbacks -- **Type Annotations**: Explicit vs inferred, interface vs type -- **File Structure**: How individual files are organized - -### 1.7 Development Workflow - -- **Scripts**: Read all scripts from package.json or equivalent -- **Environment Variables**: Read `.env.example`, `.env.sample`, or `.env.template` - list ALL required variables -- **Pre-commit Hooks**: Check `.husky/`, `.lefthook.yml`, lint-staged config -- **Code Quality**: Linter/formatter rules and config -- **Testing Setup**: Test config files, test utilities, fixtures, mocks -- **Database Operations**: Migrations, seed data, reset commands - -### 1.8 Domain Knowledge - -- **Business Entities**: Core domain objects (User, Order, Product, etc.) -- **Key Workflows**: Main user flows -- **External Integrations**: Third-party APIs, webhooks, payment gateways -- **Background Jobs**: Queue systems, cron jobs, scheduled tasks - ---- - -## Phase 2: Generate the CLAUDE.md - -Using ONLY information discovered in Phase 1, generate the `.claude/CLAUDE.md` file. -Every section must contain PROJECT-SPECIFIC content. Skip sections that don't apply. - -### Output Structure - -The CLAUDE.md MUST follow this structure: - -```markdown -# {Project Name} - -> {One-line description from README or package.json} - -## Overview - -{2-3 sentences: what this project does, who it's for, core value proposition. -Written for an AI assistant that needs to understand PURPOSE to make good decisions.} - -## Architecture - -{Describe the actual architecture pattern found} - -### Directory Structure - -\`\`\` -{Actual directory tree, depth 3, with annotations} -\`\`\` - -### Data Flow - -{How a typical request flows through the system} - -### Key Files - -| File | Purpose | -|------|---------| -| `path/to/file` | What it does | - -## Tech Stack - -| Category | Technology | Notes | -|----------|-----------|-------| -| Language | X | Config details | -| Framework | Y | How it's used | - -## Development Setup - -### Prerequisites - -{Exact versions and tools needed} - -### Getting Started - -\`\`\`bash -{Actual commands to get running} -\`\`\` - -### Environment Variables - -| Variable | Description | Example | -|----------|-------------|---------| -| `VAR_NAME` | What it's for | `example_value` | - -## Common Commands - -\`\`\`bash -{Actual commands from package.json scripts or equivalent} -\`\`\` - -## Code Conventions - -### Naming - -{ACTUAL naming patterns found} - -### Patterns to Follow - -{3-5 patterns with file references as examples} - -### Anti-Patterns to Avoid - -{What NOT to do based on codebase conventions} - -## Testing - -### Running Tests - -\`\`\`bash -{actual test commands} -\`\`\` - -### Writing Tests - -{Testing patterns, utilities, fixtures available} - -## Domain Knowledge - -### Core Entities - -{Main domain objects and relationships} - -### Key Workflows - -{3-5 most important workflows} - -## Gotchas & Important Notes - -{3-10 non-obvious things about this project that would trip up a newcomer} - -## Rules - -1. **Read before writing** - Understand existing patterns before adding code -2. **Match conventions** - Follow the patterns documented above -3. **Test everything** - Write tests, run existing tests after changes -4. {project-specific rules discovered during analysis} -``` - ---- - -## Phase 3: Quality Checklist - -Before writing the CLAUDE.md, verify: - -- [ ] Every section contains PROJECT-SPECIFIC information (not generic boilerplate) -- [ ] File paths referenced actually exist in the project -- [ ] Commands listed are verified from package.json scripts or equivalent -- [ ] Code conventions were observed from ACTUAL source files -- [ ] The "Gotchas" section contains genuinely useful, non-obvious information -- [ ] An AI reading this CLAUDE.md could add a new feature following existing patterns -- [ ] Sections without real content have been omitted entirely - ---- - -## Important Guidelines - -1. **Be specific, not generic.** "Uses React with hooks" is useless. "Uses React 18 with Server Components via Next.js App Router, client components in src/components/client/ with 'use client' directive" is useful. - -2. **Reference real files.** Every pattern should reference an actual file as an example. Use `path/to/file.ts:lineNumber` format. - -3. **Prioritize actionable information.** Focus on what helps an AI write correct code: where to put new code, what patterns to follow, what to avoid, how to test. - -4. **Skip empty sections.** Only include sections with real content. - -5. **Keep it maintainable.** Don't include metrics that go stale quickly. - -6. **Respect existing CLAUDE.md.** If one exists, read it first and preserve manually-added sections. diff --git a/skills/claude-code-starter/references/settings-patterns.md b/skills/claude-code-starter/references/settings-patterns.md deleted file mode 100644 index cbe9fc2..0000000 --- a/skills/claude-code-starter/references/settings-patterns.md +++ /dev/null @@ -1,228 +0,0 @@ -# Settings Permission Patterns - -Permission patterns for `.claude/settings.json` generation, organized by category. - -## Settings File Format - -```json -{ - "$schema": "https://json.schemastore.org/claude-code-settings.json", - "permissions": { - "allow": [ - // permissions listed here - ] - } -} -``` - -## Base Permissions (Always Included) - -These are always added regardless of detected stack: - -```json -[ - "Read(**)", - "Edit(**)", - "Write(.claude/**)", - "Bash(git:*)", - "Bash(npm:*)", - "Bash(yarn:*)", - "Bash(pnpm:*)", - "Bash(bun:*)", - "Bash(npx:*)", - "Bash(ls:*)", - "Bash(mkdir:*)", - "Bash(cat:*)", - "Bash(echo:*)", - "Bash(grep:*)", - "Bash(find:*)" -] -``` - -## Language-Specific Permissions - -### TypeScript / JavaScript - -**Condition**: If `typescript` or `javascript` detected. - -```json -[ - "Bash(node:*)", - "Bash(tsc:*)" -] -``` - -### Python - -**Condition**: If `python` detected. - -```json -[ - "Bash(python:*)", - "Bash(pip:*)", - "Bash(poetry:*)", - "Bash(pytest:*)", - "Bash(uvicorn:*)" -] -``` - -### Go - -**Condition**: If `go` detected. - -```json -[ - "Bash(go:*)" -] -``` - -### Rust - -**Condition**: If `rust` detected. - -```json -[ - "Bash(cargo:*)", - "Bash(rustc:*)" -] -``` - -### Ruby - -**Condition**: If `ruby` detected. - -```json -[ - "Bash(ruby:*)", - "Bash(bundle:*)", - "Bash(rails:*)", - "Bash(rake:*)" -] -``` - -## Testing Framework Permissions - -Add based on detected testing framework: - -| Framework | Permissions | -|-----------|------------| -| jest | `Bash(jest:*)` | -| vitest | `Bash(vitest:*)` | -| playwright | `Bash(playwright:*)` | -| cypress | `Bash(cypress:*)` | -| pytest | `Bash(pytest:*)` | -| rspec | `Bash(rspec:*)` | - -Note: `bun-test`, `go-test`, `rust-test`, `mocha`, `unittest`, `junit` do not add extra permissions (covered by language permissions). - -## Linter Permissions - -Add based on detected linter: - -| Linter | Permission | -|--------|-----------| -| eslint | `Bash(eslint:*)` | -| biome | `Bash(biome:*)` | -| ruff | `Bash(ruff:*)` | -| flake8 | `Bash(flake8:*)` | -| pylint | `Bash(pylint:*)` | -| golangci-lint | `Bash(golangci-lint:*)` | -| clippy | `Bash(clippy:*)` | -| rubocop | `Bash(rubocop:*)` | - -## Formatter Permissions - -Add based on detected formatter: - -| Formatter | Permission | -|-----------|-----------| -| prettier | `Bash(prettier:*)` | -| biome | `Bash(biome:*)` | -| black | `Bash(black:*)` | -| ruff | `Bash(ruff:*)` | -| gofmt | `Bash(gofmt:*)` | -| rustfmt | `Bash(rustfmt:*)` | -| rubocop | `Bash(rubocop:*)` | - -Note: Deduplicate permissions if the same tool appears as both linter and formatter (e.g., biome, ruff, rubocop). - -## Docker Permissions - -**Condition**: If Docker files detected (Dockerfile, docker-compose.yml, docker-compose.yaml). - -```json -[ - "Bash(docker:*)", - "Bash(docker-compose:*)" -] -``` - -## Deduplication - -The final permissions array MUST be deduplicated. If the same permission appears from multiple sources (e.g., `Bash(ruff:*)` from both linter and formatter), include it only once. - -## Example: TypeScript + Vitest + Biome + Docker - -```json -{ - "$schema": "https://json.schemastore.org/claude-code-settings.json", - "permissions": { - "allow": [ - "Read(**)", - "Edit(**)", - "Write(.claude/**)", - "Bash(git:*)", - "Bash(npm:*)", - "Bash(yarn:*)", - "Bash(pnpm:*)", - "Bash(bun:*)", - "Bash(npx:*)", - "Bash(node:*)", - "Bash(tsc:*)", - "Bash(vitest:*)", - "Bash(biome:*)", - "Bash(docker:*)", - "Bash(docker-compose:*)", - "Bash(ls:*)", - "Bash(mkdir:*)", - "Bash(cat:*)", - "Bash(echo:*)", - "Bash(grep:*)", - "Bash(find:*)" - ] - } -} -``` - -## Example: Python + Pytest + Ruff - -```json -{ - "$schema": "https://json.schemastore.org/claude-code-settings.json", - "permissions": { - "allow": [ - "Read(**)", - "Edit(**)", - "Write(.claude/**)", - "Bash(git:*)", - "Bash(npm:*)", - "Bash(yarn:*)", - "Bash(pnpm:*)", - "Bash(bun:*)", - "Bash(npx:*)", - "Bash(python:*)", - "Bash(pip:*)", - "Bash(poetry:*)", - "Bash(pytest:*)", - "Bash(uvicorn:*)", - "Bash(ruff:*)", - "Bash(ls:*)", - "Bash(mkdir:*)", - "Bash(cat:*)", - "Bash(echo:*)", - "Bash(grep:*)", - "Bash(find:*)" - ] - } -} -``` diff --git a/skills/claude-code-starter/references/templates-agents.md b/skills/claude-code-starter/references/templates-agents.md deleted file mode 100644 index ecb0caa..0000000 --- a/skills/claude-code-starter/references/templates-agents.md +++ /dev/null @@ -1,154 +0,0 @@ -# Agent Templates - -Agent templates to generate in `.claude/agents/`. Both agents are always generated. - -## Table of Contents - -- [code-reviewer](#code-reviewer) -- [test-writer](#test-writer) - ---- - -## code-reviewer - -**File**: `.claude/agents/code-reviewer.md` - -This agent is **dynamic** — the lint command and config references adapt to the detected stack. - -### Lint Command Mapping - -| Linter | Package Manager | Lint Command | -|--------|----------------|--------------| -| eslint | bun | `bun eslint .` | -| eslint | other | `npx eslint .` | -| biome | bun | `bun biome check .` | -| biome | other | `npx biome check .` | -| ruff | any | `ruff check .` | -| none | any | (omit from tools and instructions) | - -### Config References - -Include in "Code Style Reference" section based on detected stack: -- If linter is `eslint`: reference `` `eslint.config.js` or `.eslintrc.*` `` -- If formatter is `prettier`: reference `` `.prettierrc` `` -- If language includes `typescript`: reference `` `tsconfig.json` `` -- If language includes `python`: reference `` `pyproject.toml` or `setup.cfg` `` - -### Template - -Replace `{LINT_COMMAND}` with the mapped command. If no linter, omit the `Bash(...)` tool and lint instruction. - -```markdown ---- -name: code-reviewer -description: Reviews code for quality, security issues, and best practices -tools: Read, Grep, Glob{IF_LINT:, Bash({LINT_COMMAND})} -disallowedTools: Write, Edit -model: sonnet ---- - -You are a senior code reviewer with expertise in security and performance. - -## Code Style Reference - -Read these files to understand project conventions: -{IF eslint: - `eslint.config.js` or `.eslintrc.*`} -{IF prettier: - `.prettierrc`} -{IF typescript: - `tsconfig.json`} -{IF python: - `pyproject.toml` or `setup.cfg`} - -{IF LINT_COMMAND: Run `{LINT_COMMAND}` to check violations programmatically.} - -## Review Process - -1. Run `git diff` to identify changed files -2. Analyze each change for: - - Security vulnerabilities (OWASP Top 10) - - Performance issues - - Code style violations - - Missing error handling - - Test coverage gaps - -## Output Format - -For each finding: - -- **Critical**: Must fix before merge -- **Warning**: Should address -- **Suggestion**: Consider improving - -Include file:line references for each issue. -``` - ---- - -## test-writer - -**File**: `.claude/agents/test-writer.md` - -This agent is **dynamic** — the test command and framework name adapt to the detected stack. - -### Test Command Mapping - -| Testing Framework | Package Manager | Test Command | -|---|---|---| -| vitest | npm | `npm run test` | -| vitest | bun/pnpm/yarn | `{pm} test` | -| jest | npm | `npm run test` | -| jest | bun/pnpm/yarn | `{pm} test` | -| bun-test | any | `bun test` | -| pytest | any | `pytest` | -| go-test | any | `go test ./...` | -| rust-test | any | `cargo test` | -| default | any | `{pm} test` | - -### Template - -Replace `{TEST_COMMAND}` and `{TESTING_FRAMEWORK}` with detected values. - -```markdown ---- -name: test-writer -description: Generates comprehensive tests for code -tools: Read, Grep, Glob, Write, Edit, Bash({TEST_COMMAND}) -model: sonnet ---- - -You are a testing expert who writes thorough, maintainable tests. - -## Testing Framework - -This project uses: **{TESTING_FRAMEWORK}** - -## Your Process - -1. Read the code to be tested -2. Identify test cases: - - Happy path scenarios - - Edge cases - - Error conditions - - Boundary values -3. Write tests following project patterns -4. Run tests to verify they pass - -## Test Structure - -Follow the AAA pattern: -- **Arrange**: Set up test data -- **Act**: Execute the code -- **Assert**: Verify results - -## Guidelines - -- One assertion focus per test -- Descriptive test names -- Mock external dependencies -- Don't test implementation details -- Aim for behavior coverage - -## Run Tests - -```bash -{TEST_COMMAND} -``` -``` diff --git a/skills/claude-code-starter/references/templates-commands.md b/skills/claude-code-starter/references/templates-commands.md deleted file mode 100644 index 5267406..0000000 --- a/skills/claude-code-starter/references/templates-commands.md +++ /dev/null @@ -1,222 +0,0 @@ -# Command Templates - -Command templates to generate in `.claude/commands/`. All 5 commands are always generated. - -## Table of Contents - -- [/task](#task) -- [/status](#status) -- [/done](#done) -- [/analyze](#analyze) -- [/code-review](#code-review) - ---- - -## task - -**File**: `.claude/commands/task.md` - -```markdown ---- -allowed-tools: Read, Write, Edit, Glob, Grep -argument-hint: [task description] -description: Start or switch to a new task ---- - -# Start Task - -## Current State -!cat .claude/state/task.md 2>/dev/null || echo "No existing task" - -## Your Task - -Start or switch to the task: **$ARGUMENTS** - -1. Read current state from `.claude/state/task.md` -2. If switching tasks, summarize previous progress -3. Update `.claude/state/task.md` with: - - Status: In Progress - - Task description - - Initial context/understanding - - Planned next steps - -4. Begin working on the task -``` - ---- - -## status - -**File**: `.claude/commands/status.md` - -```markdown ---- -allowed-tools: Read, Glob -description: Show current task and session state ---- - -# Status Check - -## Current Task State -!cat .claude/state/task.md 2>/dev/null || echo "No task in progress" - -## Your Response - -Provide a concise status update: - -1. **Current Task**: What are you working on? -2. **Progress**: What's been completed? -3. **Blockers**: Any issues or questions? -4. **Next Steps**: What's coming up? - -Keep it brief - this is a quick check-in. -``` - ---- - -## done - -**File**: `.claude/commands/done.md` - -```markdown ---- -allowed-tools: Read, Write, Edit, Glob, Bash(git diff), Bash(git status) -description: Mark current task complete ---- - -# Complete Task - -## Current State -!cat .claude/state/task.md - -## Completion Checklist - -Before marking complete, verify: - -1. [ ] All requirements met -2. [ ] Tests pass (if applicable) -3. [ ] No linting errors -4. [ ] Code reviewed for quality - -## Your Task - -1. Run final checks (tests, lint) -2. Update `.claude/state/task.md`: - - Status: **Completed** - - Summary of what was done - - Files changed - - Any follow-up items - -3. Show git status/diff for review -``` - ---- - -## analyze - -**File**: `.claude/commands/analyze.md` - -```markdown ---- -allowed-tools: Read, Glob, Grep -argument-hint: [area to analyze] -description: Deep analysis of a specific area ---- - -# Analyze: $ARGUMENTS - -## Analysis Scope - -Perform deep analysis of: **$ARGUMENTS** - -## Process - -1. **Locate relevant files** using Glob and Grep -2. **Read and understand** the code structure -3. **Identify patterns** and conventions -4. **Document findings** with file:line references - -## Output Format - -### Overview -Brief description of what this area does. - -### Key Files -- `path/to/file.ts:10` - Purpose - -### Patterns Found -- Pattern 1: Description -- Pattern 2: Description - -### Dependencies -What this area depends on and what depends on it. - -### Recommendations -Any improvements or concerns noted. -``` - ---- - -## code-review - -**File**: `.claude/commands/code-review.md` - -```markdown ---- -allowed-tools: Read, Glob, Grep, Bash(git diff), Bash(git status), Bash(git log) -description: Review code changes for quality, security, and best practices ---- - -# Code Review - -## Changes to Review - -!git diff --stat HEAD~1 2>/dev/null || git diff --stat - -## Review Process - -Analyze all changes for: - -### 1. Security (Critical) -- [ ] No secrets/credentials in code -- [ ] Input validation present -- [ ] Output encoding where needed -- [ ] Auth/authz checks on protected routes - -### 2. Quality -- [ ] Functions ≤ 20 lines -- [ ] Files ≤ 200 lines -- [ ] No code duplication -- [ ] Clear naming -- [ ] Proper error handling - -### 3. Testing -- [ ] Tests exist for new code -- [ ] Edge cases covered -- [ ] Tests are meaningful (not just for coverage) - -### 4. Style -- [ ] Matches existing patterns -- [ ] Consistent formatting -- [ ] No commented-out code - -## Output Format - -For each finding, include file:line reference: - -### Critical (Must Fix) -Issues that block merge - -### Warning (Should Fix) -Issues that should be addressed - -### Suggestion (Consider) -Optional improvements - -## Summary - -Provide: -1. Overall assessment (Ready / Changes Needed / Not Ready) -2. Count of findings by severity -3. Top priorities to address -``` diff --git a/skills/claude-code-starter/references/templates-rules.md b/skills/claude-code-starter/references/templates-rules.md deleted file mode 100644 index 67c2026..0000000 --- a/skills/claude-code-starter/references/templates-rules.md +++ /dev/null @@ -1,176 +0,0 @@ -# Rule Templates - -Rule templates to generate in `.claude/rules/`. - -## Table of Contents - -- [TypeScript Rules (Conditional)](#typescript-rules) -- [Python Rules (Conditional)](#python-rules) -- [Code Style Rules (Always)](#code-style-rules) - ---- - -## TypeScript Rules - -**Condition**: Generate if `typescript` language detected. - -**File**: `.claude/rules/typescript.md` - -```markdown ---- -paths: - - "**/*.ts" - - "**/*.tsx" ---- - -# TypeScript Rules - -## Type Safety - -- Avoid `any` - use `unknown` and narrow types -- Prefer interfaces for objects, types for unions/intersections -- Use strict mode (`strict: true` in tsconfig) -- Enable `noUncheckedIndexedAccess` for safer array access - -## Patterns - -```typescript -// Prefer -const user: User | undefined = users.find(u => u.id === id); -if (user) { /* use user */ } - -// Avoid -const user = users.find(u => u.id === id) as User; -``` - -## Naming - -- Interfaces: PascalCase (e.g., `UserProfile`) -- Types: PascalCase (e.g., `ApiResponse`) -- Functions: camelCase (e.g., `getUserById`) -- Constants: SCREAMING_SNAKE_CASE for true constants - -## Imports - -- Group imports: external, internal, relative -- Use path aliases when configured -- Prefer named exports over default exports -``` - ---- - -## Python Rules - -**Condition**: Generate if `python` language detected. - -**File**: `.claude/rules/python.md` - -```markdown ---- -paths: - - "**/*.py" ---- - -# Python Rules - -## Style - -- Follow PEP 8 -- Use type hints for function signatures -- Docstrings for public functions (Google style) -- Max line length: 88 (Black default) - -## Patterns - -```python -# Prefer -def get_user(user_id: int) -> User | None: - """Fetch user by ID. - - Args: - user_id: The user's unique identifier. - - Returns: - User object if found, None otherwise. - """ - return db.query(User).filter(User.id == user_id).first() - -# Avoid -def get_user(id): - return db.query(User).filter(User.id == id).first() -``` - -## Naming - -- Functions/variables: snake_case -- Classes: PascalCase -- Constants: SCREAMING_SNAKE_CASE -- Private: _leading_underscore - -## Imports - -```python -# Standard library -import os -from pathlib import Path - -# Third-party -from fastapi import FastAPI -from pydantic import BaseModel - -# Local -from app.models import User -from app.services import UserService -``` -``` - ---- - -## Code Style Rules - -**Condition**: Always generate. - -**File**: `.claude/rules/code-style.md` - -This rule is **dynamic** — it references the detected formatter and linter. - -### Template - -Replace `{FORMATTER}` and `{LINTER}` with detected values. If none detected, use the generic fallback text. - -```markdown -# Code Style - -## General Principles - -1. **Clarity over cleverness** - Code is read more than written -2. **Consistency** - Match existing patterns in the codebase -3. **Simplicity** - Prefer simple solutions over complex ones - -## Formatting - -{IF FORMATTER: This project uses **{FORMATTER}** for formatting. Run it before committing.} -{IF NO FORMATTER: Format code consistently with the existing codebase.} - -{IF LINTER: This project uses **{LINTER}** for linting. Fix all warnings.} - -## Comments - -- Write self-documenting code first -- Comment the "why", not the "what" -- Keep comments up to date with code changes -- Use TODO/FIXME with context - -## Error Handling - -- Handle errors at appropriate boundaries -- Provide meaningful error messages -- Log errors with context -- Don't swallow errors silently - -## Git Commits - -- Write clear, concise commit messages -- Use conventional commits format when applicable -- Keep commits focused and atomic -``` diff --git a/skills/claude-code-starter/references/templates-skills.md b/skills/claude-code-starter/references/templates-skills.md deleted file mode 100644 index 63b1536..0000000 --- a/skills/claude-code-starter/references/templates-skills.md +++ /dev/null @@ -1,2478 +0,0 @@ -# Skill Templates - -All skill templates to generate in `.claude/skills/`. Each section is a complete skill file. - -## Table of Contents - -- [Core Skills (Always Generate)](#core-skills-always-generate) - - [pattern-discovery](#pattern-discovery) - - [systematic-debugging](#systematic-debugging) - - [testing-methodology](#testing-methodology) - - [iterative-development](#iterative-development) - - [commit-hygiene](#commit-hygiene) - - [code-deduplication](#code-deduplication) - - [simplicity-rules](#simplicity-rules) - - [security](#security) -- [Framework Skills (Conditional)](#framework-skills-conditional) - - [nextjs-patterns](#nextjs-patterns) - - [react-components](#react-components) - - [fastapi-patterns](#fastapi-patterns) - - [nestjs-patterns](#nestjs-patterns) - - [swiftui-patterns](#swiftui-patterns) - - [uikit-patterns](#uikit-patterns) - - [vapor-patterns](#vapor-patterns) - - [compose-patterns](#compose-patterns) - - [android-views-patterns](#android-views-patterns) - ---- - -## Core Skills (Always Generate) - -### pattern-discovery - -**File**: `.claude/skills/pattern-discovery.md` - -```markdown ---- -name: pattern-discovery -description: Analyze existing codebase to discover and document patterns -globs: - - "src/**/*" - - "lib/**/*" - - "app/**/*" - - "components/**/*" - - "pages/**/*" - - "api/**/*" - - "services/**/*" ---- - -# Pattern Discovery - -When starting work on a project, analyze the existing code to understand its patterns. - -## Discovery Process - -### 1. Check for Existing Documentation - -``` -Look for: -- README.md, CONTRIBUTING.md -- docs/ folder -- Code comments and JSDoc/TSDoc -- .editorconfig, .prettierrc, eslint config -``` - -### 2. Analyze Project Structure - -``` -Questions to answer: -- How are files organized? (by feature, by type, flat?) -- Where does business logic live? -- Where are tests located? -- How are configs managed? -``` - -### 3. Detect Code Patterns - -``` -Look at 3-5 similar files to find: -- Naming conventions (camelCase, snake_case, PascalCase) -- Import organization (grouped? sorted? relative vs absolute?) -- Export style (named, default, barrel files?) -- Error handling approach -- Logging patterns -``` - -### 4. Identify Architecture - -``` -Common patterns to detect: -- MVC / MVVM / Clean Architecture -- Repository pattern -- Service layer -- Dependency injection -- Event-driven -- Functional vs OOP -``` - -## When No Code Exists - -If starting a new project: - -1. Ask about preferred patterns -2. Check package.json/config files for framework hints -3. Use sensible defaults for detected stack -4. Document decisions in `.claude/state/task.md` - -## Important - -- **Match existing patterns** - don't impose new ones -- **When in doubt, check similar files** in the codebase -- **Document as you discover** - note patterns in task state -- **Ask if unclear** - better to ask than assume -``` - ---- - -### systematic-debugging - -**File**: `.claude/skills/systematic-debugging.md` - -```markdown ---- -name: systematic-debugging -description: Methodical approach to finding and fixing bugs -globs: - - "**/*.ts" - - "**/*.tsx" - - "**/*.js" - - "**/*.jsx" - - "**/*.py" - - "**/*.go" - - "**/*.rs" ---- - -# Systematic Debugging - -A 4-phase methodology for finding and fixing bugs efficiently. - -## Phase 1: Reproduce - -Before fixing, confirm you can reproduce the bug. - -``` -1. Get exact steps to reproduce -2. Identify expected vs actual behavior -3. Note any error messages verbatim -4. Check if it's consistent or intermittent -``` - -## Phase 2: Locate - -Narrow down where the bug occurs. - -``` -Techniques: -- Binary search through code flow -- Add logging at key points -- Check recent changes (git log, git diff) -- Review stack traces carefully -- Use debugger breakpoints -``` - -## Phase 3: Diagnose - -Understand WHY the bug happens. - -``` -Questions: -- What assumptions are being violated? -- What state is unexpected? -- Is this a logic error, data error, or timing issue? -- Are there edge cases not handled? -``` - -## Phase 4: Fix - -Apply the minimal correct fix. - -``` -Guidelines: -- Fix the root cause, not symptoms -- Make the smallest change that fixes the issue -- Add a test that would have caught this bug -- Check for similar bugs elsewhere -- Update documentation if needed -``` - -## Quick Reference - -| Symptom | Check First | -|---------|-------------| -| TypeError | Null/undefined values, type mismatches | -| Off-by-one | Loop bounds, array indices | -| Race condition | Async operations, shared state | -| Memory leak | Event listeners, subscriptions, closures | -| Infinite loop | Exit conditions, recursive calls | -``` - ---- - -### testing-methodology - -**File**: `.claude/skills/testing-methodology.md` - -This skill is **dynamic** — it adapts to the detected testing framework. - -**Template** (replace `{TESTING_FRAMEWORK}` and `{TESTING_EXAMPLES}`): - -```markdown ---- -name: testing-methodology -description: Testing patterns and best practices for this project -globs: - - "**/*.test.*" - - "**/*.spec.*" - - "**/test/**" - - "**/tests/**" - - "**/__tests__/**" ---- - -# Testing Methodology - -## Testing Framework - -This project uses: **{TESTING_FRAMEWORK}** - -## The AAA Pattern - -Structure every test with: - -``` -Arrange - Set up test data and conditions -Act - Execute the code being tested -Assert - Verify the expected outcome -``` - -## What to Test - -### Must Test -- Core business logic -- Edge cases and boundaries -- Error handling paths -- Public API contracts - -### Consider Testing -- Integration points -- Complex conditional logic -- State transitions - -### Skip Testing -- Framework internals -- Simple getters/setters -- Configuration constants - -## Example Patterns - -{TESTING_EXAMPLES} - -## Test Naming - -``` -Format: [unit]_[scenario]_[expected result] - -Examples: -- calculateTotal_withEmptyCart_returnsZero -- userService_createUser_savesToDatabase -- parseDate_invalidFormat_throwsError -``` - -## Mocking Guidelines - -1. **Mock external dependencies** - APIs, databases, file system -2. **Don't mock what you own** - Prefer real implementations for your code -3. **Keep mocks simple** - Complex mocks often indicate design issues -4. **Reset mocks between tests** - Avoid state leakage - -## Coverage Philosophy - -- Aim for **80%+ coverage** on critical paths -- Don't chase 100% - it often leads to brittle tests -- Focus on **behavior coverage**, not line coverage -``` - -#### Testing Examples by Framework - -**vitest / jest**: -```typescript -import { describe, it, expect } from '{FRAMEWORK}'; - -describe('UserService', () => { - it('should create user with valid data', async () => { - // Arrange - const userData = { name: 'Test', email: 'test@example.com' }; - - // Act - const user = await userService.create(userData); - - // Assert - expect(user.id).toBeDefined(); - expect(user.name).toBe('Test'); - }); - - it('should throw on invalid email', async () => { - // Arrange - const userData = { name: 'Test', email: 'invalid' }; - - // Act & Assert - await expect(userService.create(userData)).rejects.toThrow('Invalid email'); - }); -}); -``` - -**pytest**: -```python -import pytest -from myapp.services import UserService - -class TestUserService: - def test_create_user_with_valid_data(self, db_session): - # Arrange - user_data = {"name": "Test", "email": "test@example.com"} - service = UserService(db_session) - - # Act - user = service.create(user_data) - - # Assert - assert user.id is not None - assert user.name == "Test" - - def test_create_user_invalid_email_raises(self, db_session): - # Arrange - user_data = {"name": "Test", "email": "invalid"} - service = UserService(db_session) - - # Act & Assert - with pytest.raises(ValueError, match="Invalid email"): - service.create(user_data) -``` - -**go-test**: -```go -func TestUserService_Create(t *testing.T) { - t.Run("creates user with valid data", func(t *testing.T) { - // Arrange - svc := NewUserService(mockDB) - userData := UserInput{Name: "Test", Email: "test@example.com"} - - // Act - user, err := svc.Create(userData) - - // Assert - assert.NoError(t, err) - assert.NotEmpty(t, user.ID) - assert.Equal(t, "Test", user.Name) - }) - - t.Run("returns error on invalid email", func(t *testing.T) { - // Arrange - svc := NewUserService(mockDB) - userData := UserInput{Name: "Test", Email: "invalid"} - - // Act - _, err := svc.Create(userData) - - // Assert - assert.ErrorContains(t, err, "invalid email") - }) -} -``` - -**bun-test**: -```typescript -import { describe, it, expect } from 'bun:test'; -// Same pattern as vitest/jest examples above -``` - -**Generic fallback**: -``` -// Add examples for your testing framework here -describe('Component', () => { - it('should behave correctly', () => { - // Arrange - set up test conditions - // Act - execute the code - // Assert - verify results - }); -}); -``` - ---- - -### iterative-development - -**File**: `.claude/skills/iterative-development.md` - -This skill is **dynamic** — it adapts to the detected test and lint commands. - -**Template** (replace `{TEST_CMD}` and `{LINT_CMD}`): - -The test command is determined by: -| Testing Framework | Package Manager | Command | -|---|---|---| -| vitest | npm | `npm run test` | -| vitest | bun/pnpm/yarn | `{pm} test` | -| jest | npm | `npm run test` | -| jest | bun/pnpm/yarn | `{pm} test` | -| bun-test | any | `bun test` | -| pytest | any | `pytest` | -| go-test | any | `go test ./...` | -| rust-test | any | `cargo test` | -| default | any | `{pm} test` | - -The lint command is determined by: -| Linter | Package Manager | Command | -|---|---|---| -| eslint | bun | `bun eslint .` | -| eslint | other | `npx eslint .` | -| biome | bun | `bun biome check .` | -| biome | other | `npx biome check .` | -| ruff | any | `ruff check .` | -| none | any | (omit lint step) | - -```markdown ---- -name: iterative-development -description: TDD-driven iterative loops until tests pass -globs: - - "**/*.ts" - - "**/*.tsx" - - "**/*.js" - - "**/*.py" - - "**/*.go" ---- - -# Iterative Development (TDD Loops) - -Self-referential development loops where you iterate until completion criteria are met. - -## Core Philosophy - -``` -┌─────────────────────────────────────────────────────────────┐ -│ ITERATION > PERFECTION │ -│ Don't aim for perfect on first try. │ -│ Let the loop refine the work. │ -├─────────────────────────────────────────────────────────────┤ -│ FAILURES ARE DATA │ -│ Failed tests, lint errors, type mismatches are signals. │ -│ Use them to guide the next iteration. │ -├─────────────────────────────────────────────────────────────┤ -│ CLEAR COMPLETION CRITERIA │ -│ Define exactly what "done" looks like. │ -│ Tests passing. Coverage met. Lint clean. │ -└─────────────────────────────────────────────────────────────┘ -``` - -## TDD Workflow (Mandatory) - -Every implementation task MUST follow this workflow: - -### 1. RED: Write Tests First -```bash -# Write tests based on requirements -# Run tests - they MUST FAIL -{TEST_CMD} -``` - -### 2. GREEN: Implement Feature -```bash -# Write minimum code to pass tests -# Run tests - they MUST PASS -{TEST_CMD} -``` - -### 3. VALIDATE: Quality Gates -```bash -# Full quality check -{LINT_CMD}{TEST_CMD} -``` - -## Completion Criteria Template - -For any implementation task, define: - -```markdown -### Completion Criteria -- [ ] All tests passing -- [ ] Coverage >= 80% (on new code) -- [ ] Lint clean (no errors) -- [ ] Type check passing -``` - -## When to Use This Workflow - -| Task Type | Use TDD Loop? | -|-----------|---------------| -| New feature | ✅ Always | -| Bug fix | ✅ Always (write test that reproduces bug first) | -| Refactoring | ✅ Always (existing tests must stay green) | -| Spike/exploration | ❌ Skip (but document findings) | -| Documentation | ❌ Skip | - -## Anti-Patterns - -- ❌ Writing code before tests -- ❌ Skipping the RED phase (tests that never fail are useless) -- ❌ Moving on when tests fail -- ❌ Large batches (prefer small, focused iterations) -``` - ---- - -### commit-hygiene - -**File**: `.claude/skills/commit-hygiene.md` - -```markdown ---- -name: commit-hygiene -description: Atomic commits, PR size limits, commit thresholds -globs: - - "**/*" ---- - -# Commit Hygiene - -Keep commits atomic, PRs reviewable, and git history clean. - -## Size Thresholds - -| Metric | 🟢 Good | 🟡 Warning | 🔴 Commit Now | -|--------|------|---------|------------| -| Files changed | 1-5 | 6-10 | > 10 | -| Lines added | < 150 | 150-300 | > 300 | -| Total changes | < 250 | 250-400 | > 400 | - -**Research shows:** PRs > 400 lines have 40%+ defect rates vs 15% for smaller changes. - -## When to Commit - -### Commit Triggers (Any = Commit) - -| Trigger | Action | -|---------|--------| -| Test passes | Just got a test green → commit | -| Feature complete | Finished a function → commit | -| Refactor done | Renamed across files → commit | -| Bug fixed | Fixed the issue → commit | -| Threshold hit | > 5 files or > 200 lines → commit | - -### Commit Immediately If - -- ✅ Tests are passing after being red -- ✅ You're about to make a "big change" -- ✅ You've been coding for 30+ minutes -- ✅ You're about to try something risky -- ✅ The current state is "working" - -## Atomic Commit Patterns - -### Good Commits ✅ - -``` -"Add email validation to signup form" -- 3 files: validator.ts, signup.tsx, signup.test.ts -- 120 lines changed -- Single purpose: email validation - -"Fix null pointer in user lookup" -- 2 files: userService.ts, userService.test.ts -- 25 lines changed -- Single purpose: fix one bug -``` - -### Bad Commits ❌ - -``` -"Add authentication, fix bugs, update styles" -- 25 files changed, 800 lines -- Multiple unrelated purposes - -"WIP" / "Updates" / "Fix stuff" -- Unknown scope, no clear purpose -``` - -## Quick Status Check - -Run frequently to check current state: - -```bash -# See what's changed -git status --short - -# Count changes -git diff --shortstat - -# Full summary -git diff --stat HEAD -``` - -## PR Size Rules - -| PR Size | Review Time | Quality | -|---------|-------------|---------| -| < 200 lines | < 30 min | High confidence | -| 200-400 lines | 30-60 min | Good confidence | -| 400-1000 lines | 1-2 hours | Declining quality | -| > 1000 lines | Often skipped | Rubber-stamped | - -**Best practice:** If a PR will be > 400 lines, split into stacked PRs. -``` - ---- - -### code-deduplication - -**File**: `.claude/skills/code-deduplication.md` - -```markdown ---- -name: code-deduplication -description: Prevent semantic code duplication with capability index -globs: - - "**/*.ts" - - "**/*.tsx" - - "**/*.js" - - "**/*.py" ---- - -# Code Deduplication - -Prevent semantic duplication by maintaining awareness of existing capabilities. - -## Core Principle - -``` -┌─────────────────────────────────────────────────────────────────┐ -│ CHECK BEFORE YOU WRITE │ -│ ───────────────────────────────────────────────────────────── │ -│ AI doesn't copy/paste - it reimplements. │ -│ The problem isn't duplicate code, it's duplicate PURPOSE. │ -│ │ -│ Before writing ANY new function: │ -│ 1. Search codebase for similar functionality │ -│ 2. Check utils/, helpers/, lib/ for existing implementations │ -│ 3. Extend existing code if possible │ -│ 4. Only create new if nothing suitable exists │ -└─────────────────────────────────────────────────────────────────┘ -``` - -## Before Writing New Code - -### Search Checklist - -1. **Search by purpose**: "format date", "validate email", "fetch user" -2. **Search common locations**: - - `src/utils/` or `lib/` - - `src/helpers/` - - `src/common/` - - `src/shared/` -3. **Search by function signature**: Similar inputs/outputs - -### Common Duplicate Candidates - -| Category | Look For | -|----------|----------| -| Date/Time | formatDate, parseDate, isExpired, addDays | -| Validation | isEmail, isPhone, isURL, isUUID | -| Strings | slugify, truncate, capitalize, pluralize | -| API | fetchUser, createItem, handleError | -| Auth | validateToken, requireAuth, getCurrentUser | - -## If Similar Code Exists - -### Option 1: Reuse directly -```typescript -// Import and use existing function -import { formatDate } from '@/utils/dates'; -``` - -### Option 2: Extend with options -```typescript -// Add optional parameter to existing function -export function formatDate( - date: Date, - format: string = 'short', - locale?: string // NEW: added locale support -): string { ... } -``` - -### Option 3: Compose from existing -```typescript -// Build on existing utilities -export function formatDateRange(start: Date, end: Date) { - return `${formatDate(start)} - ${formatDate(end)}`; -} -``` - -## File Header Pattern - -Document what each file provides: - -```typescript -/** - * @file User validation utilities - * @description Email, phone, and identity validation functions. - * - * Key exports: - * - isEmail(email) - Validates email format - * - isPhone(phone, country?) - Validates phone with country - * - isValidUsername(username) - Checks username rules - */ -``` - -## Anti-Patterns - -- ❌ Writing date formatter without checking utils/ -- ❌ Creating new API client when one exists -- ❌ Duplicating validation logic across files -- ❌ Copy-pasting functions between files -- ❌ "I'll refactor later" (you won't) -``` - ---- - -### simplicity-rules - -**File**: `.claude/skills/simplicity-rules.md` - -```markdown ---- -name: simplicity-rules -description: Enforced code complexity constraints -globs: - - "**/*.ts" - - "**/*.tsx" - - "**/*.js" - - "**/*.py" - - "**/*.go" ---- - -# Simplicity Rules - -Complexity is the enemy. Every line of code is a liability. - -## Enforced Limits - -**CRITICAL: These limits are non-negotiable. Check and enforce for EVERY file.** - -### Function Level - -| Constraint | Limit | Action if Exceeded | -|------------|-------|-------------------| -| Lines per function | 20 max | Decompose immediately | -| Parameters | 3 max | Use options object | -| Nesting levels | 2 max | Flatten with early returns | - -### File Level - -| Constraint | Limit | Action if Exceeded | -|------------|-------|-------------------| -| Lines per file | 200 max | Split by responsibility | -| Functions per file | 10 max | Split into modules | - -### Module Level - -| Constraint | Limit | Reason | -|------------|-------|--------| -| Directory nesting | 3 levels max | Flat is better | -| Circular deps | 0 | Never acceptable | - -## Enforcement Protocol - -**Before completing ANY file:** - -``` -1. Count total lines → if > 200, STOP and split -2. Count functions → if > 10, STOP and split -3. Check function length → if any > 20 lines, decompose -4. Check parameters → if any > 3, refactor to options object -``` - -## Violation Response - -When limits are exceeded: - -``` -⚠️ FILE SIZE VIOLATION DETECTED - -[filename] has [X] lines (limit: 200) - -Splitting into: -- [filename-a].ts - [responsibility A] -- [filename-b].ts - [responsibility B] -``` - -**Never defer refactoring.** Fix violations immediately. - -## Decomposition Patterns - -### Long Function → Multiple Functions - -```typescript -// BEFORE: 40 lines -function processOrder(order) { - // validate... 10 lines - // calculate totals... 15 lines - // apply discounts... 10 lines - // save... 5 lines -} - -// AFTER: 4 functions, each < 15 lines -function processOrder(order) { - validateOrder(order); - const totals = calculateTotals(order); - const finalPrice = applyDiscounts(totals, order.coupons); - return saveOrder({ ...order, finalPrice }); -} -``` - -### Many Parameters → Options Object - -```typescript -// BEFORE: 6 parameters -function createUser(name, email, password, role, team, settings) { } - -// AFTER: 1 options object -interface CreateUserOptions { - name: string; - email: string; - password: string; - role?: string; - team?: string; - settings?: UserSettings; -} -function createUser(options: CreateUserOptions) { } -``` - -### Deep Nesting → Early Returns - -```typescript -// BEFORE: 4 levels deep -function process(data) { - if (data) { - if (data.valid) { - if (data.items) { - for (const item of data.items) { - // actual logic here - } - } - } - } -} - -// AFTER: 1 level deep -function process(data) { - if (!data?.valid || !data.items) return; - - for (const item of data.items) { - // actual logic here - } -} -``` - -## Anti-Patterns - -- ❌ God objects/files (do everything) -- ❌ "Just one more line" (compound violations) -- ❌ "I'll split it later" (you won't) -- ❌ Deep inheritance hierarchies -- ❌ Complex conditionals without extraction -``` - ---- - -### security - -**File**: `.claude/skills/security.md` - -This skill is **dynamic** — it adapts based on detected languages (JS/TS and Python sections are conditional). - -**Template** (include JS/TS sections if `typescript` or `javascript` detected, Python sections if `python` detected): - -```markdown ---- -name: security -description: Security best practices, secrets management, OWASP patterns -globs: - - "**/*" ---- - -# Security Best Practices - -Security is not optional. Every project must pass security checks. - -## Required .gitignore Entries - -**NEVER commit these:** - -```gitignore -# Environment files -.env -.env.* -!.env.example - -# Secrets and credentials -*.pem -*.key -*.p12 -credentials.json -secrets.json -*-credentials.json -service-account*.json - -# IDE secrets -.idea/ -.vscode/settings.json -``` - -## Environment Variables - -### Create .env.example - -Document required vars without values: - -```bash -# Server-side only (never expose to client) -DATABASE_URL= -API_SECRET_KEY= -ANTHROPIC_API_KEY= - -# Client-side safe (public, non-sensitive) -{JS: VITE_API_URL=\nNEXT_PUBLIC_SITE_URL=} -{Python: API_BASE_URL=} -``` - -{IF JS/TS: Include this section} -### Frontend Exposure Rules - -| Framework | Client-Exposed Prefix | Server-Only | -|-----------|----------------------|-------------| -| Vite | `VITE_*` | No prefix | -| Next.js | `NEXT_PUBLIC_*` | No prefix | -| CRA | `REACT_APP_*` | N/A | - -**CRITICAL:** Never put secrets in client-exposed env vars! - -```typescript -// ❌ WRONG - Secret exposed to browser -const key = import.meta.env.VITE_API_SECRET; - -// ✅ CORRECT - Secret stays server-side -const key = process.env.API_SECRET; // in API route only -``` -{END IF} - -### Validate at Startup - -{IF JS/TS:} -```typescript -import { z } from 'zod'; - -const envSchema = z.object({ - DATABASE_URL: z.string().url(), - API_SECRET_KEY: z.string().min(32), - NODE_ENV: z.enum(['development', 'production', 'test']), -}); - -export const env = envSchema.parse(process.env); -``` -{END IF} - -{IF Python:} -```python -from pydantic_settings import BaseSettings - -class Settings(BaseSettings): - database_url: str - api_secret_key: str - environment: str = "development" - - class Config: - env_file = ".env" - -settings = Settings() -``` -{END IF} - -## OWASP Top 10 Checklist - -| Vulnerability | Prevention | -|---------------|------------| -| Injection (SQL, NoSQL, Command) | Parameterized queries, input validation | -| Broken Auth | Secure session management, MFA | -| Sensitive Data Exposure | Encryption at rest and in transit | -| XXE | Disable external entity processing | -| Broken Access Control | Verify permissions on every request | -| Security Misconfiguration | Secure defaults, minimal permissions | -| XSS | Output encoding, CSP headers | -| Insecure Deserialization | Validate all serialized data | -| Using Vulnerable Components | Keep dependencies updated | -| Insufficient Logging | Log security events, monitor | - -## Input Validation - -``` -RULE: Never trust user input. Validate everything. - -- Validate type, length, format, range -- Sanitize before storage -- Encode before output -- Use allowlists over denylists -``` - -## Secrets Detection - -Before committing, check for: - -- API keys (usually 32+ chars, specific patterns) -- Passwords in code -- Connection strings with credentials -- Private keys (BEGIN RSA/EC/PRIVATE KEY) -- Tokens (jwt, bearer, oauth) - -## Security Review Checklist - -Before PR merge: - -- [ ] No secrets in code or config -- [ ] Input validation on all user data -- [ ] Output encoding where displayed -- [ ] Authentication checked on protected routes -- [ ] Authorization verified for resources -- [ ] Dependencies scanned for vulnerabilities -- [ ] Error messages don't leak internals -``` - ---- - -## Framework Skills (Conditional) - -### nextjs-patterns - -**Condition**: Generate if `nextjs` framework detected. - -**File**: `.claude/skills/nextjs-patterns.md` - -```markdown ---- -name: nextjs-patterns -description: Next.js App Router patterns and best practices -globs: - - "app/**/*" - - "src/app/**/*" - - "components/**/*" ---- - -# Next.js Patterns (App Router) - -## File Conventions - -| File | Purpose | -|------|---------| -| `page.tsx` | Route UI | -| `layout.tsx` | Shared layout wrapper | -| `loading.tsx` | Loading UI (Suspense) | -| `error.tsx` | Error boundary | -| `not-found.tsx` | 404 page | -| `route.ts` | API endpoint | - -## Server vs Client Components - -```tsx -// Server Component (default) - runs on server only -export default function ServerComponent() { - // Can use: async/await, direct DB access, server-only code - // Cannot use: useState, useEffect, browser APIs - return
Server rendered
; -} - -// Client Component - runs on client -'use client'; -export default function ClientComponent() { - // Can use: hooks, event handlers, browser APIs - const [state, setState] = useState(); - return ; -} -``` - -## Data Fetching - -```tsx -// Server Component - fetch directly -async function ProductPage({ params }: { params: { id: string } }) { - const product = await db.product.findUnique({ where: { id: params.id } }); - return ; -} - -// With caching -const getData = cache(async (id: string) => { - return await db.find(id); -}); -``` - -## Server Actions - -```tsx -// actions.ts -'use server'; - -export async function createPost(formData: FormData) { - const title = formData.get('title'); - await db.post.create({ data: { title } }); - revalidatePath('/posts'); -} - -// In component -
- - -
-``` - -## Route Handlers - -```tsx -// app/api/users/route.ts -import { NextResponse } from 'next/server'; - -export async function GET() { - const users = await db.user.findMany(); - return NextResponse.json(users); -} - -export async function POST(request: Request) { - const body = await request.json(); - const user = await db.user.create({ data: body }); - return NextResponse.json(user, { status: 201 }); -} -``` - -## Patterns to Follow - -1. **Default to Server Components** - Only use 'use client' when needed -2. **Colocate related files** - Keep components near their routes -3. **Use route groups** - `(auth)/login` for organization without URL impact -4. **Parallel routes** - `@modal/` for simultaneous rendering -5. **Intercepting routes** - `(.)/photo` for modal patterns -``` - ---- - -### react-components - -**Condition**: Generate if `react` framework detected AND `nextjs` is NOT detected. - -**File**: `.claude/skills/react-components.md` - -```markdown ---- -name: react-components -description: React component patterns and best practices -globs: - - "src/components/**/*" - - "components/**/*" - - "**/*.tsx" - - "**/*.jsx" ---- - -# React Component Patterns - -## Component Structure - -```tsx -// Standard component structure -import { useState, useCallback } from 'react'; -import type { ComponentProps } from './types'; - -interface Props { - title: string; - onAction?: () => void; - children?: React.ReactNode; -} - -export function MyComponent({ title, onAction, children }: Props) { - const [state, setState] = useState(false); - - const handleClick = useCallback(() => { - setState(true); - onAction?.(); - }, [onAction]); - - return ( -
-

{title}

- - {children} -
- ); -} -``` - -## Hooks Patterns - -```tsx -// Custom hook for data fetching -function useUser(id: string) { - const [user, setUser] = useState(null); - const [loading, setLoading] = useState(true); - const [error, setError] = useState(null); - - useEffect(() => { - fetchUser(id) - .then(setUser) - .catch(setError) - .finally(() => setLoading(false)); - }, [id]); - - return { user, loading, error }; -} -``` - -## State Management - -```tsx -// Use reducer for complex state -const [state, dispatch] = useReducer(reducer, initialState); - -// Use context for shared state -const ThemeContext = createContext('light'); -export const useTheme = () => useContext(ThemeContext); -``` - -## Performance - -1. **Memoize expensive calculations**: `useMemo` -2. **Memoize callbacks**: `useCallback` -3. **Memoize components**: `React.memo` -4. **Avoid inline objects/arrays in props** - -## Testing - -```tsx -import { render, screen, fireEvent } from '@testing-library/react'; - -test('button triggers action', () => { - const onAction = vi.fn(); - render(); - - fireEvent.click(screen.getByRole('button')); - - expect(onAction).toHaveBeenCalled(); -}); -``` -``` - ---- - -### fastapi-patterns - -**Condition**: Generate if `fastapi` framework detected. - -**File**: `.claude/skills/fastapi-patterns.md` - -```markdown ---- -name: fastapi-patterns -description: FastAPI endpoint patterns and best practices -globs: - - "app/**/*.py" - - "src/**/*.py" - - "api/**/*.py" - - "routers/**/*.py" ---- - -# FastAPI Patterns - -## Router Structure - -```python -# routers/users.py -from fastapi import APIRouter, Depends, HTTPException -from sqlalchemy.orm import Session - -from app.database import get_db -from app.schemas import UserCreate, UserResponse -from app.services import UserService - -router = APIRouter(prefix="/users", tags=["users"]) - -@router.get("/", response_model=list[UserResponse]) -async def list_users( - skip: int = 0, - limit: int = 100, - db: Session = Depends(get_db) -): - service = UserService(db) - return service.get_all(skip=skip, limit=limit) - -@router.post("/", response_model=UserResponse, status_code=201) -async def create_user( - user: UserCreate, - db: Session = Depends(get_db) -): - service = UserService(db) - return service.create(user) -``` - -## Dependency Injection - -```python -# Dependencies -def get_current_user(token: str = Depends(oauth2_scheme)) -> User: - user = decode_token(token) - if not user: - raise HTTPException(status_code=401, detail="Invalid token") - return user - -def require_admin(user: User = Depends(get_current_user)) -> User: - if not user.is_admin: - raise HTTPException(status_code=403, detail="Admin required") - return user - -# Usage -@router.delete("/{id}") -async def delete_user(id: int, admin: User = Depends(require_admin)): - ... -``` - -## Pydantic Schemas - -```python -from pydantic import BaseModel, EmailStr, Field - -class UserBase(BaseModel): - email: EmailStr - name: str = Field(..., min_length=1, max_length=100) - -class UserCreate(UserBase): - password: str = Field(..., min_length=8) - -class UserResponse(UserBase): - id: int - created_at: datetime - - class Config: - from_attributes = True # For ORM mode -``` - -## Error Handling - -```python -from fastapi import HTTPException -from fastapi.responses import JSONResponse - -# Custom exception -class NotFoundError(Exception): - def __init__(self, resource: str, id: int): - self.resource = resource - self.id = id - -# Exception handler -@app.exception_handler(NotFoundError) -async def not_found_handler(request, exc: NotFoundError): - return JSONResponse( - status_code=404, - content={"error": f"{exc.resource} {exc.id} not found"} - ) -``` - -## Testing - -```python -from fastapi.testclient import TestClient - -def test_create_user(client: TestClient): - response = client.post("/users/", json={ - "email": "test@example.com", - "name": "Test", - "password": "password123" - }) - assert response.status_code == 201 - assert response.json()["email"] == "test@example.com" -``` -``` - ---- - -### nestjs-patterns - -**Condition**: Generate if `nestjs` framework detected. - -**File**: `.claude/skills/nestjs-patterns.md` - -```markdown ---- -name: nestjs-patterns -description: NestJS module patterns and best practices -globs: - - "src/**/*.ts" - - "**/*.module.ts" - - "**/*.controller.ts" - - "**/*.service.ts" ---- - -# NestJS Patterns - -## Module Structure - -```typescript -// users/users.module.ts -import { Module } from '@nestjs/common'; -import { TypeOrmModule } from '@nestjs/typeorm'; -import { UsersController } from './users.controller'; -import { UsersService } from './users.service'; -import { User } from './entities/user.entity'; - -@Module({ - imports: [TypeOrmModule.forFeature([User])], - controllers: [UsersController], - providers: [UsersService], - exports: [UsersService], -}) -export class UsersModule {} -``` - -## Controller Pattern - -```typescript -// users/users.controller.ts -import { Controller, Get, Post, Body, Param, UseGuards } from '@nestjs/common'; -import { UsersService } from './users.service'; -import { CreateUserDto } from './dto/create-user.dto'; -import { JwtAuthGuard } from '../auth/jwt-auth.guard'; - -@Controller('users') -export class UsersController { - constructor(private readonly usersService: UsersService) {} - - @Get() - findAll() { - return this.usersService.findAll(); - } - - @Get(':id') - findOne(@Param('id') id: string) { - return this.usersService.findOne(+id); - } - - @Post() - @UseGuards(JwtAuthGuard) - create(@Body() createUserDto: CreateUserDto) { - return this.usersService.create(createUserDto); - } -} -``` - -## Service Pattern - -```typescript -// users/users.service.ts -import { Injectable, NotFoundException } from '@nestjs/common'; -import { InjectRepository } from '@nestjs/typeorm'; -import { Repository } from 'typeorm'; -import { User } from './entities/user.entity'; - -@Injectable() -export class UsersService { - constructor( - @InjectRepository(User) - private usersRepository: Repository, - ) {} - - findAll(): Promise { - return this.usersRepository.find(); - } - - async findOne(id: number): Promise { - const user = await this.usersRepository.findOne({ where: { id } }); - if (!user) { - throw new NotFoundException(`User #${id} not found`); - } - return user; - } -} -``` - -## DTO Validation - -```typescript -// dto/create-user.dto.ts -import { IsEmail, IsString, MinLength } from 'class-validator'; - -export class CreateUserDto { - @IsEmail() - email: string; - - @IsString() - @MinLength(1) - name: string; - - @IsString() - @MinLength(8) - password: string; -} -``` - -## Testing - -```typescript -describe('UsersService', () => { - let service: UsersService; - let repository: MockType>; - - beforeEach(async () => { - const module = await Test.createTestingModule({ - providers: [ - UsersService, - { provide: getRepositoryToken(User), useFactory: repositoryMockFactory }, - ], - }).compile(); - - service = module.get(UsersService); - repository = module.get(getRepositoryToken(User)); - }); - - it('should find all users', async () => { - const users = [{ id: 1, name: 'Test' }]; - repository.find.mockReturnValue(users); - - expect(await service.findAll()).toEqual(users); - }); -}); -``` -``` - ---- - -### swiftui-patterns - -**Condition**: Generate if `swiftui` framework detected. - -**File**: `.claude/skills/swiftui-patterns.md` - -```markdown ---- -name: swiftui-patterns -description: SwiftUI declarative UI patterns and best practices -globs: - - "**/*.swift" ---- - -# SwiftUI Patterns - -## View Structure - -```swift -import SwiftUI - -struct ContentView: View { - @State private var count = 0 - @StateObject private var viewModel = ContentViewModel() - - var body: some View { - VStack(spacing: 16) { - Text("Count: \(count)") - .font(.title) - - Button("Increment") { - count += 1 - } - .buttonStyle(.borderedProminent) - } - .padding() - } -} - -#Preview { - ContentView() -} -``` - -## Property Wrappers - -| Wrapper | Use Case | -|---------|----------| -| `@State` | Simple value types owned by view | -| `@Binding` | Two-way connection to parent's state | -| `@StateObject` | Reference type owned by view (create once) | -| `@ObservedObject` | Reference type passed from parent | -| `@EnvironmentObject` | Shared data through view hierarchy | -| `@Environment` | System environment values | - -## MVVM Pattern - -```swift -// ViewModel -@MainActor -class UserViewModel: ObservableObject { - @Published var users: [User] = [] - @Published var isLoading = false - @Published var error: Error? - - private let service: UserService - - init(service: UserService = .shared) { - self.service = service - } - - func fetchUsers() async { - isLoading = true - defer { isLoading = false } - - do { - users = try await service.getUsers() - } catch { - self.error = error - } - } -} - -// View -struct UsersView: View { - @StateObject private var viewModel = UserViewModel() - - var body: some View { - List(viewModel.users) { user in - UserRow(user: user) - } - .overlay { - if viewModel.isLoading { - ProgressView() - } - } - .task { - await viewModel.fetchUsers() - } - } -} -``` - -## Navigation (iOS 16+) - -```swift -struct AppNavigation: View { - @State private var path = NavigationPath() - - var body: some View { - NavigationStack(path: $path) { - HomeView() - .navigationDestination(for: User.self) { user in - UserDetailView(user: user) - } - .navigationDestination(for: Settings.self) { settings in - SettingsView(settings: settings) - } - } - } -} -``` - -## Async/Await Patterns - -```swift -// Task modifier for view lifecycle -.task { - await loadData() -} - -// Task with cancellation -.task(id: searchText) { - try? await Task.sleep(for: .milliseconds(300)) - await search(searchText) -} - -// Refreshable -.refreshable { - await viewModel.refresh() -} -``` - -## Best Practices - -1. **Keep views small** - Extract subviews for reusability -2. **Use `@MainActor`** - For ViewModels updating UI -3. **Prefer value types** - Structs over classes when possible -4. **Use `.task`** - Instead of `.onAppear` for async work -5. **Preview extensively** - Use #Preview for rapid iteration -``` - ---- - -### uikit-patterns - -**Condition**: Generate if `uikit` framework detected. - -**File**: `.claude/skills/uikit-patterns.md` - -```markdown ---- -name: uikit-patterns -description: UIKit view controller patterns and best practices -globs: - - "**/*.swift" ---- - -# UIKit Patterns - -## View Controller Structure - -```swift -import UIKit - -class UserViewController: UIViewController { - // MARK: - Properties - private let viewModel: UserViewModel - private var cancellables = Set() - - // MARK: - UI Components - private lazy var tableView: UITableView = { - let table = UITableView() - table.translatesAutoresizingMaskIntoConstraints = false - table.delegate = self - table.dataSource = self - table.register(UserCell.self, forCellReuseIdentifier: UserCell.identifier) - return table - }() - - // MARK: - Lifecycle - init(viewModel: UserViewModel) { - self.viewModel = viewModel - super.init(nibName: nil, bundle: nil) - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - override func viewDidLoad() { - super.viewDidLoad() - setupUI() - setupBindings() - viewModel.fetchUsers() - } - - // MARK: - Setup - private func setupUI() { - view.backgroundColor = .systemBackground - view.addSubview(tableView) - - NSLayoutConstraint.activate([ - tableView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor), - tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor), - tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor), - tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor) - ]) - } - - private func setupBindings() { - viewModel.$users - .receive(on: DispatchQueue.main) - .sink { [weak self] _ in - self?.tableView.reloadData() - } - .store(in: &cancellables) - } -} -``` - -## Coordinator Pattern - -```swift -protocol Coordinator: AnyObject { - var childCoordinators: [Coordinator] { get set } - var navigationController: UINavigationController { get set } - func start() -} - -class AppCoordinator: Coordinator { - var childCoordinators: [Coordinator] = [] - var navigationController: UINavigationController - - init(navigationController: UINavigationController) { - self.navigationController = navigationController - } - - func start() { - let vc = HomeViewController() - vc.coordinator = self - navigationController.pushViewController(vc, animated: false) - } - - func showUserDetail(_ user: User) { - let vc = UserDetailViewController(user: user) - navigationController.pushViewController(vc, animated: true) - } -} -``` - -## Table View Cell - -```swift -class UserCell: UITableViewCell { - static let identifier = "UserCell" - - private let nameLabel: UILabel = { - let label = UILabel() - label.font = .preferredFont(forTextStyle: .headline) - label.translatesAutoresizingMaskIntoConstraints = false - return label - }() - - override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { - super.init(style: style, reuseIdentifier: reuseIdentifier) - setupUI() - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - private func setupUI() { - contentView.addSubview(nameLabel) - NSLayoutConstraint.activate([ - nameLabel.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 16), - nameLabel.centerYAnchor.constraint(equalTo: contentView.centerYAnchor) - ]) - } - - func configure(with user: User) { - nameLabel.text = user.name - } -} -``` - -## Best Practices - -1. **Use Auto Layout** - Programmatic constraints over Storyboards -2. **MARK comments** - Organize code sections -3. **Coordinator pattern** - For navigation logic -4. **Dependency injection** - Pass dependencies via init -5. **Combine for bindings** - Reactive updates from ViewModel -``` - ---- - -### vapor-patterns - -**Condition**: Generate if `vapor` framework detected. - -**File**: `.claude/skills/vapor-patterns.md` - -```markdown ---- -name: vapor-patterns -description: Vapor server-side Swift patterns -globs: - - "**/*.swift" - - "Package.swift" ---- - -# Vapor Patterns - -## Route Structure - -```swift -import Vapor - -func routes(_ app: Application) throws { - // Basic routes - app.get { req in - "Hello, world!" - } - - // Route groups - let api = app.grouped("api", "v1") - - // Controller registration - try api.register(collection: UserController()) -} -``` - -## Controller Pattern - -```swift -import Vapor - -struct UserController: RouteCollection { - func boot(routes: RoutesBuilder) throws { - let users = routes.grouped("users") - - users.get(use: index) - users.post(use: create) - users.group(":userID") { user in - user.get(use: show) - user.put(use: update) - user.delete(use: delete) - } - } - - // GET /users - func index(req: Request) async throws -> [UserDTO] { - try await User.query(on: req.db).all().map { $0.toDTO() } - } - - // POST /users - func create(req: Request) async throws -> UserDTO { - let input = try req.content.decode(CreateUserInput.self) - let user = User(name: input.name, email: input.email) - try await user.save(on: req.db) - return user.toDTO() - } - - // GET /users/:userID - func show(req: Request) async throws -> UserDTO { - guard let user = try await User.find(req.parameters.get("userID"), on: req.db) else { - throw Abort(.notFound) - } - return user.toDTO() - } -} -``` - -## Fluent Models - -```swift -import Fluent -import Vapor - -final class User: Model, Content { - static let schema = "users" - - @ID(key: .id) - var id: UUID? - - @Field(key: "name") - var name: String - - @Field(key: "email") - var email: String - - @Timestamp(key: "created_at", on: .create) - var createdAt: Date? - - @Children(for: \.$user) - var posts: [Post] - - init() {} - - init(id: UUID? = nil, name: String, email: String) { - self.id = id - self.name = name - self.email = email - } -} - -// Migration -struct CreateUser: AsyncMigration { - func prepare(on database: Database) async throws { - try await database.schema("users") - .id() - .field("name", .string, .required) - .field("email", .string, .required) - .field("created_at", .datetime) - .unique(on: "email") - .create() - } - - func revert(on database: Database) async throws { - try await database.schema("users").delete() - } -} -``` - -## DTOs and Validation - -```swift -struct CreateUserInput: Content, Validatable { - var name: String - var email: String - - static func validations(_ validations: inout Validations) { - validations.add("name", as: String.self, is: !.empty) - validations.add("email", as: String.self, is: .email) - } -} - -struct UserDTO: Content { - var id: UUID? - var name: String - var email: String -} - -extension User { - func toDTO() -> UserDTO { - UserDTO(id: id, name: name, email: email) - } -} -``` - -## Middleware - -```swift -struct AuthMiddleware: AsyncMiddleware { - func respond(to request: Request, chainingTo next: AsyncResponder) async throws -> Response { - guard let token = request.headers.bearerAuthorization?.token else { - throw Abort(.unauthorized) - } - - // Validate token - let user = try await validateToken(token, on: request) - request.auth.login(user) - - return try await next.respond(to: request) - } -} -``` - -## Testing - -```swift -@testable import App -import XCTVapor - -final class UserTests: XCTestCase { - var app: Application! - - override func setUp() async throws { - app = Application(.testing) - try configure(app) - try await app.autoMigrate() - } - - override func tearDown() async throws { - try await app.autoRevert() - app.shutdown() - } - - func testCreateUser() async throws { - try app.test(.POST, "api/v1/users", beforeRequest: { req in - try req.content.encode(CreateUserInput(name: "Test", email: "test@example.com")) - }, afterResponse: { res in - XCTAssertEqual(res.status, .ok) - let user = try res.content.decode(UserDTO.self) - XCTAssertEqual(user.name, "Test") - }) - } -} -``` -``` - ---- - -### compose-patterns - -**Condition**: Generate if `jetpack-compose` framework detected. - -**File**: `.claude/skills/compose-patterns.md` - -```markdown ---- -name: compose-patterns -description: Jetpack Compose UI patterns and best practices -globs: - - "**/*.kt" ---- - -# Jetpack Compose Patterns - -## Composable Structure - -```kotlin -@Composable -fun UserScreen( - viewModel: UserViewModel = hiltViewModel() -) { - val uiState by viewModel.uiState.collectAsStateWithLifecycle() - - UserScreenContent( - uiState = uiState, - onRefresh = viewModel::refresh, - onUserClick = viewModel::selectUser - ) -} - -@Composable -private fun UserScreenContent( - uiState: UserUiState, - onRefresh: () -> Unit, - onUserClick: (User) -> Unit -) { - Scaffold( - topBar = { - TopAppBar(title = { Text("Users") }) - } - ) { padding -> - when (uiState) { - is UserUiState.Loading -> LoadingIndicator() - is UserUiState.Success -> UserList( - users = uiState.users, - onUserClick = onUserClick, - modifier = Modifier.padding(padding) - ) - is UserUiState.Error -> ErrorMessage(uiState.message) - } - } -} -``` - -## State Management - -```kotlin -// UI State -sealed interface UserUiState { - object Loading : UserUiState - data class Success(val users: List) : UserUiState - data class Error(val message: String) : UserUiState -} - -// ViewModel -@HiltViewModel -class UserViewModel @Inject constructor( - private val repository: UserRepository -) : ViewModel() { - - private val _uiState = MutableStateFlow(UserUiState.Loading) - val uiState: StateFlow = _uiState.asStateFlow() - - init { - loadUsers() - } - - fun refresh() { - loadUsers() - } - - private fun loadUsers() { - viewModelScope.launch { - _uiState.value = UserUiState.Loading - repository.getUsers() - .onSuccess { users -> - _uiState.value = UserUiState.Success(users) - } - .onFailure { error -> - _uiState.value = UserUiState.Error(error.message ?: "Unknown error") - } - } - } -} -``` - -## Reusable Components - -```kotlin -@Composable -fun UserCard( - user: User, - onClick: () -> Unit, - modifier: Modifier = Modifier -) { - Card( - onClick = onClick, - modifier = modifier.fillMaxWidth() - ) { - Row( - modifier = Modifier.padding(16.dp), - verticalAlignment = Alignment.CenterVertically - ) { - AsyncImage( - model = user.avatarUrl, - contentDescription = null, - modifier = Modifier - .size(48.dp) - .clip(CircleShape) - ) - Spacer(modifier = Modifier.width(16.dp)) - Column { - Text( - text = user.name, - style = MaterialTheme.typography.titleMedium - ) - Text( - text = user.email, - style = MaterialTheme.typography.bodySmall - ) - } - } - } -} -``` - -## Navigation - -```kotlin -@Composable -fun AppNavigation() { - val navController = rememberNavController() - - NavHost( - navController = navController, - startDestination = "home" - ) { - composable("home") { - HomeScreen( - onUserClick = { userId -> - navController.navigate("user/$userId") - } - ) - } - composable( - route = "user/{userId}", - arguments = listOf(navArgument("userId") { type = NavType.StringType }) - ) { backStackEntry -> - val userId = backStackEntry.arguments?.getString("userId") - UserDetailScreen(userId = userId) - } - } -} -``` - -## Theming - -```kotlin -@Composable -fun AppTheme( - darkTheme: Boolean = isSystemInDarkTheme(), - content: @Composable () -> Unit -) { - val colorScheme = if (darkTheme) { - darkColorScheme( - primary = Purple80, - secondary = PurpleGrey80 - ) - } else { - lightColorScheme( - primary = Purple40, - secondary = PurpleGrey40 - ) - } - - MaterialTheme( - colorScheme = colorScheme, - typography = Typography, - content = content - ) -} -``` - -## Best Practices - -1. **Stateless composables** - Pass state down, events up -2. **Remember wisely** - Use `remember` for expensive calculations -3. **Lifecycle-aware collection** - Use `collectAsStateWithLifecycle()` -4. **Modifier parameter** - Always accept Modifier as last parameter -5. **Preview annotations** - Add @Preview for rapid iteration -``` - ---- - -### android-views-patterns - -**Condition**: Generate if `android-views` framework detected. - -**File**: `.claude/skills/android-views-patterns.md` - -```markdown ---- -name: android-views-patterns -description: Android XML views and traditional patterns -globs: - - "**/*.kt" - - "**/*.xml" ---- - -# Android Views Patterns - -## Activity Structure - -```kotlin -class MainActivity : AppCompatActivity() { - - private lateinit var binding: ActivityMainBinding - private val viewModel: MainViewModel by viewModels() - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - binding = ActivityMainBinding.inflate(layoutInflater) - setContentView(binding.root) - - setupUI() - observeViewModel() - } - - private fun setupUI() { - binding.recyclerView.apply { - layoutManager = LinearLayoutManager(this@MainActivity) - adapter = userAdapter - } - - binding.swipeRefresh.setOnRefreshListener { - viewModel.refresh() - } - } - - private fun observeViewModel() { - lifecycleScope.launch { - repeatOnLifecycle(Lifecycle.State.STARTED) { - viewModel.uiState.collect { state -> - updateUI(state) - } - } - } - } - - private fun updateUI(state: MainUiState) { - binding.swipeRefresh.isRefreshing = state.isLoading - userAdapter.submitList(state.users) - binding.errorText.isVisible = state.error != null - binding.errorText.text = state.error - } -} -``` - -## Fragment Pattern - -```kotlin -class UserFragment : Fragment(R.layout.fragment_user) { - - private var _binding: FragmentUserBinding? = null - private val binding get() = _binding!! - - private val viewModel: UserViewModel by viewModels() - private val args: UserFragmentArgs by navArgs() - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - _binding = FragmentUserBinding.bind(view) - - setupUI() - observeViewModel() - viewModel.loadUser(args.userId) - } - - override fun onDestroyView() { - super.onDestroyView() - _binding = null - } -} -``` - -## RecyclerView Adapter - -```kotlin -class UserAdapter( - private val onItemClick: (User) -> Unit -) : ListAdapter(UserDiffCallback()) { - - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { - val binding = ItemUserBinding.inflate( - LayoutInflater.from(parent.context), - parent, - false - ) - return ViewHolder(binding) - } - - override fun onBindViewHolder(holder: ViewHolder, position: Int) { - holder.bind(getItem(position)) - } - - inner class ViewHolder( - private val binding: ItemUserBinding - ) : RecyclerView.ViewHolder(binding.root) { - - init { - binding.root.setOnClickListener { - onItemClick(getItem(adapterPosition)) - } - } - - fun bind(user: User) { - binding.nameText.text = user.name - binding.emailText.text = user.email - Glide.with(binding.avatar) - .load(user.avatarUrl) - .circleCrop() - .into(binding.avatar) - } - } - - class UserDiffCallback : DiffUtil.ItemCallback() { - override fun areItemsTheSame(oldItem: User, newItem: User) = - oldItem.id == newItem.id - - override fun areContentsTheSame(oldItem: User, newItem: User) = - oldItem == newItem - } -} -``` - -## XML Layout - -```xml - - - - - - - - - - - - -``` - -## ViewModel with Repository - -```kotlin -@HiltViewModel -class UserViewModel @Inject constructor( - private val repository: UserRepository, - private val savedStateHandle: SavedStateHandle -) : ViewModel() { - - private val _uiState = MutableStateFlow(UserUiState()) - val uiState: StateFlow = _uiState.asStateFlow() - - fun loadUsers() { - viewModelScope.launch { - _uiState.update { it.copy(isLoading = true) } - try { - val users = repository.getUsers() - _uiState.update { it.copy(users = users, isLoading = false) } - } catch (e: Exception) { - _uiState.update { it.copy(error = e.message, isLoading = false) } - } - } - } -} - -data class UserUiState( - val users: List = emptyList(), - val isLoading: Boolean = false, - val error: String? = null -) -``` - -## Best Practices - -1. **View Binding** - Use over findViewById or synthetic imports -2. **Lifecycle awareness** - Collect flows in repeatOnLifecycle -3. **ListAdapter** - For efficient RecyclerView updates -4. **Navigation Component** - For fragment navigation -5. **Clean up bindings** - Set to null in onDestroyView -``` diff --git a/src/cli.test.ts b/src/cli.test.ts index 675d672..1a1f7d5 100644 --- a/src/cli.test.ts +++ b/src/cli.test.ts @@ -5,7 +5,6 @@ import path from "node:path"; import { analyzeRepository, detectTechStack, summarizeTechStack } from "./analyzer.js"; import { checkClaudeCli, - createTaskFile, formatFramework, formatLanguage, getVersion, @@ -583,186 +582,6 @@ describe("showTechStack", () => { }); }); -// ============================================================================ -// createTaskFile Tests -// ============================================================================ - -describe("createTaskFile", () => { - let tempDir: string; - - beforeEach(() => { - tempDir = createTempDir(); - }); - - afterEach(() => { - removeTempDir(tempDir); - }); - - it("creates task file for existing project", () => { - const projectInfo = { - isExisting: true, - fileCount: 10, - techStack: { - languages: ["typescript" as const], - primaryLanguage: "typescript" as const, - frameworks: ["nextjs" as const], - primaryFramework: "nextjs" as const, - packageManager: "bun" as const, - testingFramework: "vitest" as const, - linter: null, - formatter: null, - bundler: null, - isMonorepo: false, - hasDocker: false, - hasCICD: false, - cicdPlatform: null, - hasClaudeConfig: false, - existingClaudeFiles: [], - }, - rootDir: tempDir, - name: "test-project", - description: "A test project", - }; - - createTaskFile(projectInfo, null); - - const taskPath = path.join(tempDir, ".claude", "state", "task.md"); - expect(fs.existsSync(taskPath)).toBe(true); - - const content = fs.readFileSync(taskPath, "utf-8"); - expect(content).toContain("# Current Task"); - expect(content).toContain("## Status: Ready"); - expect(content).toContain("test-project"); - expect(content).toContain("A test project"); - }); - - it("creates task file for new project with preferences", () => { - const projectInfo = { - isExisting: false, - fileCount: 0, - techStack: { - languages: [], - primaryLanguage: null, - frameworks: [], - primaryFramework: null, - packageManager: null, - testingFramework: null, - linter: null, - formatter: null, - bundler: null, - isMonorepo: false, - hasDocker: false, - hasCICD: false, - cicdPlatform: null, - hasClaudeConfig: false, - existingClaudeFiles: [], - }, - rootDir: tempDir, - name: "new-project", - description: null, - }; - - const preferences = { - description: "Build a new API", - primaryLanguage: "typescript" as const, - framework: "fastapi" as const, - includeTests: true, - includeLinting: true, - packageManager: null, - testingFramework: null, - linter: null, - formatter: null, - projectType: "API/Backend", - }; - - createTaskFile(projectInfo, preferences); - - const taskPath = path.join(tempDir, ".claude", "state", "task.md"); - expect(fs.existsSync(taskPath)).toBe(true); - - const content = fs.readFileSync(taskPath, "utf-8"); - expect(content).toContain("# Current Task"); - expect(content).toContain("## Status: In Progress"); - expect(content).toContain("Build a new API"); - expect(content).toContain("FastAPI"); - expect(content).toContain("TypeScript"); - }); - - it("does not overwrite existing task file", () => { - // Create existing task file - const taskDir = path.join(tempDir, ".claude", "state"); - fs.mkdirSync(taskDir, { recursive: true }); - const taskPath = path.join(taskDir, "task.md"); - fs.writeFileSync(taskPath, "# Important work in progress"); - - const projectInfo = { - isExisting: true, - fileCount: 10, - techStack: { - languages: ["typescript" as const], - primaryLanguage: "typescript" as const, - frameworks: [], - primaryFramework: null, - packageManager: null, - testingFramework: null, - linter: null, - formatter: null, - bundler: null, - isMonorepo: false, - hasDocker: false, - hasCICD: false, - cicdPlatform: null, - hasClaudeConfig: false, - existingClaudeFiles: [], - }, - rootDir: tempDir, - name: "test", - description: null, - }; - - createTaskFile(projectInfo, null); - - // Should not be overwritten - const content = fs.readFileSync(taskPath, "utf-8"); - expect(content).toBe("# Important work in progress"); - }); - - it("creates task file for new project without preferences", () => { - const projectInfo = { - isExisting: false, - fileCount: 0, - techStack: { - languages: [], - primaryLanguage: null, - frameworks: [], - primaryFramework: null, - packageManager: null, - testingFramework: null, - linter: null, - formatter: null, - bundler: null, - isMonorepo: false, - hasDocker: false, - hasCICD: false, - cicdPlatform: null, - hasClaudeConfig: false, - existingClaudeFiles: [], - }, - rootDir: tempDir, - name: "new-project", - description: null, - }; - - createTaskFile(projectInfo, null); - - const taskPath = path.join(tempDir, ".claude", "state", "task.md"); - expect(fs.existsSync(taskPath)).toBe(true); - - const content = fs.readFileSync(taskPath, "utf-8"); - expect(content).toContain("Explore and set up project"); - }); -}); - // ============================================================================ // Tech Stack Detection Tests // ============================================================================ @@ -1193,7 +1012,6 @@ describe("ensureDirectories", () => { expect(fs.existsSync(path.join(tempDir, ".claude", "agents"))).toBe(true); expect(fs.existsSync(path.join(tempDir, ".claude", "rules"))).toBe(true); expect(fs.existsSync(path.join(tempDir, ".claude", "commands"))).toBe(true); - expect(fs.existsSync(path.join(tempDir, ".claude", "state"))).toBe(true); }); it("is idempotent — running twice doesn't error", () => { @@ -1289,14 +1107,15 @@ describe("getAnalysisPrompt", () => { it("includes skills generation instructions", () => { const prompt = getAnalysisPrompt(projectInfo); expect(prompt).toContain("Phase 4"); - expect(prompt).toContain("pattern-discovery"); - expect(prompt).toContain("systematic-debugging"); - expect(prompt).toContain("testing-methodology"); expect(prompt).toContain("iterative-development"); - expect(prompt).toContain("commit-hygiene"); expect(prompt).toContain("code-deduplication"); - expect(prompt).toContain("simplicity-rules"); expect(prompt).toContain("security"); + expect(prompt).toContain("testing-methodology"); + // Removed skills should NOT be present as standalone skill files + expect(prompt).not.toContain("`.claude/skills/pattern-discovery.md`"); + expect(prompt).not.toContain("`.claude/skills/systematic-debugging.md`"); + expect(prompt).not.toContain("`.claude/skills/commit-hygiene.md`"); + expect(prompt).not.toContain("`.claude/skills/simplicity-rules.md`"); }); it("includes agents generation instructions", () => { @@ -1309,19 +1128,21 @@ describe("getAnalysisPrompt", () => { it("includes rules generation instructions", () => { const prompt = getAnalysisPrompt(projectInfo); expect(prompt).toContain("Phase 6"); - expect(prompt).toContain("code-style"); expect(prompt).toContain("typescript.md"); expect(prompt).toContain("python.md"); + // Should prohibit unfiltered rules, not generate a code-style rule + expect(prompt).not.toContain("`.claude/rules/code-style.md`"); }); it("includes commands generation instructions", () => { const prompt = getAnalysisPrompt(projectInfo); expect(prompt).toContain("Phase 7"); - expect(prompt).toContain("task.md"); - expect(prompt).toContain("status.md"); - expect(prompt).toContain("done.md"); expect(prompt).toContain("analyze.md"); expect(prompt).toContain("code-review.md"); + // Task management commands should NOT be generated (Claude Code has built-in task tools) + expect(prompt).not.toContain("### `.claude/commands/task.md`"); + expect(prompt).not.toContain("### `.claude/commands/status.md`"); + expect(prompt).not.toContain("### `.claude/commands/done.md`"); }); it("includes template variables", () => { @@ -1389,4 +1210,26 @@ describe("getAnalysisPrompt", () => { const prompt = getAnalysisPrompt(projectInfo); expect(prompt).toContain("Cross-reference, don't copy"); }); + + it("enforces CLAUDE.md line limit", () => { + const prompt = getAnalysisPrompt(projectInfo); + expect(prompt).toContain("MUST NOT exceed 120 lines"); + }); + + it("prohibits command duplication in skills", () => { + const prompt = getAnalysisPrompt(projectInfo); + expect(prompt).toContain("Forbidden Duplication List"); + expect(prompt).toContain("MUST NOT appear in skills, agents, rules, or commands"); + }); + + it("instructs test-writer agent to not duplicate testing-methodology skill", () => { + const prompt = getAnalysisPrompt(projectInfo); + expect(prompt).toContain("Do NOT duplicate the testing-methodology skill content"); + }); + + it("excludes task management commands", () => { + const prompt = getAnalysisPrompt(projectInfo); + expect(prompt).toContain("Do NOT generate task management commands"); + expect(prompt).toContain("built-in TaskCreate/TaskUpdate/TaskList"); + }); }); diff --git a/src/cli.ts b/src/cli.ts index 96a2d23..9f08116 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -30,7 +30,7 @@ import { fileURLToPath } from "node:url"; import ora from "ora"; import pc from "picocolors"; import prompts from "prompts"; -import { analyzeRepository, summarizeTechStack } from "./analyzer.js"; +import { analyzeRepository } from "./analyzer.js"; import { ensureDirectories, writeSettings } from "./generator.js"; import { getAnalysisPrompt } from "./prompt.js"; import type { @@ -474,72 +474,6 @@ export function mapFormatter(linter: Linter | null): Formatter | null { return mapping[linter] ?? null; } -export function createTaskFile( - projectInfo: ProjectInfo, - preferences: NewProjectPreferences | null -): void { - const taskPath = path.join(projectInfo.rootDir, ".claude", "state", "task.md"); - - // Create state directory - fs.mkdirSync(path.dirname(taskPath), { recursive: true }); - - // Don't overwrite existing task file - if (fs.existsSync(taskPath)) { - return; - } - - let content: string; - - if (projectInfo.isExisting) { - content = `# Current Task - -## Status: Ready - -No active task. Start one with \`/task \`. - -## Project Summary - -${projectInfo.name}${projectInfo.description ? ` - ${projectInfo.description}` : ""} - -**Tech Stack:** ${summarizeTechStack(projectInfo.techStack)} - -## Quick Commands - -- \`/task\` - Start working on something -- \`/status\` - See current state -- \`/analyze\` - Deep dive into code -- \`/done\` - Mark task complete -`; - } else { - const description = preferences?.description || "Explore and set up project"; - content = `# Current Task - -## Status: In Progress - -**Task:** ${description} - -## Context - -New project - setting up from scratch. - -${preferences?.framework ? `**Framework:** ${formatFramework(preferences.framework)}` : ""} -${preferences?.primaryLanguage ? `**Language:** ${formatLanguage(preferences.primaryLanguage)}` : ""} - -## Next Steps - -1. Define project structure -2. Set up development environment -3. Start implementation - -## Decisions - -(None yet - starting fresh) -`; - } - - fs.writeFileSync(taskPath, content); -} - export function formatLanguage(lang: Language): string { const names: Record = { typescript: "TypeScript", @@ -824,10 +758,7 @@ async function main(): Promise { console.log(pc.green(" + .claude/settings.json")); console.log(); - // Step 6: Create task file - createTaskFile(projectInfo, preferences); - - // Step 7: Run Claude-powered deep analysis for all .claude/ content files + // Step 6: Run Claude-powered deep analysis for all .claude/ content files const success = await runClaudeAnalysis(projectDir, projectInfo); if (!success) { @@ -835,7 +766,7 @@ async function main(): Promise { process.exit(1); } - // Step 8: Show summary + // Step 7: Show summary const generatedFiles = getGeneratedFiles(projectDir); console.log(); console.log(pc.green(`Done! (${generatedFiles.length} files)`)); diff --git a/src/generator.ts b/src/generator.ts index 06120df..4a85625 100644 --- a/src/generator.ts +++ b/src/generator.ts @@ -28,14 +28,7 @@ import type { TechStack } from "./types.js"; * Ensure all required .claude/ subdirectories exist. */ export function ensureDirectories(rootDir: string): void { - const dirs = [ - ".claude", - ".claude/skills", - ".claude/agents", - ".claude/rules", - ".claude/commands", - ".claude/state", - ]; + const dirs = [".claude", ".claude/skills", ".claude/agents", ".claude/rules", ".claude/commands"]; for (const dir of dirs) { fs.mkdirSync(path.join(rootDir, dir), { recursive: true }); diff --git a/src/prompt.ts b/src/prompt.ts index bdd8be4..e4a908e 100644 --- a/src/prompt.ts +++ b/src/prompt.ts @@ -8,7 +8,7 @@ * - Skills — Methodology and framework-specific guides * - Agents — Code reviewer, test writer * - Rules — Language-specific conventions - * - Commands — /task, /status, /done, /analyze, /code-review + * - Commands — /analyze, /code-review * * The prompt is embedded as a string constant so it's bundled by tsup * and doesn't require a separate file at runtime. @@ -52,14 +52,14 @@ ${templateVars} 1. Read this entire prompt to understand all phases 2. Execute Phase 1 completely - read files, analyze code, gather all data -3. Execute Phase 2 - generate the CLAUDE.md using only discovered information +3. Execute Phase 2 - generate the CLAUDE.md (max 120 lines) using only discovered information 4. Execute Phase 3 - verify quality before writing 5. Use the Write tool to create \`.claude/CLAUDE.md\` with the final content -6. Execute Phase 4 - generate ALL skill files +6. Execute Phase 4 - generate ALL skill files (4 core + framework-specific if detected) 7. Execute Phase 5 - generate agent files 8. Execute Phase 6 - generate rule files -9. Execute Phase 7 - generate command files -10. Run the Anti-Redundancy Checklist one final time across ALL generated files — if any convention is restated or any rule lacks a \`paths:\` filter, fix it before proceeding +9. Execute Phase 7 - generate command files (2 commands: analyze, code-review) +10. Run the Anti-Redundancy Enforcement checks one final time across ALL generated files — if any convention is restated, any command is duplicated, or any rule lacks a \`paths:\` filter, fix it before proceeding 11. Output a brief summary of what was generated and any gaps found Do NOT output file contents to stdout. Write all files to disk using the Write tool. @@ -257,14 +257,26 @@ frequencies, so place information where it costs the least while remaining acces 5. **Agents have zero main-context cost.** Put detailed checklists and review criteria in agent files — they run in subprocesses and don't consume the user's context window. 6. **Each piece of information must live in exactly ONE place.** If it's in CLAUDE.md, don't repeat it in rules, skills, or commands. -### Anti-Redundancy Checklist +### Anti-Redundancy Enforcement -Before writing EACH artifact, verify: -- [ ] No convention from CLAUDE.md is restated (commit format, naming, import order, etc.) -- [ ] No content from another artifact is duplicated -- [ ] Cross-references are used instead of copies (e.g., "Follow conventions in CLAUDE.md") -- [ ] All rules have a \`paths:\` filter -- [ ] Information is placed at the lowest-cost tier that still makes it accessible +Before writing EACH artifact, apply these hard constraints: + +- **REJECT** any artifact that restates a convention from CLAUDE.md. If a convention appears in CLAUDE.md, it MUST NOT appear in any other file. Not paraphrased, not summarized, not restated in different words. +- **Test commands, lint commands, and build commands** MUST appear in exactly ONE place: CLAUDE.md's Common Commands section. Skills and agents MUST write "See Common Commands in CLAUDE.md" instead. +- **All rules MUST have a \`paths:\` filter** — no unfiltered rules. +- **Cross-references replace copies** — write "Follow conventions in CLAUDE.md" instead of restating any convention. + +#### Forbidden Duplication List + +The following MUST NOT appear in skills, agents, rules, or commands — they belong exclusively in CLAUDE.md: +- Test commands (the literal test runner invocation) +- Lint commands (the literal linter invocation) +- Build commands (the literal build invocation) +- Import convention descriptions (absolute vs relative, ordering, type imports) +- Naming convention descriptions (camelCase, PascalCase, file naming) +- Commit format descriptions (conventional commits, message format) +- Anti-patterns list (things to avoid) +- Testing framework syntax examples (describe/it/expect — belongs in test-writer agent only) --- @@ -363,9 +375,13 @@ Read at least 3-5 source files and document the ACTUAL patterns used: Using ONLY information discovered in Phase 1, generate the \`.claude/CLAUDE.md\` file. Every section must contain PROJECT-SPECIFIC content. Skip sections that don't apply. +**The CLAUDE.md MUST NOT exceed 120 lines. Prioritize density over completeness.** + +Do NOT include sections that duplicate information available in package.json, tsconfig.json, or other config files the agent can read directly. + ### Output Structure -The CLAUDE.md MUST follow this structure: +The CLAUDE.md MUST follow this compact structure: \`\`\`markdown # {Project Name} @@ -379,17 +395,9 @@ Written for an AI assistant that needs to understand PURPOSE to make good decisi ## Architecture -{Describe the actual architecture pattern found} - -### Directory Structure - -\\\`\\\`\\\` -{Actual directory tree, depth 3, with annotations} -\\\`\\\`\\\` - -### Data Flow - -{How a typical request flows through the system} +{1-2 sentences describing the actual architecture pattern found, then the Key Files table. +Do NOT include a Directory Structure ASCII tree or Data Flow subsection — the agent can +read the filesystem directly.} ### Key Files @@ -397,42 +405,18 @@ Written for an AI assistant that needs to understand PURPOSE to make good decisi |------|---------| | \`path/to/file\` | What it does | -## Tech Stack - -| Category | Technology | Notes | -|----------|-----------|-------| -| Language | X | Config details | -| Framework | Y | How it's used | - -## Development Setup - -### Prerequisites - -{Exact versions and tools needed} - -### Getting Started - -\\\`\\\`\\\`bash -{Actual commands to get running} -\\\`\\\`\\\` - -### Environment Variables - -| Variable | Description | Example | -|----------|-------------|---------| -| \`VAR_NAME\` | What it's for | \`example_value\` | - ## Common Commands \\\`\\\`\\\`bash -{Actual commands from package.json scripts or equivalent} +{5 critical commands max, from package.json scripts or equivalent. +Only the commands developers use daily — not every script.} \\\`\\\`\\\` ## Code Conventions ### Naming -{ACTUAL naming patterns found} +{ACTUAL naming patterns found — be brief} ### Patterns to Follow @@ -445,45 +429,16 @@ Written for an AI assistant that needs to understand PURPOSE to make good decisi > **This Code Conventions section is the single source of truth.** > Rules and skills cross-reference this section — they do not repeat it. -## Skills - -{List each generated skill with a one-line description} - -| Skill | Purpose | -|-------|---------| -| \`pattern-discovery\` | Discover and document codebase patterns | -| ... | ... | - -## Agents - -{List each generated agent with a one-line description} - -| Agent | Purpose | -|-------|---------| -| \`code-reviewer\` | Reviews code for quality and security | -| \`test-writer\` | Generates tests for code | - ## Testing -### Running Tests - -\\\`\\\`\\\`bash -{actual test commands} -\\\`\\\`\\\` - -### Writing Tests - -{Testing patterns, utilities, fixtures available} +{2-3 lines: test command, test file location, key testing pattern. +NOT a full guide — the test-writer agent handles detailed test methodology.} ## Domain Knowledge ### Core Entities -{Main domain objects and relationships} - -### Key Workflows - -{3-5 most important workflows} +{Brief list of main domain objects and relationships} ## Gotchas & Important Notes @@ -497,12 +452,22 @@ Written for an AI assistant that needs to understand PURPOSE to make good decisi 4. {project-specific rules discovered during analysis} \`\`\` +**Sections NOT to include** (the agent can read these from config files directly): +- Directory Structure ASCII tree (agent uses Glob/Read) +- Tech Stack table (available in package.json, tsconfig.json, etc.) +- Development Setup / Getting Started / Prerequisites +- Environment Variables table (available in .env.example) +- Skills index table +- Agents index table +- Key Workflows (duplicates Data Flow / Architecture) + --- ## Phase 3: Quality Checklist Before writing the CLAUDE.md, verify: +- [ ] The file does NOT exceed 120 lines - [ ] Every section contains PROJECT-SPECIFIC information (not generic boilerplate) - [ ] File paths referenced actually exist in the project - [ ] File references use \`path/to/file.ts (functionName)\` format, not line numbers @@ -511,12 +476,13 @@ Before writing the CLAUDE.md, verify: - [ ] The "Gotchas" section contains genuinely useful, non-obvious information - [ ] An AI reading this CLAUDE.md could add a new feature following existing patterns - [ ] Sections without real content have been omitted entirely +- [ ] No section duplicates information available in config files the agent can read ### Cross-Artifact Deduplication Check Before writing ANY artifact (rule, skill, agent, command), verify: - [ ] No conventions from CLAUDE.md are restated (naming, commit format, import order, style) -- [ ] No commit format description is restated outside CLAUDE.md +- [ ] No item from the Forbidden Duplication List appears outside CLAUDE.md - [ ] No content from one artifact is duplicated in another - [ ] Cross-references are used instead of copies (e.g., "Follow conventions in CLAUDE.md") - [ ] Every rule file has a \`paths:\` filter — no unfiltered rules @@ -549,57 +515,38 @@ const SKILLS_PROMPT = `--- Write each skill file to \`.claude/skills/\` using the Write tool. Every skill must have YAML frontmatter with \`name\`, \`description\`, and optionally \`globs\` for file matching. -**Tailor ALL skills to this specific project** — use the actual test command, lint command, -file patterns, and conventions discovered during Phase 1. +**Tailor ALL skills to this specific project** — use the actual file patterns and +conventions discovered during Phase 1. ### Skill Content Rules 1. **Cross-reference, don't copy** — write "Follow conventions in CLAUDE.md" instead of restating naming, style, or commit conventions. Skills focus on methodology (HOW to do something), not conventions (WHAT the conventions are). 2. **Use stable references** — reference code as \`path/to/file.ts (functionName)\`, not line numbers which become stale. 3. **No convention duplication** — if CLAUDE.md already documents commit format, import order, or naming rules, the skill must not repeat them. +4. **No command duplication** — for test, lint, and build commands, write "See Common Commands in CLAUDE.md" instead of repeating the literal command. -### 4.1 Core Skills (ALWAYS generate all 8) - -**\`.claude/skills/pattern-discovery.md\`** -- Name: pattern-discovery -- Description: Analyze codebase to discover and document patterns -- Content: How to search for patterns in THIS project's structure. Include the actual source directories, key file patterns, and import conventions found. - -**\`.claude/skills/systematic-debugging.md\`** -- Name: systematic-debugging -- Description: 4-phase debugging methodology — Reproduce, Locate, Diagnose, Fix -- Content: Tailor reproduction steps to the project's actual test runner and dev server commands. Include how to use the project's logging/debugging setup. - -**\`.claude/skills/testing-methodology.md\`** -- Name: testing-methodology -- Description: AAA testing pattern with project-specific framework syntax -- Content: Use the project's actual testing framework syntax. Include real examples of test patterns found in the codebase (describe/it blocks, pytest fixtures, etc.). Reference the actual test command. Include mocking/stubbing patterns specific to the stack. +### 4.1 Core Skills (ALWAYS generate all 4) **\`.claude/skills/iterative-development.md\`** - Name: iterative-development -- Description: TDD workflow with project-specific test and lint commands -- Content: The TDD loop using the actual test command and lint command. Include the project's verification steps (typecheck, build, etc.). - -**\`.claude/skills/commit-hygiene.md\`** -- Name: commit-hygiene -- Description: Atomic commits, conventional format, size thresholds -- Content: Size thresholds (±300 lines per commit), when-to-commit triggers. For commit format, write "Follow the commit conventions in CLAUDE.md" — do NOT restate the format here. If the project uses commitlint or similar, reference its config. +- Description: TDD workflow with debugging methodology and verification chain +- Content: The TDD loop referencing "See Common Commands in CLAUDE.md" for actual commands. Include the project's verification steps (typecheck, build, etc.). Add a Debugging section with: 4-phase methodology (Reproduce, Locate, Diagnose, Fix), project-specific file-to-module mapping for tracing bugs, how to use the project's logging/debugging setup. Add commit guidance: size thresholds (±300 lines per commit), when-to-commit triggers, "Follow commit conventions in CLAUDE.md" for format. **\`.claude/skills/code-deduplication.md\`** - Name: code-deduplication -- Description: Check-before-write principle and search checklist -- Content: Search existing code before writing new code. Include project-specific glob patterns for source files. Reference the actual directory structure for where to look. - -**\`.claude/skills/simplicity-rules.md\`** -- Name: simplicity-rules -- Description: Function and file size limits, decomposition patterns -- Content: Function length limits (40 lines), file limits (300 lines), cyclomatic complexity. Decomposition patterns appropriate for the project's architecture style. +- Description: Check-before-write principle, search checklist, and size limits +- Content: Search existing code before writing new code. Include project-specific glob patterns for source files. Reference the actual directory structure for where to look. Include a "Where to Look" checklist for discovering patterns in THIS project's structure (source directories, key file patterns). Add size limits: function length (40 lines), file length (300 lines), decomposition patterns appropriate for the project's architecture style. **\`.claude/skills/security.md\`** - Name: security - Description: Security patterns and secrets management for this stack - Content: .gitignore entries appropriate for the detected stack. Environment variable handling patterns. OWASP checklist items relevant to the detected framework. Include actual secrets patterns to watch for (API keys, database URLs, etc.). +**\`.claude/skills/testing-methodology.md\`** +- Name: testing-methodology +- Description: Test design methodology — what to test, edge cases, test organization +- Content: Focus on test DESIGN: what to test, how to identify edge cases, test organization strategy, when to use unit vs integration tests. Include project-specific test file naming and location conventions. Reference "See Common Commands in CLAUDE.md" for the test command. Do NOT include testing framework syntax examples (describe/it/expect, pytest fixtures, etc.) — those belong in the test-writer agent, not here. The \`testing-methodology\` skill focuses on test DESIGN (what to test, edge cases, test organization). The \`test-writer\` agent focuses on test EXECUTION (writing code, running tests). They must not overlap. + ### 4.2 Framework-Specific Skills (ONLY if detected) Generate the matching skill ONLY if the framework was detected in the tech stack: @@ -692,7 +639,8 @@ Body content — instructions for the test writer agent: - Follow existing test file naming conventions - Include edge cases: empty inputs, nulls, errors, boundaries - Mock external dependencies following project patterns -- Run tests after writing to verify they pass`; +- Run tests after writing to verify they pass +- Do NOT duplicate the testing-methodology skill content. The skill covers test design (what to test, edge cases, organization); this agent covers writing and running tests (framework syntax, assertions, execution).`; // ============================================================================ // Phase 6: Rules Generation Prompt @@ -767,39 +715,11 @@ const COMMANDS_PROMPT = `--- ## Phase 7: Generate Commands -Write 5 command files to \`.claude/commands/\`. Each needs YAML frontmatter with +Write 2 command files to \`.claude/commands/\`. Each needs YAML frontmatter with \`allowed-tools\`, \`description\`, and optionally \`argument-hint\`. -### \`.claude/commands/task.md\` -\`\`\`yaml ---- -allowed-tools: ["Read", "Write", "Edit", "Glob"] -description: "Start or switch to a new task" -argument-hint: "" ---- -\`\`\` -Body: Instructions to read current \`.claude/state/task.md\`, update status to "In Progress", -record the task description and timestamp. If starting a new task, archive the previous one. - -### \`.claude/commands/status.md\` -\`\`\`yaml ---- -allowed-tools: ["Read", "Glob", "Grep", "Bash(git status)", "Bash(git diff --stat)"] -description: "Show current task and session state" ---- -\`\`\` -Body: Read \`.claude/state/task.md\`, show git status, list recently modified files, -summarize current state in a concise format. - -### \`.claude/commands/done.md\` -\`\`\`yaml ---- -allowed-tools: ["Read", "Write", "Edit", "Glob", "Grep", "Bash(git:*)", "Bash({test_command})", "Bash({lint_command})"] -description: "Mark current task complete" ---- -\`\`\` -Body: Run tests and lint checks. If they pass, update \`.claude/state/task.md\` -status to "Done". Show a summary of what was accomplished. Suggest next steps. +Do NOT generate task management commands (\`task.md\`, \`status.md\`, \`done.md\`) — +Claude Code has built-in TaskCreate/TaskUpdate/TaskList tools for task management. ### \`.claude/commands/analyze.md\` \`\`\`yaml