Explorar o código

refactor: Transform claude-architect into decision router with skill extraction

- Refactor claude-architect from 1,242 to 346 lines (72% reduction)
- Add decision frameworks for extension type selection
- Add skill routing table for specialized Claude Code skills
- Create 4 new meta skills following agentskills.io spec:
  - claude-code-hooks: Hook events, config, security patterns
  - claude-code-headless: CLI options, output formats, CI/CD
  - claude-code-templates: Agent, skill, command, hook scaffolds
  - claude-code-debug: Troubleshooting, common issues, debug commands
- Extract reference content from 13 skills to references/ directories
- Add container-orchestration, security-patterns, testing-patterns skills
- Add official documentation links to all Claude Code skills
- Add prompt caching optimization guidance to skill template
- Add depends-on/related-skills metadata per agentskills.io extensions

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
0xDarkMatter hai 6 meses
pai
achega
3757772ed1
Modificáronse 77 ficheiros con 14597 adicións e 3019 borrados
  1. 112 857
      agents/claude-architect.md
  2. 122 0
      skills/claude-code-debug/SKILL.md
  3. 208 0
      skills/claude-code-debug/references/common-issues.md
  4. 276 0
      skills/claude-code-debug/references/debug-commands.md
  5. 213 0
      skills/claude-code-debug/references/troubleshooting-flow.md
  6. 128 0
      skills/claude-code-headless/SKILL.md
  7. 207 0
      skills/claude-code-headless/references/cli-options.md
  8. 373 0
      skills/claude-code-headless/references/integration-patterns.md
  9. 202 0
      skills/claude-code-headless/references/output-formats.md
  10. 114 0
      skills/claude-code-hooks/SKILL.md
  11. 263 0
      skills/claude-code-hooks/references/configuration.md
  12. 251 0
      skills/claude-code-hooks/references/hook-events.md
  13. 264 0
      skills/claude-code-hooks/references/security-patterns.md
  14. 118 0
      skills/claude-code-templates/SKILL.md
  15. 69 0
      skills/claude-code-templates/assets/agent-template.md
  16. 93 0
      skills/claude-code-templates/assets/command-template.md
  17. 85 0
      skills/claude-code-templates/assets/hook-script.sh
  18. 138 0
      skills/claude-code-templates/assets/skill-template.md
  19. 28 189
      skills/code-stats/SKILL.md
  20. 283 0
      skills/code-stats/references/difft-advanced.md
  21. 254 0
      skills/code-stats/references/tokei-advanced.md
  22. 230 0
      skills/container-orchestration/SKILL.md
  23. 68 0
      skills/container-orchestration/assets/Dockerfile.template
  24. 140 0
      skills/container-orchestration/assets/docker-compose.template.yml
  25. 340 0
      skills/container-orchestration/references/dockerfile-patterns.md
  26. 376 0
      skills/container-orchestration/references/helm-patterns.md
  27. 381 0
      skills/container-orchestration/references/k8s-manifests.md
  28. 85 0
      skills/container-orchestration/scripts/build-push.sh
  29. 37 122
      skills/doc-scanner/SKILL.md
  30. 178 0
      skills/doc-scanner/references/file-patterns.md
  31. 349 0
      skills/doc-scanner/references/templates.md
  32. 43 154
      skills/file-search/SKILL.md
  33. 314 0
      skills/file-search/references/advanced-workflows.md
  34. 31 165
      skills/find-replace/SKILL.md
  35. 257 0
      skills/find-replace/references/advanced-patterns.md
  36. 39 268
      skills/git-workflow/SKILL.md
  37. 261 0
      skills/git-workflow/references/advanced-git.md
  38. 134 0
      skills/git-workflow/references/rebase-patterns.md
  39. 141 0
      skills/git-workflow/references/stash-patterns.md
  40. 10 0
      skills/mcp-patterns/SKILL.md
  41. 61 275
      skills/rest-patterns/SKILL.md
  42. 192 0
      skills/rest-patterns/references/caching-patterns.md
  43. 201 0
      skills/rest-patterns/references/rate-limiting.md
  44. 289 0
      skills/rest-patterns/references/response-formats.md
  45. 172 0
      skills/rest-patterns/references/status-codes.md
  46. 182 0
      skills/security-patterns/SKILL.md
  47. 322 0
      skills/security-patterns/references/auth-patterns.md
  48. 302 0
      skills/security-patterns/references/crypto-patterns.md
  49. 329 0
      skills/security-patterns/references/owasp-detailed.md
  50. 240 0
      skills/security-patterns/references/secure-headers.md
  51. 90 0
      skills/security-patterns/scripts/dependency-audit.sh
  52. 89 0
      skills/security-patterns/scripts/security-scan.sh
  53. 38 162
      skills/sql-patterns/SKILL.md
  54. 297 0
      skills/sql-patterns/references/indexing-strategies.md
  55. 333 0
      skills/sql-patterns/references/window-functions.md
  56. 32 216
      skills/sqlite-ops/SKILL.md
  57. 288 0
      skills/sqlite-ops/references/async-patterns.md
  58. 330 0
      skills/sqlite-ops/references/migration-patterns.md
  59. 229 0
      skills/sqlite-ops/references/schema-patterns.md
  60. 38 294
      skills/structural-search/SKILL.md
  61. 36 0
      skills/structural-search/assets/rule-template.yaml
  62. 240 0
      skills/structural-search/references/advanced-usage.md
  63. 191 0
      skills/structural-search/references/go-rust-patterns.md
  64. 137 0
      skills/structural-search/references/js-ts-patterns.md
  65. 131 0
      skills/structural-search/references/python-patterns.md
  66. 163 0
      skills/structural-search/references/security-patterns.md
  67. 38 149
      skills/tailwind-patterns/SKILL.md
  68. 317 0
      skills/tailwind-patterns/references/component-patterns.md
  69. 160 0
      skills/testing-patterns/SKILL.md
  70. 293 0
      skills/testing-patterns/references/ci-testing.md
  71. 239 0
      skills/testing-patterns/references/mocking-strategies.md
  72. 214 0
      skills/testing-patterns/references/tdd-workflow.md
  73. 332 0
      skills/testing-patterns/references/test-data-patterns.md
  74. 38 0
      skills/testing-patterns/scripts/coverage-check.sh
  75. 49 168
      skills/tool-discovery/SKILL.md
  76. 458 0
      skills/tool-discovery/references/agents-catalog.md
  77. 292 0
      skills/tool-discovery/references/skills-catalog.md

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 112 - 857
agents/claude-architect.md


+ 122 - 0
skills/claude-code-debug/SKILL.md

@@ -0,0 +1,122 @@
+---
+name: claude-code-debug
+description: "Troubleshoot Claude Code extensions and behavior. Triggers on: debug, troubleshoot, not working, skill not loading, hook not running, agent not found."
+compatibility: "Claude Code CLI"
+allowed-tools: "Bash Read"
+depends-on: []
+related-skills: [claude-code-hooks, claude-code-headless, claude-code-templates]
+---
+
+# Claude Code Debug
+
+Troubleshoot extensions, hooks, and unexpected behavior.
+
+## Quick Diagnostics
+
+```bash
+# Enable debug mode
+claude --debug
+
+# Check loaded extensions
+/hooks        # View registered hooks
+/agents       # View available agents
+/memory       # View loaded memory files
+/config       # View current configuration
+```
+
+## Common Issues
+
+| Symptom | Quick Check |
+|---------|-------------|
+| Skill not activating | Verify description has trigger keywords |
+| Hook not running | Check `chmod +x`, run `/hooks` |
+| Agent not delegating | Add "Use proactively" to description |
+| MCP connection fails | Test server manually with `npx` |
+| Permission denied | Check settings.json allow rules |
+
+## Debug Mode Output
+
+```bash
+claude --debug
+# Shows:
+# - Hook execution and errors
+# - Skill loading status
+# - Subagent invocations
+# - Tool permission decisions
+# - MCP server connections
+```
+
+## Quick Fixes
+
+### Skill Not Loading
+
+```bash
+# Check structure
+ls -la .claude/skills/my-skill/
+# Must have: SKILL.md
+
+# Verify YAML frontmatter
+head -10 .claude/skills/my-skill/SKILL.md
+# Must start/end with ---
+
+# Check name matches directory
+grep "^name:" .claude/skills/my-skill/SKILL.md
+```
+
+### Hook Not Executing
+
+```bash
+# Make executable
+chmod +x .claude/hooks/my-hook.sh
+
+# Test manually
+echo '{"tool_name":"Bash"}' | .claude/hooks/my-hook.sh
+echo $?  # Check exit code
+
+# Verify JSON syntax
+jq '.' ~/.claude/settings.json
+```
+
+### Agent Not Being Used
+
+```bash
+# Check file location
+ls ~/.claude/agents/
+ls .claude/agents/
+
+# Verify description includes "Use for:" or "Use proactively"
+grep -i "use" agents/my-agent.md | head -5
+
+# Explicitly request
+# "Use the my-agent agent to analyze this"
+```
+
+## Validation
+
+```bash
+# Run all validations
+just test
+
+# YAML validation only
+just validate-yaml
+
+# Name matching only
+just validate-names
+```
+
+## Official Documentation
+
+- https://code.claude.com/docs/en/hooks - Hooks reference
+- https://code.claude.com/docs/en/skills - Skills reference
+- https://code.claude.com/docs/en/sub-agents - Custom subagents
+- https://code.claude.com/docs/en/settings - Settings configuration
+
+## Additional Resources
+
+- `./references/common-issues.md` - Issue → Solution lookup table
+- `./references/debug-commands.md` - All inspection commands
+- `./references/troubleshooting-flow.md` - Decision tree
+
+---
+
+**See Also:** `claude-code-hooks` for hook debugging, `claude-code-templates` for correct structure

+ 208 - 0
skills/claude-code-debug/references/common-issues.md

@@ -0,0 +1,208 @@
+# Common Issues Reference
+
+Issue → Cause → Solution lookup for Claude Code debugging.
+
+## Skills
+
+### Skill Never Activates
+
+| Cause | Solution |
+|-------|----------|
+| Description too vague | Add specific trigger keywords: "Triggers on: keyword1, keyword2" |
+| YAML syntax error | Check frontmatter opens/closes with `---` |
+| Wrong location | Must be `.claude/skills/name/SKILL.md` or `~/.claude/skills/name/SKILL.md` |
+| Name mismatch | Directory name must match `name:` field |
+| Missing SKILL.md | File must be named exactly `SKILL.md` (uppercase) |
+
+**Diagnosis:**
+```bash
+# Check structure
+ls -la .claude/skills/my-skill/
+
+# Verify frontmatter
+head -5 .claude/skills/my-skill/SKILL.md
+
+# Check name matches
+dirname=$(basename "$(pwd)")
+grep "^name: $dirname" SKILL.md
+```
+
+### Skill Loads But Doesn't Help
+
+| Cause | Solution |
+|-------|----------|
+| Content too generic | Add specific commands, examples, patterns |
+| Missing tool examples | Include `bash` blocks with real commands |
+| No "When to Use" | Add scenarios for activation |
+
+## Hooks
+
+### Hook Doesn't Execute
+
+| Cause | Solution |
+|-------|----------|
+| Not executable | `chmod +x hook-script.sh` |
+| Invalid JSON in settings | Validate with `jq '.' settings.json` |
+| Wrong matcher | Matchers are case-sensitive: `"Bash"` not `"bash"` |
+| Relative path fails | Use `$CLAUDE_PROJECT_DIR/path/to/script.sh` |
+| Script not found | Check path exists, use absolute paths |
+
+**Diagnosis:**
+```bash
+# Check executable
+ls -la .claude/hooks/
+
+# Test script manually
+echo '{"tool_name":"Test"}' | ./hook.sh
+echo "Exit code: $?"
+
+# Verify JSON
+jq '.' ~/.claude/settings.json
+
+# List registered hooks
+/hooks
+```
+
+### Hook Runs But Doesn't Block
+
+| Cause | Solution |
+|-------|----------|
+| Exit code not 2 | Use `exit 2` to block (not 1) |
+| Error on stdout | Put error messages on stderr: `echo "error" >&2` |
+| Blocking for wrong tool | Check matcher pattern matches tool name |
+
+### Hook Blocks Everything
+
+| Cause | Solution |
+|-------|----------|
+| Matcher too broad | Use specific matcher instead of `"*"` |
+| Logic error | Add debugging: `echo "DEBUG: $TOOL" >&2` |
+| Always exits 2 | Check conditional logic in script |
+
+## Agents
+
+### Custom Agent Not Used
+
+| Cause | Solution |
+|-------|----------|
+| Description doesn't match | Include "Use for: scenario1, scenario2" |
+| Wrong location | Must be `.claude/agents/name.md` or `~/.claude/agents/name.md` |
+| YAML invalid | Check frontmatter has `name:` and `description:` |
+| Name conflicts | Check for duplicate agent names |
+
+**Diagnosis:**
+```bash
+# List available agents
+/agents
+
+# Check file location
+ls ~/.claude/agents/
+ls .claude/agents/
+
+# Verify frontmatter
+head -10 .claude/agents/my-agent.md
+
+# Force usage
+# "Use the my-agent agent to help with this"
+```
+
+### Agent Doesn't Have Expected Tools
+
+| Cause | Solution |
+|-------|----------|
+| `tools` field restricts | Remove `tools` field to inherit all tools |
+| Permission denied | Check settings.json allow rules |
+| Tool not installed | Verify tool exists (e.g., `which jq`) |
+
+## MCP
+
+### MCP Server Won't Connect
+
+| Cause | Solution |
+|-------|----------|
+| Package not installed | `npm install -g @modelcontextprotocol/server-X` |
+| Missing env vars | Check `.mcp.json` for `${VAR}` references |
+| Server crashes | Test manually: `npx @modelcontextprotocol/server-X` |
+| Wrong transport | HTTP servers need `--transport http` |
+
+**Diagnosis:**
+```bash
+# Test server manually
+npx @modelcontextprotocol/server-filesystem
+
+# Check .mcp.json
+cat .mcp.json | jq '.'
+
+# Verify env vars exist
+echo $GITHUB_TOKEN
+```
+
+### MCP Tools Not Available
+
+| Cause | Solution |
+|-------|----------|
+| Server not in config | Add to `.mcp.json` or use `claude mcp add` |
+| Permission denied | Add `mcp__server__*` to allow rules |
+| Token limit | Reduce output size, check MAX_MCP_OUTPUT_TOKENS |
+
+## Memory & Rules
+
+### CLAUDE.md Not Loading
+
+| Cause | Solution |
+|-------|----------|
+| Wrong location | Must be `./CLAUDE.md` or `./.claude/CLAUDE.md` |
+| Import cycle | Max 5 hops for `@path` imports |
+| Syntax error | Check markdown syntax, especially code blocks |
+
+**Diagnosis:**
+```bash
+# Check what's loaded
+/memory
+
+# Verify file exists
+ls -la CLAUDE.md .claude/CLAUDE.md 2>/dev/null
+
+# Check imports
+grep "^@" CLAUDE.md
+```
+
+### Rules Not Applying
+
+| Cause | Solution |
+|-------|----------|
+| Wrong glob pattern | Test pattern: `ls .claude/rules/**/*.md` |
+| Path not matching | Check `paths:` field matches current file |
+| Lower priority | User rules load before project rules |
+
+## Permissions
+
+### Tool Blocked Unexpectedly
+
+| Cause | Solution |
+|-------|----------|
+| Not in allow list | Add to `permissions.allow` in settings.json |
+| In deny list | Remove from `permissions.deny` |
+| Hook blocking | Check PreToolUse hooks |
+
+**Diagnosis:**
+```bash
+# Check settings
+cat ~/.claude/settings.json | jq '.permissions'
+
+# Check project settings
+cat .claude/settings.local.json | jq '.permissions' 2>/dev/null
+
+# Debug mode shows permission decisions
+claude --debug
+```
+
+## General Debugging Steps
+
+1. **Enable debug mode**: `claude --debug`
+2. **Check file locations**: `ls -la .claude/` and `ls -la ~/.claude/`
+3. **Validate JSON**: `jq '.' settings.json`
+4. **Verify YAML**: Check frontmatter opens/closes with `---`
+5. **Test manually**: Run scripts directly, test MCP servers
+6. **Check permissions**: Review allow/deny rules
+7. **Use inspection commands**: `/hooks`, `/agents`, `/memory`, `/config`

+ 276 - 0
skills/claude-code-debug/references/debug-commands.md

@@ -0,0 +1,276 @@
+# Debug Commands Reference
+
+All inspection and debugging commands for Claude Code.
+
+## CLI Debug Mode
+
+```bash
+# Full debug output
+claude --debug
+
+# Verbose logging
+claude --verbose
+claude -v
+```
+
+### Debug Mode Shows
+
+| Category | Information |
+|----------|-------------|
+| Hooks | Loading, execution, errors, exit codes |
+| Skills | Discovery, activation, loading errors |
+| Agents | Invocation, tool access, context inheritance |
+| Permissions | Allow/deny decisions, rule matching |
+| MCP | Server connections, tool registration |
+| Context | Memory loading, rule application |
+
+## Slash Commands
+
+### /hooks
+
+List all registered hooks and their configuration.
+
+```
+/hooks
+
+Output:
+PreToolUse:
+  - Bash: ./hooks/validate-bash.sh (timeout: 5000ms)
+  - *: ./hooks/audit-log.sh (timeout: 3000ms)
+
+PostToolUse:
+  - Write: ./hooks/notify-write.sh
+```
+
+### /agents
+
+Manage and inspect subagents.
+
+```
+/agents
+
+Output:
+Available Agents:
+  Built-in:
+    - Explore (read-only codebase search)
+    - Plan (implementation planning)
+    - general-purpose (default)
+
+  Custom (user):
+    - python-expert
+    - react-expert
+
+  Custom (project):
+    - my-project-agent
+```
+
+Actions:
+- View agent details
+- Create new agent
+- Edit existing agent
+- Delete agent
+
+### /memory
+
+View and edit memory files (CLAUDE.md).
+
+```
+/memory
+
+Output:
+Loaded Memory Files:
+  1. ~/.claude/CLAUDE.md (user)
+  2. ./CLAUDE.md (project)
+  3. ./.claude/CLAUDE.md (project)
+
+Imports:
+  - @README.md
+  - @docs/api.md
+```
+
+Opens system editor for editing when invoked.
+
+### /config
+
+View current configuration state.
+
+```
+/config
+
+Output:
+Permission Mode: default
+Model: claude-sonnet-4-20250514
+
+Permissions:
+  Allow: Bash(git:*), Bash(npm:*), Read, Write
+  Deny: Bash(rm -rf:*)
+
+Active MCP Servers:
+  - filesystem: /Users/me/.npm/_npx/...
+  - github: /Users/me/.npm/_npx/...
+```
+
+### /plugin
+
+Browse and manage installed plugins.
+
+```
+/plugin
+
+Output:
+Installed Plugins:
+  - my-plugin (v1.0.0)
+    Commands: /my-command
+    Skills: my-skill
+
+Marketplaces:
+  - awesome-plugins (github:user/repo)
+```
+
+## File System Inspection
+
+### Check Extension Structure
+
+```bash
+# Skills
+ls -la .claude/skills/
+ls -la ~/.claude/skills/
+
+# Agents
+ls -la .claude/agents/
+ls -la ~/.claude/agents/
+
+# Commands
+ls -la .claude/commands/
+ls -la ~/.claude/commands/
+
+# Rules
+ls -la .claude/rules/
+ls -la ~/.claude/rules/
+
+# Hooks
+ls -la .claude/hooks/
+```
+
+### Verify Configuration Files
+
+```bash
+# Global settings
+cat ~/.claude/settings.json | jq '.'
+
+# Project settings
+cat .claude/settings.local.json | jq '.'
+
+# MCP configuration
+cat .mcp.json | jq '.'
+```
+
+### Check YAML Frontmatter
+
+```bash
+# View frontmatter
+head -20 path/to/extension.md
+
+# Extract name field
+grep "^name:" path/to/extension.md
+
+# Validate YAML structure
+head -20 path/to/extension.md | grep -E "^---|^name:|^description:"
+```
+
+## Process Debugging
+
+### Test Hook Scripts
+
+```bash
+# Test with sample input
+echo '{"tool_name":"Bash","tool_input":{"command":"ls"}}' | ./hook.sh
+
+# Check exit code
+echo $?
+
+# View stderr output
+echo '{"tool_name":"Bash"}' | ./hook.sh 2>&1
+```
+
+### Test MCP Servers
+
+```bash
+# Run server directly
+npx @modelcontextprotocol/server-filesystem
+
+# Check if package exists
+npm view @modelcontextprotocol/server-github
+
+# Verify env vars
+printenv | grep -i token
+```
+
+## Log Analysis
+
+### Hook Audit Logs
+
+```bash
+# View recent hook activity
+tail -50 .claude/audit.log
+
+# Search for errors
+grep -i error .claude/audit.log
+
+# Count by tool
+awk -F'|' '{print $2}' .claude/audit.log | sort | uniq -c | sort -rn
+```
+
+### Session Logs
+
+```bash
+# Find session files
+ls -la ~/.claude/sessions/
+
+# View recent session
+cat ~/.claude/sessions/$(ls -t ~/.claude/sessions/ | head -1)
+```
+
+## Environment Verification
+
+```bash
+# Claude Code version
+claude --version
+
+# Check API key is set
+echo ${ANTHROPIC_API_KEY:0:10}...
+
+# Project directory
+echo $CLAUDE_PROJECT_DIR
+
+# Current working directory
+pwd
+```
+
+## Validation Commands
+
+```bash
+# Run full validation suite (claude-mods)
+just test
+
+# YAML validation only
+just validate-yaml
+
+# Name matching validation
+just validate-names
+
+# Windows validation
+just test-win
+```
+
+## Quick Reference
+
+| Command | Purpose |
+|---------|---------|
+| `claude --debug` | Enable debug output |
+| `/hooks` | List registered hooks |
+| `/agents` | Manage subagents |
+| `/memory` | View/edit memory files |
+| `/config` | View configuration |
+| `/plugin` | Manage plugins |
+| `just test` | Run validations |

+ 213 - 0
skills/claude-code-debug/references/troubleshooting-flow.md

@@ -0,0 +1,213 @@
+# Troubleshooting Flow
+
+Decision trees for diagnosing Claude Code issues.
+
+## Extension Not Working
+
+```
+Extension not working?
+│
+├─ What type?
+│  │
+│  ├─ Skill ─────────────► Go to: Skill Debugging Flow
+│  ├─ Hook ──────────────► Go to: Hook Debugging Flow
+│  ├─ Agent ─────────────► Go to: Agent Debugging Flow
+│  ├─ Command ───────────► Go to: Command Debugging Flow
+│  └─ MCP ───────────────► Go to: MCP Debugging Flow
+```
+
+## Skill Debugging Flow
+
+```
+Skill not activating?
+│
+├─ Does directory exist?
+│  ├─ No ──► Create: mkdir -p .claude/skills/my-skill
+│  └─ Yes
+│      │
+│      ├─ Does SKILL.md exist (exact case)?
+│      │  ├─ No ──► Create SKILL.md (not skill.md)
+│      │  └─ Yes
+│      │      │
+│      │      ├─ Does frontmatter start with ---?
+│      │      │  ├─ No ──► Add --- at line 1
+│      │      │  └─ Yes
+│      │      │      │
+│      │      │      ├─ Does frontmatter end with ---?
+│      │      │      │  ├─ No ──► Add --- after last field
+│      │      │      │  └─ Yes
+│      │      │      │      │
+│      │      │      │      ├─ Does name: match directory?
+│      │      │      │      │  ├─ No ──► Fix name to match
+│      │      │      │      │  └─ Yes
+│      │      │      │      │      │
+│      │      │      │      │      ├─ Does description have triggers?
+│      │      │      │      │      │  ├─ No ──► Add "Triggers on: x, y, z"
+│      │      │      │      │      │  └─ Yes
+│      │      │      │      │      │      │
+│      │      │      │      │      │      └─ Try: claude --debug
+│      │      │      │      │      │         Look for skill loading errors
+```
+
+## Hook Debugging Flow
+
+```
+Hook not running?
+│
+├─ Is script executable?
+│  ├─ No ──► chmod +x script.sh
+│  └─ Yes
+│      │
+│      ├─ Is settings.json valid JSON?
+│      │  ├─ No ──► Fix JSON syntax (jq '.' to validate)
+│      │  └─ Yes
+│      │      │
+│      │      ├─ Is matcher correct? (case-sensitive!)
+│      │      │  ├─ "bash" ──► Change to "Bash"
+│      │      │  └─ Correct
+│      │      │      │
+│      │      │      ├─ Does path exist?
+│      │      │      │  ├─ No ──► Fix path, use $CLAUDE_PROJECT_DIR
+│      │      │      │  └─ Yes
+│      │      │      │      │
+│      │      │      │      ├─ Does script work manually?
+│      │      │      │      │  │  echo '{"tool_name":"X"}' | ./script.sh
+│      │      │      │      │  │
+│      │      │      │      │  ├─ Fails ──► Fix script errors
+│      │      │      │      │  └─ Works
+│      │      │      │      │      │
+│      │      │      │      │      └─ Run: /hooks
+│      │      │      │      │         Is hook listed?
+│      │      │      │      │         ├─ No ──► Check settings location
+│      │      │      │      │         └─ Yes ──► Try claude --debug
+```
+
+## Agent Debugging Flow
+
+```
+Agent not being used?
+│
+├─ Is file in correct location?
+│  ├─ ~/.claude/agents/name.md (user)
+│  ├─ .claude/agents/name.md (project)
+│  │
+│  ├─ Wrong location ──► Move file
+│  └─ Correct
+│      │
+│      ├─ Does filename match name: field?
+│      │  ├─ No ──► Rename file or fix name field
+│      │  └─ Yes
+│      │      │
+│      │      ├─ Does description include "Use for:"?
+│      │      │  ├─ No ──► Add: "Use for: scenario1, scenario2"
+│      │      │  └─ Yes
+│      │      │      │
+│      │      │      ├─ Run: /agents
+│      │      │      │  Is agent listed?
+│      │      │      │  │
+│      │      │      │  ├─ No ──► Check YAML frontmatter syntax
+│      │      │      │  └─ Yes
+│      │      │      │      │
+│      │      │      │      └─ Try explicit request:
+│      │      │      │         "Use the my-agent agent for this"
+```
+
+## Command Debugging Flow
+
+```
+Command not working?
+│
+├─ Is file in correct location?
+│  ├─ ~/.claude/commands/name.md (user)
+│  ├─ .claude/commands/name.md (project)
+│  │
+│  ├─ Wrong location ──► Move file
+│  └─ Correct
+│      │
+│      ├─ Does /command-name show in help?
+│      │  ├─ No ──► Check YAML frontmatter
+│      │  └─ Yes
+│      │      │
+│      │      └─ Command runs but fails?
+│      │         ├─ Check instructions in command file
+│      │         └─ Verify required tools are available
+```
+
+## MCP Debugging Flow
+
+```
+MCP server not connecting?
+│
+├─ Is server installed?
+│  │  npx @modelcontextprotocol/server-X
+│  │
+│  ├─ "not found" ──► npm install -g @modelcontextprotocol/server-X
+│  └─ Runs
+│      │
+│      ├─ Is server in .mcp.json?
+│      │  ├─ No ──► Add server config or use: claude mcp add
+│      │  └─ Yes
+│      │      │
+│      │      ├─ Are env vars set?
+│      │      │  │  Check ${VAR} references in .mcp.json
+│      │      │  │
+│      │      │  ├─ Missing ──► Set env vars or add to .env
+│      │      │  └─ Set
+│      │      │      │
+│      │      │      ├─ Is transport correct?
+│      │      │      │  │  HTTP servers need --transport http
+│      │      │      │  │
+│      │      │      │  ├─ Wrong ──► Fix transport config
+│      │      │      │  └─ Correct
+│      │      │      │      │
+│      │      │      │      └─ Try: claude --debug
+│      │      │      │         Look for MCP connection errors
+```
+
+## Permission Debugging Flow
+
+```
+Tool blocked unexpectedly?
+│
+├─ Check deny rules first
+│  │  jq '.permissions.deny' ~/.claude/settings.json
+│  │
+│  ├─ Tool in deny ──► Remove from deny list
+│  └─ Not in deny
+│      │
+│      ├─ Check allow rules
+│      │  │  jq '.permissions.allow' ~/.claude/settings.json
+│      │  │
+│      │  ├─ Tool not in allow ──► Add to allow list
+│      │  └─ In allow
+│      │      │
+│      │      ├─ Is pattern correct?
+│      │      │  │  "Bash(git:*)" allows only git commands
+│      │      │  │
+│      │      │  ├─ Pattern too narrow ──► Broaden pattern
+│      │      │  └─ Pattern correct
+│      │      │      │
+│      │      │      ├─ Check PreToolUse hooks
+│      │      │      │  │  /hooks
+│      │      │      │  │
+│      │      │      │  ├─ Hook blocking ──► Fix hook logic
+│      │      │      │  └─ No blocking hook
+│      │      │      │      │
+│      │      │      │      └─ Run: claude --debug
+│      │      │      │         Check permission decision logs
+```
+
+## General Debugging Checklist
+
+When all else fails:
+
+1. [ ] Run `claude --debug` and read output carefully
+2. [ ] Verify file locations and names
+3. [ ] Validate all JSON with `jq '.'`
+4. [ ] Check YAML frontmatter syntax
+5. [ ] Test components in isolation
+6. [ ] Check file permissions (`ls -la`)
+7. [ ] Verify environment variables
+8. [ ] Review recent changes to config
+9. [ ] Try with a fresh session
+10. [ ] Check Claude Code version (`claude --version`)

+ 128 - 0
skills/claude-code-headless/SKILL.md

@@ -0,0 +1,128 @@
+---
+name: claude-code-headless
+description: "Run Claude Code programmatically without interactive UI. Triggers on: headless, CLI automation, --print, output-format, stream-json, CI/CD, scripting."
+compatibility: "Claude Code CLI"
+allowed-tools: "Bash Read"
+depends-on: []
+related-skills: [claude-code-hooks, claude-code-debug]
+---
+
+# Claude Code Headless Mode
+
+Run Claude Code from scripts without interactive UI.
+
+## Quick Start
+
+```bash
+# Basic headless execution
+claude -p "Explain this code" --allowedTools "Read,Grep"
+
+# JSON output for parsing
+claude -p "List files" --output-format json
+
+# Continue conversation
+claude -p "Start analysis" --output-format json > result.json
+session=$(jq -r '.session_id' result.json)
+claude --resume "$session" "Now fix the issues"
+```
+
+## Essential CLI Options
+
+| Flag | Description |
+|------|-------------|
+| `-p`, `--print` | Non-interactive (headless) mode |
+| `--output-format` | text, json, stream-json |
+| `-r`, `--resume` | Resume by session ID |
+| `-c`, `--continue` | Continue most recent session |
+| `--allowedTools` | Comma-separated allowed tools |
+| `--disallowedTools` | Comma-separated denied tools |
+| `--mcp-config` | Path to MCP server config JSON |
+| `--verbose` | Enable verbose logging |
+| `--append-system-prompt` | Add to system prompt |
+
+## Permission Modes
+
+| Mode | Flag | Effect |
+|------|------|--------|
+| Default | (none) | Prompt for permissions |
+| Accept edits | `--permission-mode acceptEdits` | Auto-accept file changes |
+| Bypass | `--permission-mode bypassPermissions` | Skip all prompts |
+
+## Output Formats
+
+### Text (default)
+```bash
+claude -p "Hello"
+# Outputs: Human-readable response
+```
+
+### JSON
+```bash
+claude -p "Hello" --output-format json
+```
+```json
+{
+  "type": "result",
+  "subtype": "success",
+  "result": "Hello! How can I help?",
+  "session_id": "abc123",
+  "total_cost_usd": 0.001,
+  "duration_ms": 1234,
+  "num_turns": 1
+}
+```
+
+### Stream-JSON
+```bash
+claude -p "Hello" --output-format stream-json
+# Real-time JSONL output for each message
+```
+
+## Common Patterns
+
+### Script with tool restrictions
+```bash
+claude -p "Analyze the codebase" \
+  --allowedTools "Read,Grep,Glob" \
+  --disallowedTools "Write,Edit,Bash"
+```
+
+### CI/CD integration
+```bash
+claude -p "Review this PR diff" \
+  --permission-mode acceptEdits \
+  --output-format json \
+  --append-system-prompt "Focus on security issues"
+```
+
+### Multi-turn automation
+```bash
+session=$(claude -p "Start task" --output-format json | jq -r '.session_id')
+claude --resume "$session" "Continue with step 2"
+claude --resume "$session" "Finalize and report"
+```
+
+## Error Handling
+
+```bash
+result=$(claude -p "Task" --output-format json)
+if [[ $(echo "$result" | jq -r '.is_error') == "true" ]]; then
+    echo "Error: $(echo "$result" | jq -r '.result')" >&2
+    exit 1
+fi
+```
+
+## Official Documentation
+
+- https://code.claude.com/docs/en/headless - Headless mode reference
+- https://code.claude.com/docs/en/settings - Settings and permissions
+
+## Additional Resources
+
+- `./references/cli-options.md` - Complete CLI flag reference
+- `./references/output-formats.md` - Output format schemas
+- `./references/integration-patterns.md` - CI/CD and scripting examples
+
+---
+
+**See Also:** `claude-code-hooks` for automation events, `claude-code-debug` for troubleshooting

+ 207 - 0
skills/claude-code-headless/references/cli-options.md

@@ -0,0 +1,207 @@
+# CLI Options Reference
+
+Complete reference for Claude Code CLI flags.
+
+## Core Options
+
+### Input/Output
+
+| Flag | Short | Description |
+|------|-------|-------------|
+| `--print` | `-p` | Non-interactive mode (required for headless) |
+| `--output-format` | | Output format: text, json, stream-json |
+| `--verbose` | `-v` | Enable verbose/debug logging |
+| `--quiet` | `-q` | Suppress non-essential output |
+
+### Session Management
+
+| Flag | Short | Description |
+|------|-------|-------------|
+| `--resume` | `-r` | Resume conversation by session ID |
+| `--continue` | `-c` | Continue most recent conversation |
+| `--session-id` | | Specify session ID for new session |
+
+### Prompt Configuration
+
+| Flag | Description |
+|------|-------------|
+| `--append-system-prompt` | Append text to system prompt |
+| `--prepend-system-prompt` | Prepend text to system prompt |
+| `--system-prompt` | Replace entire system prompt |
+
+### Tool Control
+
+| Flag | Description |
+|------|-------------|
+| `--allowedTools` | Comma-separated list of allowed tools |
+| `--disallowedTools` | Comma-separated list of denied tools |
+| `--mcp-config` | Path to MCP server configuration JSON |
+
+### Permission Control
+
+| Flag | Description |
+|------|-------------|
+| `--permission-mode` | Permission handling mode |
+
+Permission modes:
+- `default` - Ask for permission (blocks in headless)
+- `acceptEdits` - Auto-accept file modifications
+- `bypassPermissions` - Skip all permission prompts
+
+### Model Selection
+
+| Flag | Description |
+|------|-------------|
+| `--model` | Model to use: sonnet, opus, haiku |
+
+## Usage Examples
+
+### Basic Headless
+
+```bash
+# Simple query
+claude -p "What is 2+2?"
+
+# With file context
+cat file.py | claude -p "Explain this code"
+
+# From file
+claude -p "$(cat prompt.txt)"
+```
+
+### Tool Restrictions
+
+```bash
+# Read-only mode
+claude -p "Analyze codebase" \
+  --allowedTools "Read,Grep,Glob,WebFetch,WebSearch" \
+  --disallowedTools "Write,Edit,Bash,Task"
+
+# Specific tools only
+claude -p "Search for bugs" \
+  --allowedTools "Read,Grep"
+```
+
+### Session Continuation
+
+```bash
+# Start session, capture ID
+result=$(claude -p "Start analysis" --output-format json)
+session_id=$(echo "$result" | jq -r '.session_id')
+
+# Continue with context
+claude -r "$session_id" "What did you find?"
+
+# Continue most recent
+claude -c "Add more details"
+```
+
+### System Prompt Modification
+
+```bash
+# Add context
+claude -p "Review code" \
+  --append-system-prompt "Focus on security vulnerabilities. Output findings as markdown."
+
+# Full replacement
+claude -p "Hello" \
+  --system-prompt "You are a helpful assistant that only speaks in haiku."
+```
+
+### MCP Integration
+
+```bash
+# Use MCP servers from config
+claude -p "Query the database" \
+  --mcp-config ./mcp-servers.json
+
+# With specific tools
+claude -p "Fetch from GitHub" \
+  --mcp-config ./mcp-servers.json \
+  --allowedTools "mcp__github__*"
+```
+
+### Debugging
+
+```bash
+# Verbose output
+claude -p "Debug this" --verbose
+
+# Debug mode (shows internal operations)
+claude --debug -p "Analyze"
+```
+
+## Input Methods
+
+### Stdin Piping
+
+```bash
+# Pipe file content
+cat error.log | claude -p "Explain these errors"
+
+# Pipe command output
+git diff | claude -p "Review this diff"
+
+# Heredoc
+claude -p "$(cat <<EOF
+Analyze this data:
+- Item 1
+- Item 2
+EOF
+)"
+```
+
+### File Input
+
+```bash
+# Read prompt from file
+claude -p "$(cat prompt.md)"
+
+# With context files
+claude -p "Review: $(cat src/main.ts)"
+```
+
+## Exit Codes
+
+| Code | Meaning |
+|------|---------|
+| 0 | Success |
+| 1 | General error |
+| 2 | Invalid arguments |
+
+## Environment Variables
+
+| Variable | Description |
+|----------|-------------|
+| `ANTHROPIC_API_KEY` | API key for Claude |
+| `CLAUDE_PROJECT_DIR` | Override project directory |
+| `NO_COLOR` | Disable colored output |
+
+## Flag Combinations
+
+### CI/CD Pipeline
+
+```bash
+claude -p "Run tests and report" \
+  --permission-mode acceptEdits \
+  --output-format json \
+  --allowedTools "Bash,Read,Write"
+```
+
+### Security Audit
+
+```bash
+claude -p "Security review" \
+  --allowedTools "Read,Grep,WebSearch" \
+  --disallowedTools "Write,Edit,Bash" \
+  --append-system-prompt "Report vulnerabilities in JSON format"
+```
+
+### Documentation Generation
+
+```bash
+claude -p "Generate API docs" \
+  --permission-mode acceptEdits \
+  --allowedTools "Read,Write,Glob" \
+  --output-format json
+```

+ 373 - 0
skills/claude-code-headless/references/integration-patterns.md

@@ -0,0 +1,373 @@
+# Integration Patterns
+
+Patterns for integrating Claude Code into CI/CD, scripts, and automation.
+
+## CI/CD Pipelines
+
+### GitHub Actions
+
+```yaml
+name: Claude Code Review
+
+on:
+  pull_request:
+    types: [opened, synchronize]
+
+jobs:
+  review:
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@v4
+
+      - name: Get PR diff
+        id: diff
+        run: |
+          gh pr diff ${{ github.event.pull_request.number }} > diff.txt
+        env:
+          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+
+      - name: Run Claude review
+        run: |
+          result=$(cat diff.txt | claude -p "Review this PR diff for:
+          - Security vulnerabilities
+          - Performance issues
+          - Code quality
+
+          Output as markdown." \
+            --output-format json \
+            --allowedTools "Read,Grep")
+
+          echo "$result" | jq -r '.result' > review.md
+        env:
+          ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
+
+      - name: Post review comment
+        run: |
+          gh pr comment ${{ github.event.pull_request.number }} \
+            --body-file review.md
+        env:
+          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+```
+
+### GitLab CI
+
+```yaml
+claude-review:
+  stage: review
+  script:
+    - git diff origin/main...HEAD > diff.txt
+    - |
+      cat diff.txt | claude -p "Security review" \
+        --output-format json \
+        --allowedTools "Read" \
+        > review.json
+    - cat review.json | jq -r '.result' > review.md
+  artifacts:
+    paths:
+      - review.md
+  only:
+    - merge_requests
+```
+
+### Jenkins
+
+```groovy
+pipeline {
+    agent any
+    environment {
+        ANTHROPIC_API_KEY = credentials('anthropic-api-key')
+    }
+    stages {
+        stage('Claude Analysis') {
+            steps {
+                script {
+                    def result = sh(
+                        script: '''
+                            claude -p "Analyze build issues" \
+                                --output-format json \
+                                --allowedTools "Read,Bash"
+                        ''',
+                        returnStdout: true
+                    )
+                    def json = readJSON text: result
+                    if (json.is_error) {
+                        error "Claude analysis failed: ${json.result}"
+                    }
+                }
+            }
+        }
+    }
+}
+```
+
+## Shell Scripts
+
+### PR Review Script
+
+```bash
+#!/bin/bash
+set -euo pipefail
+
+audit_pr() {
+    local pr_number="$1"
+
+    # Get PR diff
+    diff=$(gh pr diff "$pr_number")
+
+    # Run Claude analysis
+    result=$(echo "$diff" | claude -p \
+        --append-system-prompt "Security review. Output JSON: {severity, findings, recommendations}" \
+        --output-format json \
+        --allowedTools "Read,Grep,WebSearch")
+
+    # Check for errors
+    if [[ $(echo "$result" | jq -r '.is_error') == "true" ]]; then
+        echo "Error: $(echo "$result" | jq -r '.result')" >&2
+        return 1
+    fi
+
+    echo "$result" | jq -r '.result'
+}
+
+# Usage
+audit_pr 123
+```
+
+### Batch Processing
+
+```bash
+#!/bin/bash
+set -euo pipefail
+
+process_files() {
+    local pattern="$1"
+    local prompt="$2"
+
+    find . -name "$pattern" -print0 | while IFS= read -r -d '' file; do
+        echo "Processing: $file"
+
+        result=$(cat "$file" | claude -p "$prompt" \
+            --output-format json \
+            --allowedTools "Read")
+
+        if [[ $(echo "$result" | jq -r '.is_error') == "false" ]]; then
+            echo "$result" | jq -r '.result' > "${file}.analysis.md"
+        fi
+    done
+}
+
+# Usage
+process_files "*.py" "Analyze this Python file for issues"
+```
+
+### Multi-Turn Workflow
+
+```bash
+#!/bin/bash
+set -euo pipefail
+
+run_workflow() {
+    # Step 1: Initial analysis
+    result=$(claude -p "Analyze the codebase structure" \
+        --output-format json \
+        --allowedTools "Read,Glob,Grep")
+
+    session=$(echo "$result" | jq -r '.session_id')
+    echo "Session: $session"
+
+    # Step 2: Deep dive with context
+    result=$(claude --resume "$session" \
+        "Now examine the authentication module in detail" \
+        --output-format json)
+
+    # Step 3: Generate report
+    claude --resume "$session" \
+        "Generate a security report in markdown" \
+        --output-format json | jq -r '.result' > report.md
+
+    echo "Report saved to report.md"
+}
+
+run_workflow
+```
+
+## Pre-commit Hooks
+
+### Python Code Review
+
+```bash
+#!/bin/bash
+# .git/hooks/pre-commit
+
+staged_files=$(git diff --cached --name-only --diff-filter=ACM | grep '\.py$' || true)
+
+if [[ -n "$staged_files" ]]; then
+    echo "Running Claude review on staged Python files..."
+
+    for file in $staged_files; do
+        result=$(cat "$file" | claude -p \
+            "Quick code review. Report only critical issues. Be concise." \
+            --output-format json \
+            --allowedTools "Read" 2>/dev/null)
+
+        if [[ $(echo "$result" | jq -r '.is_error') == "false" ]]; then
+            review=$(echo "$result" | jq -r '.result')
+            if [[ "$review" != *"no issues"* ]] && [[ "$review" != *"looks good"* ]]; then
+                echo "Review for $file:"
+                echo "$review"
+                echo ""
+            fi
+        fi
+    done
+fi
+```
+
+## Scheduled Tasks
+
+### Daily Code Quality Report
+
+```bash
+#!/bin/bash
+# Run via cron: 0 8 * * * /path/to/daily-report.sh
+
+REPORT_DIR="/var/reports/claude"
+DATE=$(date +%Y-%m-%d)
+
+mkdir -p "$REPORT_DIR"
+
+cd /path/to/project
+
+result=$(claude -p "Generate a daily code quality report covering:
+1. Recent changes summary
+2. Potential issues
+3. Recommendations
+
+Use git log for recent changes." \
+    --output-format json \
+    --allowedTools "Bash,Read,Grep")
+
+echo "$result" | jq -r '.result' > "$REPORT_DIR/report-$DATE.md"
+
+# Email or Slack notification
+# curl -X POST "$SLACK_WEBHOOK" -d "{\"text\": \"Daily report ready\"}"
+```
+
+## Web Application Integration
+
+### Express.js Endpoint
+
+```javascript
+const express = require('express');
+const { spawn } = require('child_process');
+
+const app = express();
+app.use(express.json());
+
+app.post('/api/claude', async (req, res) => {
+    const { prompt, tools } = req.body;
+
+    const args = ['-p', prompt, '--output-format', 'json'];
+    if (tools) {
+        args.push('--allowedTools', tools.join(','));
+    }
+
+    const claude = spawn('claude', args);
+    let output = '';
+
+    claude.stdout.on('data', (data) => {
+        output += data.toString();
+    });
+
+    claude.on('close', (code) => {
+        try {
+            const result = JSON.parse(output);
+            res.json(result);
+        } catch (e) {
+            res.status(500).json({ error: 'Failed to parse response' });
+        }
+    });
+});
+
+app.listen(3000);
+```
+
+### Python FastAPI
+
+```python
+from fastapi import FastAPI, HTTPException
+from pydantic import BaseModel
+import subprocess
+import json
+
+app = FastAPI()
+
+class ClaudeRequest(BaseModel):
+    prompt: str
+    tools: list[str] | None = None
+
+@app.post("/api/claude")
+async def run_claude(request: ClaudeRequest):
+    args = ["claude", "-p", request.prompt, "--output-format", "json"]
+
+    if request.tools:
+        args.extend(["--allowedTools", ",".join(request.tools)])
+
+    proc = subprocess.run(args, capture_output=True, text=True)
+
+    try:
+        result = json.loads(proc.stdout)
+        return result
+    except json.JSONDecodeError:
+        raise HTTPException(status_code=500, detail="Failed to parse response")
+```
+
+## Error Handling Patterns
+
+### Retry with Backoff
+
+```bash
+#!/bin/bash
+
+run_with_retry() {
+    local max_attempts=3
+    local attempt=1
+    local delay=5
+
+    while [[ $attempt -le $max_attempts ]]; do
+        result=$(claude -p "$1" --output-format json 2>&1)
+
+        if [[ $(echo "$result" | jq -r '.is_error // true') == "false" ]]; then
+            echo "$result"
+            return 0
+        fi
+
+        echo "Attempt $attempt failed, retrying in ${delay}s..." >&2
+        sleep $delay
+        attempt=$((attempt + 1))
+        delay=$((delay * 2))
+    done
+
+    echo "All attempts failed" >&2
+    return 1
+}
+```
+
+### Graceful Degradation
+
+```bash
+#!/bin/bash
+
+analyze_with_fallback() {
+    # Try Claude first
+    result=$(claude -p "$1" --output-format json 2>/dev/null)
+
+    if [[ -z "$result" ]] || [[ $(echo "$result" | jq -r '.is_error') == "true" ]]; then
+        echo "Claude unavailable, using fallback analysis" >&2
+        # Fallback to simpler analysis
+        run_basic_linter "$2"
+        return
+    fi
+
+    echo "$result" | jq -r '.result'
+}
+```

+ 202 - 0
skills/claude-code-headless/references/output-formats.md

@@ -0,0 +1,202 @@
+# Output Formats Reference
+
+Detailed documentation for Claude Code output formats.
+
+## Text Format (Default)
+
+Human-readable output for terminal use.
+
+```bash
+claude -p "Hello"
+# Output: Hello! How can I help you today?
+```
+
+Characteristics:
+- Plain text response
+- May include ANSI colors (disable with `NO_COLOR=1`)
+- No metadata (session ID, cost, etc.)
+- Best for interactive scripts
+
+## JSON Format
+
+Structured output for programmatic parsing.
+
+```bash
+claude -p "Hello" --output-format json
+```
+
+### Success Response
+
+```json
+{
+  "type": "result",
+  "subtype": "success",
+  "result": "Hello! How can I help you today?",
+  "session_id": "session_abc123xyz",
+  "total_cost_usd": 0.00123,
+  "duration_ms": 1542,
+  "num_turns": 1,
+  "is_error": false
+}
+```
+
+### Error Response
+
+```json
+{
+  "type": "result",
+  "subtype": "error",
+  "result": "Error message here",
+  "session_id": "session_abc123xyz",
+  "total_cost_usd": 0.0005,
+  "duration_ms": 234,
+  "num_turns": 0,
+  "is_error": true
+}
+```
+
+### Field Reference
+
+| Field | Type | Description |
+|-------|------|-------------|
+| `type` | string | Always "result" |
+| `subtype` | string | "success" or "error" |
+| `result` | string | Response text or error message |
+| `session_id` | string | Session identifier for resumption |
+| `total_cost_usd` | number | Total API cost in USD |
+| `duration_ms` | number | Total execution time in milliseconds |
+| `num_turns` | number | Number of conversation turns |
+| `is_error` | boolean | Whether result is an error |
+
+### Parsing Examples
+
+```bash
+# Extract session ID
+session=$(claude -p "Start" --output-format json | jq -r '.session_id')
+
+# Check for errors
+result=$(claude -p "Task" --output-format json)
+if [[ $(echo "$result" | jq -r '.is_error') == "true" ]]; then
+    echo "Error: $(echo "$result" | jq -r '.result')"
+    exit 1
+fi
+
+# Get cost
+cost=$(echo "$result" | jq -r '.total_cost_usd')
+echo "Cost: \$${cost}"
+```
+
+## Stream-JSON Format
+
+Real-time JSONL (JSON Lines) output for streaming applications.
+
+```bash
+claude -p "Count to 5" --output-format stream-json
+```
+
+### Message Types
+
+#### Assistant Message
+
+```json
+{"type": "assistant", "content": "1", "timestamp": "2024-01-15T10:30:00Z"}
+{"type": "assistant", "content": "2", "timestamp": "2024-01-15T10:30:01Z"}
+```
+
+#### Tool Use
+
+```json
+{"type": "tool_use", "tool": "Read", "input": {"file_path": "/path/to/file"}, "timestamp": "..."}
+{"type": "tool_result", "tool": "Read", "output": "file contents...", "timestamp": "..."}
+```
+
+#### Final Result
+
+```json
+{"type": "result", "session_id": "...", "total_cost_usd": 0.01, "duration_ms": 5000}
+```
+
+### Stream Processing
+
+```bash
+# Process each line as it arrives
+claude -p "Long task" --output-format stream-json | while IFS= read -r line; do
+    type=$(echo "$line" | jq -r '.type')
+    case "$type" in
+        assistant)
+            echo "Claude: $(echo "$line" | jq -r '.content')"
+            ;;
+        tool_use)
+            echo "Using: $(echo "$line" | jq -r '.tool')"
+            ;;
+        result)
+            echo "Done! Cost: \$$(echo "$line" | jq -r '.total_cost_usd')"
+            ;;
+    esac
+done
+```
+
+### Node.js Stream Processing
+
+```javascript
+const { spawn } = require('child_process');
+const readline = require('readline');
+
+const claude = spawn('claude', ['-p', 'Task', '--output-format', 'stream-json']);
+
+const rl = readline.createInterface({ input: claude.stdout });
+
+rl.on('line', (line) => {
+    const event = JSON.parse(line);
+    switch (event.type) {
+        case 'assistant':
+            process.stdout.write(event.content);
+            break;
+        case 'result':
+            console.log(`\nCost: $${event.total_cost_usd}`);
+            break;
+    }
+});
+```
+
+### Python Stream Processing
+
+```python
+import subprocess
+import json
+
+proc = subprocess.Popen(
+    ['claude', '-p', 'Task', '--output-format', 'stream-json'],
+    stdout=subprocess.PIPE,
+    text=True
+)
+
+for line in proc.stdout:
+    event = json.loads(line)
+    if event['type'] == 'assistant':
+        print(event['content'], end='', flush=True)
+    elif event['type'] == 'result':
+        print(f"\nCost: ${event['total_cost_usd']}")
+```
+
+## Format Comparison
+
+| Feature | text | json | stream-json |
+|---------|------|------|-------------|
+| Real-time output | Yes | No | Yes |
+| Structured data | No | Yes | Yes |
+| Session ID | No | Yes | Yes |
+| Cost tracking | No | Yes | Yes |
+| Easy parsing | No | Yes | Yes |
+| Best for | Humans | Scripts | Real-time apps |
+
+## Format Selection Guide
+
+| Use Case | Format |
+|----------|--------|
+| Interactive terminal | text |
+| CI/CD pipelines | json |
+| Web applications | stream-json |
+| Cost tracking | json |
+| Session management | json |
+| Live progress display | stream-json |

+ 114 - 0
skills/claude-code-hooks/SKILL.md

@@ -0,0 +1,114 @@
+---
+name: claude-code-hooks
+description: "Claude Code hook system for pre/post tool execution. Triggers on: hooks, PreToolUse, PostToolUse, hook script, tool validation, audit logging."
+compatibility: "Claude Code CLI with settings.json support"
+allowed-tools: "Bash Read Write"
+depends-on: []
+related-skills: [claude-code-debug, claude-code-headless]
+---
+
+# Claude Code Hooks
+
+Execute custom scripts before/after Claude Code tool invocations.
+
+## Quick Reference
+
+| Event | When | Has Matcher |
+|-------|------|-------------|
+| `PreToolUse` | Before tool execution | Yes |
+| `PostToolUse` | After tool completes | Yes |
+| `PermissionRequest` | Permission dialog shown | Yes |
+| `Notification` | Notifications sent | Yes |
+| `UserPromptSubmit` | User submits prompt | No |
+| `Stop` | Agent finishes | No |
+| `SubagentStop` | Subagent finishes | No |
+| `PreCompact` | Before context compaction | No |
+| `SessionStart` | Session begins/resumes | No |
+| `SessionEnd` | Session ends | No |
+
+## Basic Configuration
+
+Add to `~/.claude/settings.json` or `.claude/settings.local.json`:
+
+```json
+{
+  "hooks": {
+    "PreToolUse": [{
+      "matcher": "Bash",
+      "hooks": [{
+        "type": "command",
+        "command": "$CLAUDE_PROJECT_DIR/hooks/validate.sh",
+        "timeout": 5000
+      }]
+    }]
+  }
+}
+```
+
+## Matcher Patterns
+
+| Pattern | Matches |
+|---------|---------|
+| `"Write"` | Only Write tool |
+| `"*"` or `""` | All tools |
+| `"mcp__*"` | All MCP tools |
+| `"Bash"` | Bash commands |
+
+## Hook Script Requirements
+
+```bash
+#!/bin/bash
+# Receives JSON via stdin: { "tool_name": "...", "tool_input": {...} }
+INPUT=$(cat)
+TOOL=$(echo "$INPUT" | jq -r '.tool_name')
+
+# Exit codes:
+# 0 = Success (continue)
+# 2 = Block with error (stderr shown to Claude)
+# Other = Non-blocking error
+```
+
+## Common Use Cases
+
+| Use Case | Event | Example |
+|----------|-------|---------|
+| Validate inputs | PreToolUse | Block dangerous commands |
+| Audit logging | PostToolUse | Log all tool usage |
+| Custom approval | PermissionRequest | Slack notification |
+| Session init | SessionStart | Load project context |
+
+## Security Checklist
+
+- [ ] Quote all variables: `"$VAR"` not `$VAR`
+- [ ] Validate paths (no `..` traversal)
+- [ ] Use `$CLAUDE_PROJECT_DIR` for paths
+- [ ] Set reasonable timeouts
+- [ ] Handle jq parsing errors
+
+## Troubleshooting
+
+```bash
+# Debug hook loading
+claude --debug
+
+# List registered hooks
+/hooks
+
+# Test script manually
+echo '{"tool_name":"Bash"}' | ./hooks/validate.sh
+```
+
+## Official Documentation
+
+- https://code.claude.com/docs/en/hooks - Hooks reference
+- https://code.claude.com/docs/en/settings - Settings configuration
+
+## Additional Resources
+
+- `./references/hook-events.md` - All events with input/output schemas
+- `./references/configuration.md` - Advanced config patterns
+- `./references/security-patterns.md` - Production security
+
+---
+
+**See Also:** `claude-code-debug` for troubleshooting, `claude-code-headless` for CLI automation

+ 263 - 0
skills/claude-code-hooks/references/configuration.md

@@ -0,0 +1,263 @@
+# Hook Configuration Patterns
+
+Advanced configuration for Claude Code hooks.
+
+## Configuration Locations
+
+| File | Scope | Priority |
+|------|-------|----------|
+| `~/.claude/settings.json` | Global (all projects) | Lower |
+| `.claude/settings.local.json` | Project-specific | Higher |
+
+Project settings are additive to global settings.
+
+## Full Configuration Schema
+
+```json
+{
+  "hooks": {
+    "EventName": [
+      {
+        "matcher": "ToolPattern",
+        "hooks": [
+          {
+            "type": "command",
+            "command": "path/to/script.sh",
+            "timeout": 5000
+          }
+        ]
+      }
+    ]
+  }
+}
+```
+
+## Multiple Hooks Per Event
+
+```json
+{
+  "hooks": {
+    "PreToolUse": [
+      {
+        "matcher": "Write",
+        "hooks": [
+          { "type": "command", "command": "validate-write.sh" }
+        ]
+      },
+      {
+        "matcher": "Bash",
+        "hooks": [
+          { "type": "command", "command": "validate-bash.sh" }
+        ]
+      },
+      {
+        "matcher": "*",
+        "hooks": [
+          { "type": "command", "command": "log-all-tools.sh" }
+        ]
+      }
+    ]
+  }
+}
+```
+
+## Matcher Patterns
+
+### Simple Matchers
+
+```json
+{"matcher": "Write"}      // Exact tool name
+{"matcher": "Bash"}       // Bash commands
+{"matcher": "Read"}       // File reads
+```
+
+### Wildcard Matchers
+
+```json
+{"matcher": "*"}          // All tools
+{"matcher": ""}           // All tools (empty = wildcard)
+{"matcher": "mcp__*"}     // All MCP tools
+```
+
+### MCP Tool Matchers
+
+```json
+{"matcher": "mcp__filesystem__*"}     // All filesystem MCP tools
+{"matcher": "mcp__github__create_*"}  // GitHub create operations
+```
+
+## Chaining Multiple Commands
+
+```json
+{
+  "hooks": {
+    "PreToolUse": [
+      {
+        "matcher": "Write",
+        "hooks": [
+          { "type": "command", "command": "lint-check.sh", "timeout": 3000 },
+          { "type": "command", "command": "security-scan.sh", "timeout": 10000 }
+        ]
+      }
+    ]
+  }
+}
+```
+
+Hooks execute sequentially. If any hook exits with code 2, execution stops.
+
+## Timeout Configuration
+
+```json
+{
+  "type": "command",
+  "command": "slow-check.sh",
+  "timeout": 30000  // 30 seconds (milliseconds)
+}
+```
+
+Default timeout: 5000ms (5 seconds)
+
+## Path Variables
+
+Use `$CLAUDE_PROJECT_DIR` for portable paths:
+
+```json
+{
+  "hooks": {
+    "PreToolUse": [{
+      "matcher": "*",
+      "hooks": [{
+        "type": "command",
+        "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/validate.sh"
+      }]
+    }]
+  }
+}
+```
+
+## Conditional Hooks
+
+Handle conditions in the script, not configuration:
+
+```bash
+#!/bin/bash
+INPUT=$(cat)
+TOOL=$(echo "$INPUT" | jq -r '.tool_name')
+
+# Only process Write and Edit
+case "$TOOL" in
+  Write|Edit)
+    # Validation logic
+    ;;
+  *)
+    exit 0  # Skip other tools
+    ;;
+esac
+```
+
+## Environment-Specific Hooks
+
+### Development vs Production
+
+```bash
+#!/bin/bash
+if [[ "${CLAUDE_ENV:-development}" == "production" ]]; then
+    # Stricter validation
+    strict_validate.sh
+else
+    # Lenient for development
+    exit 0
+fi
+```
+
+### Per-Project Override
+
+Project `.claude/settings.local.json` can add project-specific hooks:
+
+```json
+{
+  "hooks": {
+    "PreToolUse": [{
+      "matcher": "Bash",
+      "hooks": [{
+        "type": "command",
+        "command": "$CLAUDE_PROJECT_DIR/scripts/project-validate.sh"
+      }]
+    }]
+  }
+}
+```
+
+## Common Configuration Patterns
+
+### Audit Logging
+
+```json
+{
+  "hooks": {
+    "PostToolUse": [{
+      "matcher": "*",
+      "hooks": [{
+        "type": "command",
+        "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/audit-log.sh"
+      }]
+    }]
+  }
+}
+```
+
+### Block Dangerous Commands
+
+```json
+{
+  "hooks": {
+    "PreToolUse": [{
+      "matcher": "Bash",
+      "hooks": [{
+        "type": "command",
+        "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/block-dangerous.sh",
+        "timeout": 1000
+      }]
+    }]
+  }
+}
+```
+
+### Session Initialization
+
+```json
+{
+  "hooks": {
+    "SessionStart": [{
+      "hooks": [{
+        "type": "command",
+        "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/init-session.sh"
+      }]
+    }]
+  }
+}
+```
+
+## Debugging Configuration
+
+1. **Check JSON validity:**
+   ```bash
+   jq '.' ~/.claude/settings.json
+   ```
+
+2. **Test hook script:**
+   ```bash
+   echo '{"tool_name":"Bash","tool_input":{}}' | ./hook.sh
+   echo $?  # Check exit code
+   ```
+
+3. **Enable debug mode:**
+   ```bash
+   claude --debug
+   ```
+
+4. **List registered hooks:**
+   ```
+   /hooks
+   ```

+ 251 - 0
skills/claude-code-hooks/references/hook-events.md

@@ -0,0 +1,251 @@
+# Hook Events Reference
+
+Comprehensive documentation for all Claude Code hook events.
+
+## Event Processing Order
+
+```
+PreToolUse Hook → Deny Rules → Allow Rules → Ask Rules → Permission Check → [Tool Execution] → PostToolUse Hook
+```
+
+## PreToolUse
+
+Fires before a tool is executed. Can block or modify the operation.
+
+**Input Schema:**
+```json
+{
+  "session_id": "abc123",
+  "tool_name": "Write",
+  "tool_input": {
+    "file_path": "/path/to/file.txt",
+    "content": "file contents..."
+  }
+}
+```
+
+**Use Cases:**
+- Block dangerous operations
+- Validate file paths
+- Enforce naming conventions
+- Rate limiting
+
+**Example:**
+```bash
+#!/bin/bash
+INPUT=$(cat)
+FILE=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty')
+
+# Block writes to protected directories
+if [[ "$FILE" == /etc/* ]] || [[ "$FILE" == /usr/* ]]; then
+    echo "Cannot write to system directories" >&2
+    exit 2
+fi
+```
+
+## PostToolUse
+
+Fires after a tool completes. Cannot block but can log or notify.
+
+**Input Schema:**
+```json
+{
+  "session_id": "abc123",
+  "tool_name": "Bash",
+  "tool_input": {
+    "command": "npm test"
+  },
+  "tool_output": {
+    "stdout": "...",
+    "stderr": "...",
+    "exit_code": 0
+  }
+}
+```
+
+**Use Cases:**
+- Audit logging
+- Metrics collection
+- Notifications on completion
+- Output transformation
+
+**Example:**
+```bash
+#!/bin/bash
+INPUT=$(cat)
+LOG_FILE="$CLAUDE_PROJECT_DIR/.claude/audit.log"
+TOOL=$(echo "$INPUT" | jq -r '.tool_name')
+TIME=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
+
+echo "$TIME | $TOOL | $(echo "$INPUT" | jq -c '.')" >> "$LOG_FILE"
+```
+
+## PermissionRequest
+
+Fires when Claude Code shows a permission dialog.
+
+**Input Schema:**
+```json
+{
+  "session_id": "abc123",
+  "tool_name": "Bash",
+  "tool_input": {
+    "command": "rm -rf node_modules"
+  },
+  "permission_type": "tool_use"
+}
+```
+
+**Use Cases:**
+- Custom approval workflows
+- Slack/Teams notifications
+- External approval systems
+
+## Notification
+
+Fires when Claude Code sends a notification.
+
+**Input Schema:**
+```json
+{
+  "session_id": "abc123",
+  "notification_type": "task_complete",
+  "message": "Build completed successfully"
+}
+```
+
+**Use Cases:**
+- Forward to external services
+- Custom notification routing
+
+## UserPromptSubmit
+
+Fires when user submits a prompt. No matcher support.
+
+**Input Schema:**
+```json
+{
+  "session_id": "abc123",
+  "prompt": "User's message text"
+}
+```
+
+**Use Cases:**
+- Input logging
+- Prompt transformation
+- Usage analytics
+
+## Stop
+
+Fires when the main agent finishes. No matcher support.
+
+**Input Schema:**
+```json
+{
+  "session_id": "abc123",
+  "reason": "completed",
+  "final_message": "Task completed successfully"
+}
+```
+
+**Use Cases:**
+- Session cleanup
+- Final logging
+- Resource deallocation
+
+## SubagentStop
+
+Fires when a subagent finishes. No matcher support.
+
+**Input Schema:**
+```json
+{
+  "session_id": "abc123",
+  "subagent_id": "xyz789",
+  "subagent_type": "python-expert",
+  "result": "Analysis complete"
+}
+```
+
+**Use Cases:**
+- Subagent performance tracking
+- Result aggregation
+
+## PreCompact
+
+Fires before context window compaction. No matcher support.
+
+**Input Schema:**
+```json
+{
+  "session_id": "abc123",
+  "current_tokens": 150000,
+  "max_tokens": 200000
+}
+```
+
+**Use Cases:**
+- Save context state
+- Pre-compaction processing
+
+## SessionStart
+
+Fires when a session begins or resumes. No matcher support.
+
+**Input Schema:**
+```json
+{
+  "session_id": "abc123",
+  "is_resume": false,
+  "project_dir": "/path/to/project"
+}
+```
+
+**Use Cases:**
+- Project initialization
+- Load session state
+- Environment setup
+
+**Example:**
+```bash
+#!/bin/bash
+# Load project-specific environment
+source "$CLAUDE_PROJECT_DIR/.env.local" 2>/dev/null || true
+echo "Session initialized for $(basename "$CLAUDE_PROJECT_DIR")"
+```
+
+## SessionEnd
+
+Fires when a session ends. No matcher support.
+
+**Input Schema:**
+```json
+{
+  "session_id": "abc123",
+  "duration_ms": 3600000,
+  "total_cost_usd": 0.05
+}
+```
+
+**Use Cases:**
+- Session logging
+- Cost tracking
+- Cleanup tasks
+
+## Exit Code Reference
+
+| Code | Meaning | Effect |
+|------|---------|--------|
+| 0 | Success | Continue execution |
+| 2 | Blocking error | Stop, show stderr to Claude |
+| Other | Non-blocking error | Log warning, continue |
+
+## Environment Variables
+
+Available in all hook scripts:
+
+| Variable | Description |
+|----------|-------------|
+| `CLAUDE_PROJECT_DIR` | Current project directory |
+| `CLAUDE_SESSION_ID` | Current session identifier |
+| `CLAUDE_TOOL_NAME` | Tool being executed (PreToolUse/PostToolUse only) |

+ 264 - 0
skills/claude-code-hooks/references/security-patterns.md

@@ -0,0 +1,264 @@
+# Hook Security Patterns
+
+Security best practices for Claude Code hook scripts.
+
+## Input Validation
+
+### Always Parse JSON Safely
+
+```bash
+#!/bin/bash
+set -euo pipefail
+
+INPUT=$(cat)
+
+# Validate JSON structure
+if ! echo "$INPUT" | jq -e '.' > /dev/null 2>&1; then
+    echo "Invalid JSON input" >&2
+    exit 2
+fi
+
+TOOL=$(echo "$INPUT" | jq -r '.tool_name // empty')
+if [[ -z "$TOOL" ]]; then
+    echo "Missing tool_name" >&2
+    exit 2
+fi
+```
+
+### Quote All Variables
+
+```bash
+# GOOD - Variables are quoted
+file_path="$1"
+command="$CLAUDE_PROJECT_DIR/scripts/validate.sh"
+echo "Processing: $file_path"
+
+# BAD - Unquoted variables allow injection
+file_path=$1
+command=$CLAUDE_PROJECT_DIR/scripts/validate.sh
+```
+
+### Path Traversal Prevention
+
+```bash
+#!/bin/bash
+INPUT=$(cat)
+FILE=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty')
+
+# Check for path traversal
+if [[ "$FILE" == *".."* ]]; then
+    echo "Path traversal attempt blocked: $FILE" >&2
+    exit 2
+fi
+
+# Ensure within project directory
+REAL_PATH=$(realpath -m "$FILE" 2>/dev/null || echo "$FILE")
+if [[ "$REAL_PATH" != "$CLAUDE_PROJECT_DIR"* ]]; then
+    echo "Path outside project directory: $FILE" >&2
+    exit 2
+fi
+```
+
+### Command Injection Prevention
+
+```bash
+#!/bin/bash
+INPUT=$(cat)
+CMD=$(echo "$INPUT" | jq -r '.tool_input.command // empty')
+
+# Block dangerous commands
+DANGEROUS_PATTERNS=(
+    "rm -rf /"
+    "rm -rf /*"
+    "> /dev/sda"
+    "mkfs."
+    "dd if="
+    ":(){:|:&};:"
+)
+
+for pattern in "${DANGEROUS_PATTERNS[@]}"; do
+    if [[ "$CMD" == *"$pattern"* ]]; then
+        echo "Blocked dangerous command: $pattern" >&2
+        exit 2
+    fi
+done
+```
+
+## Secrets Management
+
+### Never Log Secrets
+
+```bash
+#!/bin/bash
+INPUT=$(cat)
+
+# DON'T: Log full input (may contain secrets)
+# echo "$INPUT" >> /tmp/debug.log
+
+# DO: Log sanitized data
+TOOL=$(echo "$INPUT" | jq -r '.tool_name')
+echo "$(date) | $TOOL" >> "$CLAUDE_PROJECT_DIR/.claude/audit.log"
+```
+
+### Environment Variable Handling
+
+```bash
+#!/bin/bash
+# Load secrets from secure source
+if [[ -f "$HOME/.secrets/claude-hooks" ]]; then
+    source "$HOME/.secrets/claude-hooks"
+fi
+
+# Never echo secrets
+# echo "Using API key: $API_KEY"  # BAD
+
+# Use for operations without exposing
+curl -s -H "Authorization: Bearer $API_KEY" "$ENDPOINT" > /dev/null
+```
+
+## Rate Limiting
+
+```bash
+#!/bin/bash
+RATE_FILE="/tmp/claude-hook-rate"
+MAX_CALLS=100
+WINDOW=60  # seconds
+
+NOW=$(date +%s)
+CUTOFF=$((NOW - WINDOW))
+
+# Atomic file operations
+{
+    flock -x 200
+
+    # Clean old entries and count recent
+    if [[ -f "$RATE_FILE" ]]; then
+        RECENT=$(awk -v cutoff="$CUTOFF" '$1 > cutoff' "$RATE_FILE" | wc -l)
+    else
+        RECENT=0
+    fi
+
+    if [[ $RECENT -ge $MAX_CALLS ]]; then
+        echo "Rate limit exceeded: $RECENT calls in ${WINDOW}s" >&2
+        exit 2
+    fi
+
+    # Log this call
+    echo "$NOW" >> "$RATE_FILE"
+
+    # Cleanup old entries
+    awk -v cutoff="$CUTOFF" '$1 > cutoff' "$RATE_FILE" > "${RATE_FILE}.tmp"
+    mv "${RATE_FILE}.tmp" "$RATE_FILE"
+
+} 200>"${RATE_FILE}.lock"
+```
+
+## Timeout Handling
+
+```bash
+#!/bin/bash
+# Set script timeout
+TIMEOUT=10
+
+# Use timeout for external commands
+timeout "$TIMEOUT" some-slow-command || {
+    echo "Command timed out after ${TIMEOUT}s" >&2
+    exit 2
+}
+```
+
+## Error Handling
+
+```bash
+#!/bin/bash
+set -euo pipefail
+
+# Trap errors
+trap 'echo "Hook failed at line $LINENO" >&2; exit 1' ERR
+
+# Validate dependencies
+command -v jq >/dev/null 2>&1 || {
+    echo "jq is required but not installed" >&2
+    exit 1
+}
+
+# Main logic with explicit error handling
+INPUT=$(cat) || {
+    echo "Failed to read input" >&2
+    exit 1
+}
+```
+
+## File Permissions
+
+```bash
+# Hook scripts should be executable only by owner
+chmod 700 hook-script.sh
+
+# Sensitive config should be readable only by owner
+chmod 600 ~/.claude/settings.json
+
+# Audit logs should be append-only where possible
+chattr +a /var/log/claude-audit.log  # Linux only
+```
+
+## Audit Trail Pattern
+
+```bash
+#!/bin/bash
+INPUT=$(cat)
+LOG_DIR="$CLAUDE_PROJECT_DIR/.claude/audit"
+mkdir -p "$LOG_DIR"
+
+TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
+SESSION=$(echo "$INPUT" | jq -r '.session_id // "unknown"')
+TOOL=$(echo "$INPUT" | jq -r '.tool_name // "unknown"')
+LOG_FILE="$LOG_DIR/${SESSION}.jsonl"
+
+# Append-only logging
+{
+    echo "{\"timestamp\":\"$TIMESTAMP\",\"tool\":\"$TOOL\",\"input\":$(echo "$INPUT" | jq -c '.tool_input')}"
+} >> "$LOG_FILE"
+```
+
+## Security Checklist
+
+### Before Deployment
+
+- [ ] All variables quoted
+- [ ] Path traversal checks implemented
+- [ ] Dangerous command patterns blocked
+- [ ] No secrets in logs
+- [ ] Proper file permissions set
+- [ ] Timeout configured
+- [ ] Error handling complete
+- [ ] Input JSON validated
+
+### Script Header Template
+
+```bash
+#!/bin/bash
+#
+# Claude Code Hook: [description]
+# Security considerations:
+#   - Validates all JSON input
+#   - Blocks path traversal
+#   - Quotes all variables
+#   - Logs sanitized data only
+#
+
+set -euo pipefail
+trap 'echo "Error at line $LINENO" >&2; exit 1' ERR
+
+# Dependencies check
+command -v jq >/dev/null 2>&1 || { echo "jq required" >&2; exit 1; }
+
+# Read and validate input
+INPUT=$(cat)
+if ! echo "$INPUT" | jq -e '.' > /dev/null 2>&1; then
+    echo "Invalid JSON" >&2
+    exit 2
+fi
+
+# Main logic here...
+```

+ 118 - 0
skills/claude-code-templates/SKILL.md

@@ -0,0 +1,118 @@
+---
+name: claude-code-templates
+description: "Boilerplate templates for Claude Code extensions. Triggers on: create agent, new skill, command template, hook script, extension scaffold."
+compatibility: "Claude Code CLI"
+allowed-tools: "Read Write"
+depends-on: []
+related-skills: [claude-code-hooks, claude-code-debug]
+---
+
+# Claude Code Templates
+
+Starter templates for building Claude Code extensions.
+
+## Template Selection
+
+| Building | Template | Key Features |
+|----------|----------|--------------|
+| Expert persona | `agent-template.md` | Focus areas, quality checklist, references |
+| Tool capability | `skill-template.md` | Commands, examples, triggers |
+| User workflow | `command-template.md` | Execution flow, options |
+| Automation | `hook-script.sh` | Input parsing, exit codes |
+
+## Quick Start
+
+### Create an Agent
+
+```bash
+# Copy template
+cp ~/.claude/skills/claude-code-templates/assets/agent-template.md \
+   ~/.claude/agents/my-expert.md
+
+# Edit: name, description, focus areas, references
+```
+
+### Create a Skill
+
+```bash
+# Create skill directory
+mkdir -p ~/.claude/skills/my-skill
+
+# Copy template
+cp ~/.claude/skills/claude-code-templates/assets/skill-template.md \
+   ~/.claude/skills/my-skill/SKILL.md
+
+# Edit: name, description, commands, examples
+```
+
+### Create a Command
+
+```bash
+# Copy template
+cp ~/.claude/skills/claude-code-templates/assets/command-template.md \
+   ~/.claude/commands/my-command.md
+
+# Edit: name, description, execution flow
+```
+
+### Create a Hook Script
+
+```bash
+# Copy template
+cp ~/.claude/skills/claude-code-templates/assets/hook-script.sh \
+   .claude/hooks/my-hook.sh
+
+# Make executable
+chmod +x .claude/hooks/my-hook.sh
+```
+
+## Template Locations
+
+Templates are in `./assets/`:
+
+| File | Purpose |
+|------|---------|
+| `agent-template.md` | Expert agent boilerplate |
+| `skill-template.md` | Skill with YAML frontmatter |
+| `command-template.md` | Slash command scaffold |
+| `hook-script.sh` | Secure hook script template |
+
+## Naming Conventions
+
+| Type | Pattern | Example |
+|------|---------|---------|
+| Agent | `{technology}-expert.md` | `react-expert.md` |
+| Skill | `{tool-or-pattern}/SKILL.md` | `git-workflow/SKILL.md` |
+| Command | `{action}.md` | `review.md` |
+| Hook | `{event}-{action}.sh` | `pre-write-validate.sh` |
+
+## Validation
+
+```bash
+# Validate YAML frontmatter
+head -20 my-extension.md
+
+# Check name matches filename
+grep "^name:" my-extension.md
+
+# Run project tests
+just test
+```
+
+## Official Documentation
+
+- https://code.claude.com/docs/en/skills - Skills reference
+- https://code.claude.com/docs/en/sub-agents - Custom subagents
+- https://code.claude.com/docs/en/hooks - Hooks reference
+- https://agentskills.io/specification - Agent Skills open standard
+
+## Assets
+
+- `./assets/agent-template.md` - Expert agent scaffold
+- `./assets/skill-template.md` - Skill with references pattern
+- `./assets/command-template.md` - Slash command scaffold
+- `./assets/hook-script.sh` - Secure bash hook template
+
+---
+
+**See Also:** `claude-code-debug` for troubleshooting extensions

+ 69 - 0
skills/claude-code-templates/assets/agent-template.md

@@ -0,0 +1,69 @@
+---
+name: technology-expert
+description: "Expert in [technology]. Use for: [scenario 1], [scenario 2], [scenario 3]."
+model: inherit
+---
+
+# [Technology] Expert Agent
+
+You are an expert in [technology], specializing in [specific areas].
+
+## Focus Areas
+
+- [Area 1: e.g., Component architecture]
+- [Area 2: e.g., State management]
+- [Area 3: e.g., Performance optimization]
+- [Area 4: e.g., Testing strategies]
+
+## Approach Principles
+
+- [Principle 1: e.g., Always validate input before processing]
+- [Principle 2: e.g., Prefer composition over inheritance]
+- [Principle 3: e.g., Write tests alongside implementation]
+- [Principle 4: e.g., Document public APIs with examples]
+
+## Quality Checklist
+
+- [ ] [Requirement 1: e.g., Type hints on all functions]
+- [ ] [Requirement 2: e.g., No console.log in production code]
+- [ ] [Requirement 3: e.g., Error handling with specific exceptions]
+- [ ] [Requirement 4: e.g., Tests cover edge cases]
+
+## Output Deliverables
+
+When completing tasks, provide:
+
+1. [Deliverable 1: e.g., Working, tested code]
+2. [Deliverable 2: e.g., Clear documentation]
+3. [Deliverable 3: e.g., Example usage]
+
+## Common Pitfalls
+
+- [Pitfall 1: e.g., Using any instead of proper types]
+- [Pitfall 2: e.g., Mutating state directly]
+- [Pitfall 3: e.g., Ignoring error boundaries]
+
+## References
+
+- [URL 1: Official documentation]
+- [URL 2: Best practices guide]
+- [URL 3: API reference]
+- [URL 4: Community resources]
+- [URL 5: Tutorial/cookbook]
+
+<!--
+USAGE INSTRUCTIONS:
+
+1. Copy this file to ~/.claude/agents/your-agent.md
+2. Replace all [placeholders] with your content
+3. Rename the file to match the `name` field (kebab-case)
+4. Ensure description includes "Use for:" with clear scenarios
+5. Add 10+ authoritative reference URLs
+6. Test by asking Claude to use your agent
+
+TIPS:
+- Focus areas should be specific, not generic
+- Principles should be actionable, not vague
+- Checklist items should be verifiable
+- References should be official/authoritative sources
+-->

+ 93 - 0
skills/claude-code-templates/assets/command-template.md

@@ -0,0 +1,93 @@
+---
+name: command-name
+description: "What this command does in one sentence."
+---
+
+# /command-name
+
+Brief description of the command's purpose.
+
+## Usage
+
+```
+/command-name [options] [arguments]
+```
+
+## Execution Flow
+
+```
+/command-name
+    │
+    ├── Step 1: [Action]
+    │   └── [Details]
+    │
+    ├── Step 2: [Action]
+    │   └── [Details]
+    │
+    └── Step 3: [Action]
+        └── [Details]
+```
+
+## Instructions
+
+### Step 1: [Action Name]
+
+[Detailed instructions for this step]
+
+- Sub-step A
+- Sub-step B
+
+### Step 2: [Action Name]
+
+[Detailed instructions for this step]
+
+### Step 3: [Action Name]
+
+[Detailed instructions for this step]
+
+## Options
+
+| Flag | Description | Default |
+|------|-------------|---------|
+| `--flag1` | Description | value |
+| `--flag2` | Description | value |
+
+## Examples
+
+### Basic Usage
+
+```
+/command-name
+```
+
+### With Options
+
+```
+/command-name --flag1 value
+```
+
+### Full Example
+
+```
+/command-name --flag1 value --flag2 value argument
+```
+
+## Output
+
+[Description of what the command produces]
+
+<!--
+USAGE INSTRUCTIONS:
+
+1. Copy to ~/.claude/commands/your-command.md or .claude/commands/
+2. Replace all [placeholders] with your content
+3. Ensure filename matches the `name` field
+4. Keep execution flow clear and scannable
+5. Test by typing /your-command in Claude
+
+TIPS:
+- Execution flow should be visual and easy to follow
+- Each step should be actionable
+- Include real examples users can copy
+- Document all options with defaults
+-->

+ 85 - 0
skills/claude-code-templates/assets/hook-script.sh

@@ -0,0 +1,85 @@
+#!/bin/bash
+#
+# Claude Code Hook: [Description]
+#
+# Event: [PreToolUse|PostToolUse|SessionStart|etc]
+# Matcher: [Tool name or * for all]
+#
+# Security: Validates input, quotes variables, prevents path traversal
+#
+
+set -euo pipefail
+
+# Error handling
+trap 'echo "Error at line $LINENO" >&2; exit 1' ERR
+
+# Check dependencies
+command -v jq >/dev/null 2>&1 || {
+    echo "jq is required but not installed" >&2
+    exit 1
+}
+
+# Read input from stdin
+INPUT=$(cat)
+
+# Validate JSON
+if ! echo "$INPUT" | jq -e '.' > /dev/null 2>&1; then
+    echo "Invalid JSON input" >&2
+    exit 2
+fi
+
+# Parse common fields
+TOOL=$(echo "$INPUT" | jq -r '.tool_name // empty')
+SESSION=$(echo "$INPUT" | jq -r '.session_id // empty')
+
+# -------------------------------------------------------------------
+# Your hook logic here
+# -------------------------------------------------------------------
+
+# Example: Log tool usage
+LOG_FILE="${CLAUDE_PROJECT_DIR:-.}/.claude/hook.log"
+mkdir -p "$(dirname "$LOG_FILE")"
+echo "$(date -u +"%Y-%m-%dT%H:%M:%SZ") | $TOOL | $SESSION" >> "$LOG_FILE"
+
+# Example: Block dangerous operations
+# if [[ "$TOOL" == "Bash" ]]; then
+#     CMD=$(echo "$INPUT" | jq -r '.tool_input.command // empty')
+#     if [[ "$CMD" == *"rm -rf /"* ]]; then
+#         echo "Blocked dangerous command" >&2
+#         exit 2  # Exit 2 = blocking error
+#     fi
+# fi
+
+# Example: Validate file paths
+# if [[ "$TOOL" == "Write" ]]; then
+#     FILE=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty')
+#     if [[ "$FILE" == *".."* ]]; then
+#         echo "Path traversal blocked" >&2
+#         exit 2
+#     fi
+# fi
+
+# -------------------------------------------------------------------
+# Exit codes:
+#   0 = Success (continue execution)
+#   2 = Blocking error (stderr shown to Claude)
+#   Other = Non-blocking error (logged, continues)
+# -------------------------------------------------------------------
+
+exit 0
+
+# CONFIGURATION EXAMPLE:
+# Add to ~/.claude/settings.json or .claude/settings.local.json:
+#
+# {
+#   "hooks": {
+#     "PreToolUse": [{
+#       "matcher": "*",
+#       "hooks": [{
+#         "type": "command",
+#         "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/this-script.sh",
+#         "timeout": 5000
+#       }]
+#     }]
+#   }
+# }

+ 138 - 0
skills/claude-code-templates/assets/skill-template.md

@@ -0,0 +1,138 @@
+---
+name: skill-name
+description: "Brief description of what this skill does. Triggers on: keyword1, keyword2, keyword3."
+compatibility: "Requirements (e.g., Python 3.10+, Node.js, specific CLI tools)"
+allowed-tools: "Bash Read Write"
+depends-on: []
+related-skills: []
+---
+
+# Skill Name
+
+One-line description of what this skill enables.
+
+## Quick Reference
+
+| Task | Command |
+|------|---------|
+| [Task 1] | `command1 args` |
+| [Task 2] | `command2 args` |
+| [Task 3] | `command3 args` |
+
+## Basic Usage
+
+```bash
+# Example 1: [Description]
+command example
+
+# Example 2: [Description]
+command example
+```
+
+## Common Patterns
+
+### Pattern 1: [Name]
+
+```bash
+# Description of when to use this
+command with options
+```
+
+### Pattern 2: [Name]
+
+```bash
+# Description of when to use this
+command with options
+```
+
+## When to Use
+
+- [Scenario 1: e.g., Processing large JSON files]
+- [Scenario 2: e.g., Batch transformations]
+- [Scenario 3: e.g., Data extraction]
+
+## Troubleshooting
+
+| Issue | Solution |
+|-------|----------|
+| [Problem 1] | [Solution 1] |
+| [Problem 2] | [Solution 2] |
+
+## Additional Resources
+
+- `./references/advanced-patterns.md` - Detailed patterns
+- `./references/configuration.md` - Configuration options
+
+---
+
+**See Also:** [related-skill-1], [related-skill-2]
+
+<!--
+AGENTSKILLS.IO SPECIFICATION
+=============================
+This template follows the open standard at https://agentskills.io/specification
+
+REQUIRED FIELDS:
+- name: 1-64 chars, lowercase alphanumeric + hyphens, must match directory name
+- description: 1-1024 chars, include trigger keywords for discovery
+
+OPTIONAL FIELDS (per spec):
+- license: License applied to the skill
+- compatibility: Max 500 chars, environment requirements
+- metadata: Key-value mapping for additional properties
+- allowed-tools: Space-delimited pre-approved tools (experimental)
+
+EXTENSIONS (via metadata convention):
+- depends-on: Prerequisite skills that should be loaded first
+- related-skills: Complementary skills for cross-reference
+
+DIRECTORY STRUCTURE:
+skills/your-skill/
+├── SKILL.md           # Required, <500 lines per spec
+├── references/        # On-demand detailed docs
+│   └── advanced.md
+├── scripts/           # Executable helpers
+│   └── helper.sh
+└── assets/            # Static resources
+    └── template.txt
+
+GUIDELINES:
+- SKILL.md under 500 lines (guideline, can exceed if needed)
+- Instructions under 5000 tokens for efficient loading
+- Use relative paths one level deep from SKILL.md
+- Name must match parent directory exactly
+
+USAGE:
+1. Create directory: mkdir -p ~/.claude/skills/your-skill
+2. Copy this file to ~/.claude/skills/your-skill/SKILL.md
+3. Replace all [placeholders] with your content
+4. Ensure directory name matches the `name` field
+5. Test by mentioning trigger keywords in a conversation
+
+TIPS:
+- Description MUST include trigger keywords for agent discovery
+- Keep SKILL.md lean - use references/ for detailed patterns
+- Use tables for quick scanning
+- Include troubleshooting for common issues
+
+PROMPT CACHING OPTIMIZATION:
+Claude Code benefits from prompt caching (90% token cost reduction on cache hits).
+See: https://platform.claude.com/docs/en/build-with-claude/prompt-caching
+
+For cache efficiency:
+- Put stable, reusable content at the TOP of files
+- Large reference files (>1024 tokens) benefit most from caching
+- Structure references/ files with static content first, examples last
+- Avoid mixing frequently-changing content with static patterns
+- SKILL.md is loaded first, references/ loaded on-demand (cache-friendly)
+
+Cache thresholds (minimum tokens to cache):
+- Claude Sonnet/Opus: 1024 tokens
+- Claude Haiku 3: 2048 tokens
+- Claude Haiku 4.5/Opus 4.5: 4096 tokens
+
+When NOT to optimize for caching:
+- Small skills under 1024 tokens (won't cache anyway)
+- Highly dynamic content that changes per-request
+- One-time reference lookups
+-->

+ 28 - 189
skills/code-stats/SKILL.md

@@ -7,86 +7,25 @@ allowed-tools: "Bash"
 
 # Code Statistics
 
-## Purpose
-Quickly analyze codebase size, composition, and changes with token-efficient output.
+Quickly analyze codebase size, composition, and changes.
 
-## Tools
-
-| Tool | Command | Use For |
-|------|---------|---------|
-| tokei | `tokei` | Line counts by language |
-| difft | `difft file1 file2` | Semantic AST-aware diffs |
-
-## tokei - Code Statistics
-
-### Basic Usage
+## tokei - Line Counts
 
 ```bash
-# Count all code in current directory
+# Count all code
 tokei
 
-# Count specific directory
-tokei src/
-
-# Count multiple directories
-tokei src/ lib/ tests/
-
-# Count specific file
-tokei src/main.rs
-```
-
-### Output Options
-
-```bash
-# Compact single-line per language
-tokei --compact
-
-# Sort by lines of code
-tokei --sort code
-
-# Sort by number of files
-tokei --sort files
-
-# Sort by comments
-tokei --sort comments
+# Compact output sorted by code
+tokei --compact --sort code
 
-# Only show specific languages
+# Specific languages
 tokei --type=TypeScript,JavaScript
 
-# List all recognized languages
-tokei --languages
-```
-
-### Filtering
-
-```bash
 # Exclude directories
-tokei --exclude node_modules --exclude vendor --exclude dist
+tokei --exclude node_modules --exclude dist
 
-# Exclude by pattern
-tokei --exclude "*.test.*" --exclude "*.spec.*"
-
-# Include hidden files
-tokei --hidden
-
-# Only count certain languages
-tokei -t Python,Rust
-```
-
-### Output Formats
-
-```bash
-# JSON output (for processing)
-tokei --output json
-
-# YAML output
-tokei --output yaml
-
-# CBOR output
-tokei --output cbor
-
-# Pipe JSON to jq
-tokei --output json | jq '.TypeScript.code'
+# JSON output for scripting
+tokei --output json | jq '.Total.code'
 ```
 
 ### Sample Output
@@ -97,135 +36,32 @@ tokei --output json | jq '.TypeScript.code'
 ===============================================================================
  TypeScript             45        12847         9823         1456         1568
  JavaScript             12         2341         1876          234          231
- JSON                    8          456          456            0            0
- Markdown               15         1234            0         1234            0
 -------------------------------------------------------------------------------
- Total                  80        16878        12155         2924         1799
+ Total                  57        15188        11699         1690         1799
 ===============================================================================
 ```
 
-### Understanding Output
-
-| Column | Meaning |
-|--------|---------|
-| Files | Number of files of this language |
-| Lines | Total lines (code + comments + blanks) |
-| Code | Non-blank, non-comment lines |
-| Comments | Comment lines |
-| Blanks | Empty lines |
-
 ## difft - Semantic Diffs
 
-### Basic Usage
-
-```bash
-# Compare two files
-difft old.py new.py
-
-# Compare directories
-difft dir1/ dir2/
-
-# Compare with options
-difft --color=always old.ts new.ts
-```
-
-### Display Modes
-
 ```bash
-# Side-by-side (default)
-difft old.js new.js
+# Compare files
+difft old.ts new.ts
 
-# Inline (unified style)
-difft --display=inline old.js new.js
+# Inline mode
+difft --display=inline old.ts new.ts
 
-# Show only changes
-difft --skip-unchanged old.js new.js
+# With git
+GIT_EXTERNAL_DIFF=difft git diff
+GIT_EXTERNAL_DIFF=difft git show HEAD~1
 ```
 
-### Git Integration
-
-```bash
-# Use as git difftool
-git difftool --tool=difftastic HEAD~1
-
-# Configure as default difftool
-git config --global diff.tool difftastic
-git config --global difftool.difftastic.cmd 'difft "$LOCAL" "$REMOTE"'
-
-# Use for specific diff
-GIT_EXTERNAL_DIFF=difft git diff HEAD~1
-```
-
-### Language Support
-
-```bash
-# Force language detection
-difft --language=python old.py new.py
-
-# List supported languages
-difft --list-languages
-```
-
-### Why Semantic Diffs?
+### Why Semantic?
 
 | Traditional diff | difft |
 |-----------------|-------|
-| Line-by-line comparison | AST-aware comparison |
-| Shows moved lines as delete+add | Shows as moved |
-| Whitespace sensitive | Ignores formatting changes |
-| Can be noisy | Focuses on semantic changes |
-
-## Comparison: tokei vs other tools
-
-| Feature | tokei | cloc | wc -l |
-|---------|-------|------|-------|
-| Speed | Fastest | Slow | Fast |
-| Language detection | Yes | Yes | No |
-| Comment counting | Yes | Yes | No |
-| .gitignore respect | Yes | Yes | No |
-| JSON output | Yes | Yes | No |
-
-## Common Workflows
-
-### Project Assessment
-
-```bash
-# Quick overview
-tokei --compact --sort code
-
-# Detailed breakdown to file
-tokei > code-stats.txt
-
-# Compare before/after refactor
-tokei --output json > before.json
-# ... make changes ...
-tokei --output json > after.json
-diff before.json after.json
-```
-
-### Code Review
-
-```bash
-# Semantic diff for review
-difft main.ts feature.ts
-
-# Compare branches
-git diff main feature -- "*.ts" | difft
-
-# Review specific commit
-GIT_EXTERNAL_DIFF=difft git show abc123
-```
-
-### CI Integration
-
-```bash
-# Check codebase size limits
-LINES=$(tokei --output json | jq '.Total.code')
-if [ "$LINES" -gt 100000 ]; then
-  echo "Codebase exceeds 100k lines"
-  exit 1
-fi
-```
+| Line-by-line | AST-aware |
+| Shows moved as delete+add | Recognizes moves |
+| Whitespace sensitive | Ignores formatting |
 
 ## Quick Reference
 
@@ -238,7 +74,6 @@ fi
 | JSON output | `tokei --output json` |
 | Exclude dir | `tokei --exclude node_modules` |
 | Semantic diff | `difft file1 file2` |
-| Inline diff | `difft --display=inline a b` |
 | Git diff | `GIT_EXTERNAL_DIFF=difft git diff` |
 
 ## When to Use
@@ -247,6 +82,10 @@ fi
 - Comparing code changes semantically
 - Understanding project composition
 - Reviewing refactoring impact
-- Estimating project size
-- Tracking codebase growth over time
-- Code review with meaningful diffs
+- Tracking codebase growth
+
+## Additional Resources
+
+For detailed patterns, load:
+- `./references/tokei-advanced.md` - Filtering, output formats, CI integration
+- `./references/difft-advanced.md` - Display modes, git integration, language support

+ 283 - 0
skills/code-stats/references/difft-advanced.md

@@ -0,0 +1,283 @@
+# difft (difftastic) Advanced Usage
+
+Semantic, AST-aware diff tool for meaningful code comparisons.
+
+## Display Modes
+
+### Side-by-Side (Default)
+
+```bash
+difft old.ts new.ts
+# Shows files side by side with syntax highlighting
+```
+
+### Inline (Unified Style)
+
+```bash
+difft --display=inline old.ts new.ts
+# Traditional unified diff format
+```
+
+### Side-by-Side in Terminal
+
+```bash
+difft --display=side-by-side old.ts new.ts
+# Explicit side-by-side
+```
+
+## Filtering Options
+
+### Skip Unchanged
+
+```bash
+difft --skip-unchanged old.ts new.ts
+# Only show files that changed
+```
+
+### Context Lines
+
+```bash
+difft --context 5 old.ts new.ts
+# Show 5 lines of context around changes
+```
+
+### Language Override
+
+```bash
+difft --language=python file1 file2
+# Force specific language parser
+
+# List supported languages
+difft --list-languages
+```
+
+## Color and Formatting
+
+```bash
+# Force color output (for piping)
+difft --color=always old.ts new.ts | less -R
+
+# Disable color
+difft --color=never old.ts new.ts
+
+# Set terminal width
+difft --width 120 old.ts new.ts
+
+# Tab width
+difft --tab-width 4 old.ts new.ts
+```
+
+## Git Integration
+
+### As External Diff
+
+```bash
+# One-time use
+GIT_EXTERNAL_DIFF=difft git diff
+GIT_EXTERNAL_DIFF=difft git show HEAD~1
+GIT_EXTERNAL_DIFF=difft git log -p
+
+# With options
+GIT_EXTERNAL_DIFF="difft --display=inline" git diff
+```
+
+### Configure as Default
+
+```bash
+# Add to ~/.gitconfig
+git config --global diff.external difft
+
+# Or add to .gitconfig directly:
+# [diff]
+#     external = difft
+
+# Disable for specific command
+git --no-ext-diff diff
+```
+
+### As Difftool
+
+```bash
+# Configure
+git config --global diff.tool difftastic
+git config --global difftool.difftastic.cmd 'difft "$LOCAL" "$REMOTE"'
+git config --global difftool.prompt false
+
+# Use
+git difftool HEAD~1
+git difftool main feature-branch
+```
+
+### Per-Repository
+
+```bash
+# In repo's .git/config
+git config diff.external difft
+
+# Or in .gitattributes for specific files
+*.rs diff=difftastic
+```
+
+## Directory Comparison
+
+```bash
+# Compare directories
+difft dir1/ dir2/
+
+# Compare with options
+difft --skip-unchanged dir1/ dir2/
+```
+
+## Why Semantic Diffs?
+
+### Traditional diff vs difft
+
+| Scenario | Traditional | difft |
+|----------|-------------|-------|
+| Reformatted code | Shows all lines as changed | Shows only semantic changes |
+| Moved function | Delete + Add | Recognizes as move |
+| Renamed variable | Many line changes | Highlights just the rename |
+| Added whitespace | Shows as change | Ignores (no semantic change) |
+| Reordered imports | All imports changed | Shows specific additions/removals |
+
+### Example: Reformatting
+
+Traditional diff:
+```diff
+-function foo() { return 42; }
++function foo() {
++  return 42;
++}
+```
+
+difft:
+```
+(no changes - semantically identical)
+```
+
+### Example: Moved Code
+
+Traditional diff:
+```diff
+-function helper() { ... }
+ function main() { ... }
++function helper() { ... }
+```
+
+difft:
+```
+function helper() { ... }  →  (moved to line 10)
+```
+
+## Supported Languages
+
+difft parses actual ASTs for many languages:
+
+- **Web**: JavaScript, TypeScript, JSX, TSX, CSS, HTML, JSON
+- **Systems**: C, C++, Rust, Go, Zig
+- **Scripting**: Python, Ruby, Perl, Lua, Bash
+- **JVM**: Java, Kotlin, Scala, Clojure
+- **Functional**: Haskell, OCaml, Elixir, Erlang
+- **Others**: SQL, YAML, TOML, Nix, Terraform
+
+```bash
+# List all
+difft --list-languages
+```
+
+## Performance Tips
+
+```bash
+# For large files, limit context
+difft --context 3 large1.ts large2.ts
+
+# Skip binary files
+difft --skip-unchanged dir1/ dir2/
+
+# Force text mode for unknown formats
+difft --language=text file1 file2
+```
+
+## Piping and Scripting
+
+```bash
+# Pipe to pager
+difft old.ts new.ts | less -R
+
+# Save to file
+difft --color=never old.ts new.ts > changes.txt
+
+# Check if files differ (exit code)
+difft old.ts new.ts > /dev/null
+echo $?  # 0 = same, 1 = different
+```
+
+## Common Workflows
+
+### Code Review
+
+```bash
+# Review specific commit
+GIT_EXTERNAL_DIFF=difft git show abc123
+
+# Review PR changes
+GIT_EXTERNAL_DIFF=difft git diff main...feature-branch
+
+# Review staged changes
+GIT_EXTERNAL_DIFF=difft git diff --cached
+```
+
+### Before/After Refactoring
+
+```bash
+# Save original
+cp module.ts module.ts.bak
+
+# Refactor...
+
+# Compare
+difft module.ts.bak module.ts
+```
+
+### Comparing Branches
+
+```bash
+# Full diff between branches
+GIT_EXTERNAL_DIFF=difft git diff main feature-branch
+
+# Specific file across branches
+difft <(git show main:src/index.ts) <(git show feature:src/index.ts)
+```
+
+### Comparing Commits
+
+```bash
+# Specific file between commits
+difft <(git show HEAD~2:src/index.ts) <(git show HEAD:src/index.ts)
+```
+
+## Configuration
+
+Create `~/.config/difft/config.toml`:
+
+```toml
+# Display mode
+display = "side-by-side"
+
+# Context lines
+context = 3
+
+# Tab width
+tab-width = 4
+
+# Color theme (try different values)
+color = "always"
+```
+
+## Tips
+
+1. **Use with git always** - `GIT_EXTERNAL_DIFF=difft` or configure globally
+2. **Skip unchanged in directories** - `--skip-unchanged` for cleaner output
+3. **Inline for copy/paste** - `--display=inline` when sharing diffs
+4. **Force language** - `--language=X` when auto-detection fails
+5. **Combine with delta** - Use difft for semantic diffs, delta for line-level

+ 254 - 0
skills/code-stats/references/tokei-advanced.md

@@ -0,0 +1,254 @@
+# tokei Advanced Usage
+
+Complete reference for tokei code statistics tool.
+
+## Filtering Options
+
+### By Language
+
+```bash
+# Only specific languages
+tokei --type=TypeScript,JavaScript,Python
+tokei -t TypeScript,Rust
+
+# Exclude languages
+tokei --exclude-lang=Markdown,JSON
+
+# List all recognized languages
+tokei --languages
+```
+
+### By Path
+
+```bash
+# Specific directories
+tokei src/ lib/ tests/
+
+# Exclude directories
+tokei --exclude node_modules --exclude dist --exclude vendor
+tokei -e "*.test.*" -e "*.spec.*"
+
+# Include hidden files
+tokei --hidden
+
+# Include gitignored files
+tokei --no-ignore
+```
+
+### By Depth
+
+```bash
+# Limit directory depth
+tokei --max-depth 2
+
+# Only files in current directory
+tokei --max-depth 1
+```
+
+## Output Formats
+
+### Default Table
+
+```bash
+tokei
+# ===============================================================================
+#  Language            Files        Lines         Code     Comments       Blanks
+# ===============================================================================
+#  TypeScript             45        12847         9823         1456         1568
+#  JavaScript             12         2341         1876          234          231
+# ===============================================================================
+```
+
+### Compact
+
+```bash
+tokei --compact
+# -------------------------------------------------------------------------------
+#  TypeScript   45   12847    9823    1456    1568
+#  JavaScript   12    2341    1876     234     231
+# -------------------------------------------------------------------------------
+```
+
+### JSON
+
+```bash
+tokei --output json
+# {"TypeScript":{"blanks":1568,"code":9823,"comments":1456,"lines":12847},...}
+
+# Pretty print with jq
+tokei --output json | jq .
+
+# Extract specific language
+tokei --output json | jq '.TypeScript.code'
+
+# Get total lines
+tokei --output json | jq '.Total.code'
+```
+
+### YAML
+
+```bash
+tokei --output yaml
+# TypeScript:
+#   blanks: 1568
+#   code: 9823
+#   comments: 1456
+#   lines: 12847
+```
+
+## Sorting
+
+```bash
+# Sort by lines of code (default)
+tokei --sort code
+
+# Sort by number of files
+tokei --sort files
+
+# Sort by comments
+tokei --sort comments
+
+# Sort by blank lines
+tokei --sort blanks
+
+# Sort by total lines
+tokei --sort lines
+```
+
+## Per-File Statistics
+
+```bash
+# Show statistics per file
+tokei --files
+
+# JSON with file details
+tokei --output json --files | jq '.TypeScript.reports[].name'
+```
+
+## Common Workflows
+
+### Compare Before/After
+
+```bash
+# Before refactoring
+tokei --output json > before.json
+
+# Make changes...
+
+# After refactoring
+tokei --output json > after.json
+
+# Compare
+diff before.json after.json
+
+# Or with jq
+echo "Before: $(jq '.Total.code' before.json), After: $(jq '.Total.code' after.json)"
+```
+
+### CI Size Limits
+
+```bash
+#!/bin/bash
+# Check codebase size limits in CI
+
+MAX_LINES=100000
+LINES=$(tokei --output json | jq '.Total.code')
+
+if [ "$LINES" -gt "$MAX_LINES" ]; then
+    echo "ERROR: Codebase exceeds $MAX_LINES lines (current: $LINES)"
+    exit 1
+fi
+
+echo "Codebase size OK: $LINES lines"
+```
+
+### Language Breakdown Report
+
+```bash
+#!/bin/bash
+# Generate language breakdown report
+
+echo "# Code Statistics Report"
+echo "Generated: $(date)"
+echo
+tokei --compact --sort code
+echo
+echo "## Details"
+tokei --output json | jq -r '
+  to_entries |
+  sort_by(-.value.code) |
+  .[] |
+  select(.key != "Total") |
+  "- \(.key): \(.value.code) lines (\(.value.files) files)"
+'
+```
+
+### Track Growth Over Time
+
+```bash
+#!/bin/bash
+# Append to stats history
+
+DATE=$(date +%Y-%m-%d)
+STATS=$(tokei --output json | jq -c '{date: "'"$DATE"'", stats: .Total}')
+echo "$STATS" >> code_stats_history.jsonl
+
+# View history
+cat code_stats_history.jsonl | jq -s '.'
+```
+
+## Configuration File
+
+Create `.tokeirc` or `tokei.toml` in project root:
+
+```toml
+# tokei.toml
+columns = 80
+files = false
+hidden = false
+no_ignore = false
+sort = "code"
+types = ["TypeScript", "JavaScript", "Python"]
+
+[languages.TypeScript]
+line_comment = ["//"]
+multi_line = ["/*", "*/"]
+quotes = [["\"", "\""], ["'", "'"]]
+```
+
+## Understanding Output
+
+| Column | Meaning |
+|--------|---------|
+| Files | Number of files of this language |
+| Lines | Total lines (code + comments + blanks) |
+| Code | Non-blank, non-comment lines |
+| Comments | Lines that are comments |
+| Blanks | Empty/whitespace-only lines |
+
+### What Counts as Code?
+
+- Executable statements
+- Declarations
+- Import/export statements
+- NOT: comments, blank lines, documentation strings (in some languages)
+
+## Comparison with Other Tools
+
+| Feature | tokei | cloc | sloccount | wc -l |
+|---------|-------|------|-----------|-------|
+| Speed | Fastest | Slow | Medium | Fastest |
+| Language detection | Yes | Yes | Yes | No |
+| Comment detection | Yes | Yes | Yes | No |
+| .gitignore respect | Yes | Yes | No | No |
+| JSON output | Yes | Yes | No | No |
+| Multi-threaded | Yes | No | No | No |
+| Memory usage | Low | High | Medium | Lowest |
+
+## Tips
+
+1. **Use `--compact` for quick overview** - easier to scan
+2. **Pipe JSON to jq for scripting** - machine-readable output
+3. **Exclude generated code** - `--exclude dist --exclude generated`
+4. **Compare branches** - checkout each, run tokei, diff results
+5. **Regular tracking** - run in CI to catch unexpected growth

+ 230 - 0
skills/container-orchestration/SKILL.md

@@ -0,0 +1,230 @@
+---
+name: container-orchestration
+description: "Docker and Kubernetes patterns. Triggers on: Dockerfile, docker-compose, kubernetes, k8s, helm, pod, deployment, service, ingress, container, image."
+compatibility: "Docker 20+, Kubernetes 1.25+, Helm 3+"
+allowed-tools: "Read Write Bash"
+---
+
+# Container Orchestration
+
+Docker and Kubernetes patterns for containerized applications.
+
+## Dockerfile Best Practices
+
+```dockerfile
+# Use specific version, not :latest
+FROM python:3.11-slim AS builder
+
+# Set working directory
+WORKDIR /app
+
+# Copy dependency files first (better caching)
+COPY requirements.txt .
+RUN pip install --no-cache-dir -r requirements.txt
+
+# Copy application code
+COPY src/ ./src/
+
+# Production stage (multi-stage build)
+FROM python:3.11-slim
+
+WORKDIR /app
+
+# Create non-root user
+RUN useradd --create-home appuser
+USER appuser
+
+# Copy from builder
+COPY --from=builder /app /app
+
+# Set environment
+ENV PYTHONUNBUFFERED=1
+
+# Health check
+HEALTHCHECK --interval=30s --timeout=3s \
+  CMD curl -f http://localhost:8000/health || exit 1
+
+EXPOSE 8000
+CMD ["python", "-m", "uvicorn", "src.main:app", "--host", "0.0.0.0"]
+```
+
+### Dockerfile Rules
+```
+DO:
+- Use specific base image versions
+- Use multi-stage builds
+- Run as non-root user
+- Order commands by change frequency
+- Use .dockerignore
+- Add health checks
+
+DON'T:
+- Use :latest tag
+- Run as root
+- Copy unnecessary files
+- Store secrets in image
+- Install dev dependencies in production
+```
+
+## Docker Compose
+
+```yaml
+# docker-compose.yml
+version: "3.9"
+
+services:
+  app:
+    build:
+      context: .
+      dockerfile: Dockerfile
+    ports:
+      - "8000:8000"
+    environment:
+      - DATABASE_URL=postgres://user:pass@db:5432/app
+    depends_on:
+      db:
+        condition: service_healthy
+    healthcheck:
+      test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
+      interval: 30s
+      timeout: 10s
+      retries: 3
+
+  db:
+    image: postgres:15-alpine
+    volumes:
+      - postgres_data:/var/lib/postgresql/data
+    environment:
+      POSTGRES_USER: user
+      POSTGRES_PASSWORD: pass
+      POSTGRES_DB: app
+    healthcheck:
+      test: ["CMD-SHELL", "pg_isready -U user -d app"]
+      interval: 10s
+      timeout: 5s
+      retries: 5
+
+volumes:
+  postgres_data:
+```
+
+## Kubernetes Basics
+
+### Deployment
+
+```yaml
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: app
+  labels:
+    app: myapp
+spec:
+  replicas: 3
+  selector:
+    matchLabels:
+      app: myapp
+  template:
+    metadata:
+      labels:
+        app: myapp
+    spec:
+      containers:
+      - name: app
+        image: myapp:1.0.0
+        ports:
+        - containerPort: 8000
+        resources:
+          requests:
+            memory: "128Mi"
+            cpu: "100m"
+          limits:
+            memory: "256Mi"
+            cpu: "500m"
+        livenessProbe:
+          httpGet:
+            path: /health
+            port: 8000
+          initialDelaySeconds: 10
+          periodSeconds: 30
+        readinessProbe:
+          httpGet:
+            path: /ready
+            port: 8000
+          initialDelaySeconds: 5
+          periodSeconds: 10
+        env:
+        - name: DATABASE_URL
+          valueFrom:
+            secretKeyRef:
+              name: app-secrets
+              key: database-url
+```
+
+### Service
+
+```yaml
+apiVersion: v1
+kind: Service
+metadata:
+  name: app-service
+spec:
+  selector:
+    app: myapp
+  ports:
+  - port: 80
+    targetPort: 8000
+  type: ClusterIP
+```
+
+### Ingress
+
+```yaml
+apiVersion: networking.k8s.io/v1
+kind: Ingress
+metadata:
+  name: app-ingress
+  annotations:
+    nginx.ingress.kubernetes.io/rewrite-target: /
+spec:
+  ingressClassName: nginx
+  rules:
+  - host: app.example.com
+    http:
+      paths:
+      - path: /
+        pathType: Prefix
+        backend:
+          service:
+            name: app-service
+            port:
+              number: 80
+```
+
+## kubectl Quick Reference
+
+| Command | Description |
+|---------|-------------|
+| `kubectl get pods` | List pods |
+| `kubectl logs <pod>` | View logs |
+| `kubectl exec -it <pod> -- sh` | Shell into pod |
+| `kubectl apply -f manifest.yaml` | Apply config |
+| `kubectl rollout restart deployment/app` | Restart deployment |
+| `kubectl rollout status deployment/app` | Check rollout |
+| `kubectl describe pod <pod>` | Debug pod |
+| `kubectl port-forward svc/app 8080:80` | Local port forward |
+
+## Additional Resources
+
+- `./references/dockerfile-patterns.md` - Advanced Dockerfile techniques
+- `./references/k8s-manifests.md` - Full Kubernetes manifest examples
+- `./references/helm-patterns.md` - Helm chart structure and values
+
+## Scripts
+
+- `./scripts/build-push.sh` - Build and push Docker image
+
+## Assets
+
+- `./assets/Dockerfile.template` - Production Dockerfile template
+- `./assets/docker-compose.template.yml` - Compose starter template

+ 68 - 0
skills/container-orchestration/assets/Dockerfile.template

@@ -0,0 +1,68 @@
+# Production Dockerfile Template
+# Customize for your application
+
+# ==============================================================================
+# Build Stage
+# ==============================================================================
+FROM python:3.11-slim AS builder
+
+WORKDIR /app
+
+# Install build dependencies (if needed)
+RUN apt-get update && apt-get install -y --no-install-recommends \
+    build-essential \
+    && rm -rf /var/lib/apt/lists/*
+
+# Create virtual environment
+RUN python -m venv /opt/venv
+ENV PATH="/opt/venv/bin:$PATH"
+
+# Install Python dependencies
+COPY requirements.txt .
+RUN pip install --no-cache-dir --upgrade pip \
+    && pip install --no-cache-dir -r requirements.txt
+
+# ==============================================================================
+# Production Stage
+# ==============================================================================
+FROM python:3.11-slim
+
+WORKDIR /app
+
+# Install runtime dependencies only
+RUN apt-get update && apt-get install -y --no-install-recommends \
+    # Add runtime dependencies here (e.g., libpq5 for postgres)
+    curl \
+    && rm -rf /var/lib/apt/lists/*
+
+# Copy virtual environment from builder
+COPY --from=builder /opt/venv /opt/venv
+ENV PATH="/opt/venv/bin:$PATH"
+
+# Create non-root user
+RUN groupadd --gid 1000 appgroup \
+    && useradd --uid 1000 --gid appgroup --shell /bin/bash --create-home appuser
+
+# Set ownership
+RUN chown -R appuser:appgroup /app
+
+# Switch to non-root user
+USER appuser
+
+# Copy application code
+COPY --chown=appuser:appgroup src/ ./src/
+
+# Environment variables
+ENV PYTHONUNBUFFERED=1 \
+    PYTHONDONTWRITEBYTECODE=1 \
+    PORT=8000
+
+# Health check
+HEALTHCHECK --interval=30s --timeout=3s --start-period=10s --retries=3 \
+    CMD curl -f http://localhost:${PORT}/health || exit 1
+
+# Expose port
+EXPOSE ${PORT}
+
+# Run application
+CMD ["python", "-m", "uvicorn", "src.main:app", "--host", "0.0.0.0", "--port", "8000"]

+ 140 - 0
skills/container-orchestration/assets/docker-compose.template.yml

@@ -0,0 +1,140 @@
+# Docker Compose Template
+# For local development and testing
+
+version: "3.9"
+
+services:
+  # ==============================================================================
+  # Application
+  # ==============================================================================
+  app:
+    build:
+      context: .
+      dockerfile: Dockerfile
+      # For development, use debug target
+      # target: debug
+    image: ${IMAGE_NAME:-myapp}:${IMAGE_TAG:-latest}
+    container_name: myapp
+    restart: unless-stopped
+    ports:
+      - "${APP_PORT:-8000}:8000"
+    environment:
+      - DATABASE_URL=postgres://${DB_USER:-postgres}:${DB_PASSWORD:-postgres}@db:5432/${DB_NAME:-myapp}
+      - REDIS_URL=redis://redis:6379/0
+      - LOG_LEVEL=${LOG_LEVEL:-info}
+    depends_on:
+      db:
+        condition: service_healthy
+      redis:
+        condition: service_healthy
+    healthcheck:
+      test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
+      interval: 30s
+      timeout: 10s
+      retries: 3
+      start_period: 10s
+    volumes:
+      # Development: mount source code
+      # - ./src:/app/src:ro
+      - app_logs:/app/logs
+    networks:
+      - app-network
+
+  # ==============================================================================
+  # Database
+  # ==============================================================================
+  db:
+    image: postgres:15-alpine
+    container_name: myapp-db
+    restart: unless-stopped
+    environment:
+      POSTGRES_USER: ${DB_USER:-postgres}
+      POSTGRES_PASSWORD: ${DB_PASSWORD:-postgres}
+      POSTGRES_DB: ${DB_NAME:-myapp}
+    ports:
+      - "${DB_PORT:-5432}:5432"
+    volumes:
+      - postgres_data:/var/lib/postgresql/data
+      # - ./init.sql:/docker-entrypoint-initdb.d/init.sql:ro
+    healthcheck:
+      test: ["CMD-SHELL", "pg_isready -U ${DB_USER:-postgres} -d ${DB_NAME:-myapp}"]
+      interval: 10s
+      timeout: 5s
+      retries: 5
+    networks:
+      - app-network
+
+  # ==============================================================================
+  # Cache
+  # ==============================================================================
+  redis:
+    image: redis:7-alpine
+    container_name: myapp-redis
+    restart: unless-stopped
+    command: redis-server --appendonly yes
+    ports:
+      - "${REDIS_PORT:-6379}:6379"
+    volumes:
+      - redis_data:/data
+    healthcheck:
+      test: ["CMD", "redis-cli", "ping"]
+      interval: 10s
+      timeout: 5s
+      retries: 5
+    networks:
+      - app-network
+
+  # ==============================================================================
+  # Optional: Worker (for background jobs)
+  # ==============================================================================
+  # worker:
+  #   build:
+  #     context: .
+  #     dockerfile: Dockerfile
+  #   container_name: myapp-worker
+  #   restart: unless-stopped
+  #   command: python -m celery -A src.worker worker --loglevel=info
+  #   environment:
+  #     - DATABASE_URL=postgres://${DB_USER:-postgres}:${DB_PASSWORD:-postgres}@db:5432/${DB_NAME:-myapp}
+  #     - REDIS_URL=redis://redis:6379/0
+  #   depends_on:
+  #     - db
+  #     - redis
+  #   networks:
+  #     - app-network
+
+  # ==============================================================================
+  # Optional: Nginx (reverse proxy)
+  # ==============================================================================
+  # nginx:
+  #   image: nginx:alpine
+  #   container_name: myapp-nginx
+  #   restart: unless-stopped
+  #   ports:
+  #     - "80:80"
+  #     - "443:443"
+  #   volumes:
+  #     - ./nginx.conf:/etc/nginx/nginx.conf:ro
+  #     - ./certs:/etc/nginx/certs:ro
+  #   depends_on:
+  #     - app
+  #   networks:
+  #     - app-network
+
+# ==============================================================================
+# Volumes
+# ==============================================================================
+volumes:
+  postgres_data:
+    driver: local
+  redis_data:
+    driver: local
+  app_logs:
+    driver: local
+
+# ==============================================================================
+# Networks
+# ==============================================================================
+networks:
+  app-network:
+    driver: bridge

+ 340 - 0
skills/container-orchestration/references/dockerfile-patterns.md

@@ -0,0 +1,340 @@
+# Advanced Dockerfile Patterns
+
+Production-ready Dockerfile techniques.
+
+## Multi-Stage Builds
+
+### Python Application
+
+```dockerfile
+# Stage 1: Build dependencies
+FROM python:3.11-slim AS builder
+
+WORKDIR /app
+
+# Install build dependencies
+RUN apt-get update && apt-get install -y --no-install-recommends \
+    build-essential \
+    && rm -rf /var/lib/apt/lists/*
+
+# Create virtual environment
+RUN python -m venv /opt/venv
+ENV PATH="/opt/venv/bin:$PATH"
+
+# Install dependencies
+COPY requirements.txt .
+RUN pip install --no-cache-dir -r requirements.txt
+
+# Stage 2: Production image
+FROM python:3.11-slim
+
+WORKDIR /app
+
+# Copy virtual environment from builder
+COPY --from=builder /opt/venv /opt/venv
+ENV PATH="/opt/venv/bin:$PATH"
+
+# Create non-root user
+RUN useradd --create-home --shell /bin/bash appuser
+USER appuser
+
+# Copy application
+COPY --chown=appuser:appuser src/ ./src/
+
+EXPOSE 8000
+CMD ["python", "-m", "uvicorn", "src.main:app", "--host", "0.0.0.0"]
+```
+
+### Node.js Application
+
+```dockerfile
+# Stage 1: Dependencies
+FROM node:20-alpine AS deps
+WORKDIR /app
+COPY package*.json ./
+RUN npm ci --only=production
+
+# Stage 2: Build
+FROM node:20-alpine AS builder
+WORKDIR /app
+COPY package*.json ./
+RUN npm ci
+COPY . .
+RUN npm run build
+
+# Stage 3: Production
+FROM node:20-alpine AS runner
+WORKDIR /app
+
+ENV NODE_ENV=production
+RUN addgroup --system --gid 1001 nodejs
+RUN adduser --system --uid 1001 nextjs
+
+COPY --from=deps /app/node_modules ./node_modules
+COPY --from=builder /app/dist ./dist
+COPY --from=builder /app/package.json ./
+
+USER nextjs
+EXPOSE 3000
+CMD ["node", "dist/index.js"]
+```
+
+### Go Application
+
+```dockerfile
+# Stage 1: Build
+FROM golang:1.21-alpine AS builder
+
+WORKDIR /app
+
+# Cache dependencies
+COPY go.mod go.sum ./
+RUN go mod download
+
+# Build
+COPY . .
+RUN CGO_ENABLED=0 GOOS=linux go build -ldflags="-s -w" -o /app/server ./cmd/server
+
+# Stage 2: Minimal runtime
+FROM scratch
+
+# Copy CA certificates for HTTPS
+COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
+
+# Copy binary
+COPY --from=builder /app/server /server
+
+EXPOSE 8080
+ENTRYPOINT ["/server"]
+```
+
+## Layer Optimization
+
+### Order by Change Frequency
+
+```dockerfile
+# Least frequently changed first
+FROM python:3.11-slim
+
+# System packages (rarely change)
+RUN apt-get update && apt-get install -y \
+    libpq5 \
+    && rm -rf /var/lib/apt/lists/*
+
+# Dependencies (change occasionally)
+COPY requirements.txt .
+RUN pip install --no-cache-dir -r requirements.txt
+
+# Application code (changes frequently)
+COPY src/ ./src/
+
+CMD ["python", "-m", "src.main"]
+```
+
+### Combine RUN Commands
+
+```dockerfile
+# BAD - Multiple layers
+RUN apt-get update
+RUN apt-get install -y curl
+RUN apt-get install -y git
+RUN rm -rf /var/lib/apt/lists/*
+
+# GOOD - Single layer
+RUN apt-get update && apt-get install -y --no-install-recommends \
+    curl \
+    git \
+    && rm -rf /var/lib/apt/lists/*
+```
+
+## Security Best Practices
+
+### Non-Root User
+
+```dockerfile
+# Create user with specific UID
+RUN groupadd --gid 1000 appgroup \
+    && useradd --uid 1000 --gid appgroup --shell /bin/bash --create-home appuser
+
+# Switch to user
+USER appuser
+
+# Copy files with correct ownership
+COPY --chown=appuser:appgroup src/ ./src/
+```
+
+### Read-Only Root Filesystem
+
+```dockerfile
+# Use with docker run --read-only
+FROM python:3.11-slim
+
+# Create writable directories
+RUN mkdir -p /tmp /var/log/app \
+    && chown -R appuser:appuser /tmp /var/log/app
+
+USER appuser
+
+# Application writes only to /tmp and /var/log/app
+```
+
+### No Secrets in Image
+
+```dockerfile
+# WRONG - Secret in build arg
+ARG API_KEY
+ENV API_KEY=${API_KEY}
+
+# CORRECT - Secret at runtime
+# Pass via environment variable or secret manager
+ENV API_KEY=""  # Set at runtime
+```
+
+### Minimal Base Image
+
+```dockerfile
+# Full image: ~1GB
+FROM python:3.11
+
+# Slim image: ~150MB
+FROM python:3.11-slim
+
+# Alpine image: ~50MB (but musl libc issues)
+FROM python:3.11-alpine
+
+# Distroless: Minimal, no shell
+FROM gcr.io/distroless/python3-debian12
+```
+
+## Health Checks
+
+```dockerfile
+# HTTP health check
+HEALTHCHECK --interval=30s --timeout=3s --start-period=10s --retries=3 \
+    CMD curl -f http://localhost:8000/health || exit 1
+
+# Without curl (for minimal images)
+HEALTHCHECK --interval=30s --timeout=3s \
+    CMD python -c "import urllib.request; urllib.request.urlopen('http://localhost:8000/health')"
+
+# TCP health check
+HEALTHCHECK --interval=30s --timeout=3s \
+    CMD nc -z localhost 8000 || exit 1
+```
+
+## Build Arguments
+
+```dockerfile
+# Declare build args
+ARG PYTHON_VERSION=3.11
+ARG APP_ENV=production
+
+FROM python:${PYTHON_VERSION}-slim
+
+# Use in ENV
+ARG APP_ENV
+ENV APP_ENV=${APP_ENV}
+
+# Conditional logic
+RUN if [ "$APP_ENV" = "development" ]; then \
+        pip install debugpy pytest; \
+    fi
+```
+
+## Caching Strategies
+
+### Mount Cache (BuildKit)
+
+```dockerfile
+# syntax=docker/dockerfile:1.4
+
+# Cache pip downloads
+RUN --mount=type=cache,target=/root/.cache/pip \
+    pip install -r requirements.txt
+
+# Cache apt packages
+RUN --mount=type=cache,target=/var/cache/apt \
+    apt-get update && apt-get install -y curl
+```
+
+### Bind Mounts for Build
+
+```dockerfile
+# syntax=docker/dockerfile:1.4
+
+# Mount source code without copying
+RUN --mount=type=bind,source=src,target=/app/src \
+    python -m compileall /app/src
+```
+
+## Labels and Metadata
+
+```dockerfile
+LABEL org.opencontainers.image.title="My App"
+LABEL org.opencontainers.image.description="Production application"
+LABEL org.opencontainers.image.version="1.0.0"
+LABEL org.opencontainers.image.vendor="Company"
+LABEL org.opencontainers.image.source="https://github.com/org/repo"
+```
+
+## .dockerignore
+
+```
+# .dockerignore
+.git
+.gitignore
+.env
+.env.*
+*.md
+!README.md
+Dockerfile*
+docker-compose*
+.dockerignore
+
+# Python
+__pycache__
+*.pyc
+*.pyo
+.pytest_cache
+.coverage
+htmlcov
+.venv
+venv
+
+# Node
+node_modules
+npm-debug.log
+.npm
+
+# IDE
+.idea
+.vscode
+*.swp
+```
+
+## Debug Container
+
+```dockerfile
+# Multi-stage with debug target
+FROM python:3.11-slim AS base
+WORKDIR /app
+COPY requirements.txt .
+RUN pip install -r requirements.txt
+COPY src/ ./src/
+
+# Debug stage
+FROM base AS debug
+RUN pip install debugpy
+CMD ["python", "-m", "debugpy", "--listen", "0.0.0.0:5678", "-m", "src.main"]
+
+# Production stage
+FROM base AS production
+USER appuser
+CMD ["python", "-m", "src.main"]
+```
+
+Build specific target:
+```bash
+docker build --target debug -t myapp:debug .
+docker build --target production -t myapp:latest .
+```

+ 376 - 0
skills/container-orchestration/references/helm-patterns.md

@@ -0,0 +1,376 @@
+# Helm Chart Patterns
+
+Production Helm chart structure and patterns.
+
+## Chart Structure
+
+```
+myapp/
+├── Chart.yaml
+├── values.yaml
+├── values-staging.yaml
+├── values-production.yaml
+├── templates/
+│   ├── _helpers.tpl
+│   ├── deployment.yaml
+│   ├── service.yaml
+│   ├── ingress.yaml
+│   ├── configmap.yaml
+│   ├── secret.yaml
+│   ├── hpa.yaml
+│   ├── pdb.yaml
+│   └── NOTES.txt
+└── charts/           # Dependencies
+```
+
+## Chart.yaml
+
+```yaml
+apiVersion: v2
+name: myapp
+description: My Application Helm Chart
+type: application
+version: 1.0.0
+appVersion: "2.0.0"
+keywords:
+  - web
+  - api
+maintainers:
+  - name: Team
+    email: team@example.com
+dependencies:
+  - name: postgresql
+    version: "12.x.x"
+    repository: https://charts.bitnami.com/bitnami
+    condition: postgresql.enabled
+```
+
+## values.yaml
+
+```yaml
+# Default values for myapp
+
+replicaCount: 3
+
+image:
+  repository: myregistry/myapp
+  pullPolicy: IfNotPresent
+  tag: ""  # Defaults to appVersion
+
+imagePullSecrets: []
+nameOverride: ""
+fullnameOverride: ""
+
+serviceAccount:
+  create: true
+  annotations: {}
+  name: ""
+
+podAnnotations: {}
+
+podSecurityContext:
+  runAsNonRoot: true
+  runAsUser: 1000
+  fsGroup: 1000
+
+securityContext:
+  allowPrivilegeEscalation: false
+  readOnlyRootFilesystem: true
+  capabilities:
+    drop:
+      - ALL
+
+service:
+  type: ClusterIP
+  port: 80
+
+ingress:
+  enabled: false
+  className: nginx
+  annotations: {}
+  hosts:
+    - host: app.example.com
+      paths:
+        - path: /
+          pathType: Prefix
+  tls: []
+
+resources:
+  limits:
+    cpu: 500m
+    memory: 512Mi
+  requests:
+    cpu: 100m
+    memory: 128Mi
+
+autoscaling:
+  enabled: true
+  minReplicas: 3
+  maxReplicas: 10
+  targetCPUUtilizationPercentage: 70
+  targetMemoryUtilizationPercentage: 80
+
+pdb:
+  enabled: true
+  minAvailable: 2
+
+nodeSelector: {}
+tolerations: []
+affinity: {}
+
+# Application config
+config:
+  logLevel: info
+  cacheTtl: 3600
+
+# Secrets (use external secrets in production)
+secrets:
+  databaseUrl: ""
+  apiKey: ""
+
+# Database dependency
+postgresql:
+  enabled: false
+  auth:
+    database: myapp
+```
+
+## Helper Template (_helpers.tpl)
+
+```yaml
+{{/*
+Expand the name of the chart.
+*/}}
+{{- define "myapp.name" -}}
+{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
+{{- end }}
+
+{{/*
+Create a default fully qualified app name.
+*/}}
+{{- define "myapp.fullname" -}}
+{{- if .Values.fullnameOverride }}
+{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
+{{- else }}
+{{- $name := default .Chart.Name .Values.nameOverride }}
+{{- if contains $name .Release.Name }}
+{{- .Release.Name | trunc 63 | trimSuffix "-" }}
+{{- else }}
+{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
+{{- end }}
+{{- end }}
+{{- end }}
+
+{{/*
+Create chart name and version as used by the chart label.
+*/}}
+{{- define "myapp.chart" -}}
+{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
+{{- end }}
+
+{{/*
+Common labels
+*/}}
+{{- define "myapp.labels" -}}
+helm.sh/chart: {{ include "myapp.chart" . }}
+{{ include "myapp.selectorLabels" . }}
+{{- if .Chart.AppVersion }}
+app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
+{{- end }}
+app.kubernetes.io/managed-by: {{ .Release.Service }}
+{{- end }}
+
+{{/*
+Selector labels
+*/}}
+{{- define "myapp.selectorLabels" -}}
+app.kubernetes.io/name: {{ include "myapp.name" . }}
+app.kubernetes.io/instance: {{ .Release.Name }}
+{{- end }}
+
+{{/*
+Create the name of the service account to use
+*/}}
+{{- define "myapp.serviceAccountName" -}}
+{{- if .Values.serviceAccount.create }}
+{{- default (include "myapp.fullname" .) .Values.serviceAccount.name }}
+{{- else }}
+{{- default "default" .Values.serviceAccount.name }}
+{{- end }}
+{{- end }}
+```
+
+## Deployment Template
+
+```yaml
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: {{ include "myapp.fullname" . }}
+  labels:
+    {{- include "myapp.labels" . | nindent 4 }}
+spec:
+  {{- if not .Values.autoscaling.enabled }}
+  replicas: {{ .Values.replicaCount }}
+  {{- end }}
+  selector:
+    matchLabels:
+      {{- include "myapp.selectorLabels" . | nindent 6 }}
+  template:
+    metadata:
+      annotations:
+        checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }}
+        {{- with .Values.podAnnotations }}
+        {{- toYaml . | nindent 8 }}
+        {{- end }}
+      labels:
+        {{- include "myapp.selectorLabels" . | nindent 8 }}
+    spec:
+      {{- with .Values.imagePullSecrets }}
+      imagePullSecrets:
+        {{- toYaml . | nindent 8 }}
+      {{- end }}
+      serviceAccountName: {{ include "myapp.serviceAccountName" . }}
+      securityContext:
+        {{- toYaml .Values.podSecurityContext | nindent 8 }}
+      containers:
+        - name: {{ .Chart.Name }}
+          securityContext:
+            {{- toYaml .Values.securityContext | nindent 12 }}
+          image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
+          imagePullPolicy: {{ .Values.image.pullPolicy }}
+          ports:
+            - name: http
+              containerPort: 8000
+              protocol: TCP
+          livenessProbe:
+            httpGet:
+              path: /health
+              port: http
+            initialDelaySeconds: 10
+            periodSeconds: 30
+          readinessProbe:
+            httpGet:
+              path: /ready
+              port: http
+            initialDelaySeconds: 5
+            periodSeconds: 10
+          resources:
+            {{- toYaml .Values.resources | nindent 12 }}
+          envFrom:
+            - configMapRef:
+                name: {{ include "myapp.fullname" . }}
+            - secretRef:
+                name: {{ include "myapp.fullname" . }}
+          volumeMounts:
+            - name: tmp
+              mountPath: /tmp
+      volumes:
+        - name: tmp
+          emptyDir: {}
+      {{- with .Values.nodeSelector }}
+      nodeSelector:
+        {{- toYaml . | nindent 8 }}
+      {{- end }}
+      {{- with .Values.affinity }}
+      affinity:
+        {{- toYaml . | nindent 8 }}
+      {{- end }}
+      {{- with .Values.tolerations }}
+      tolerations:
+        {{- toYaml . | nindent 8 }}
+      {{- end }}
+```
+
+## Helm Commands
+
+```bash
+# Install
+helm install myapp ./myapp -f values-production.yaml
+
+# Upgrade
+helm upgrade myapp ./myapp -f values-production.yaml
+
+# Dry run
+helm install myapp ./myapp --dry-run --debug
+
+# Template output
+helm template myapp ./myapp -f values-production.yaml
+
+# Rollback
+helm rollback myapp 1
+
+# History
+helm history myapp
+
+# Uninstall
+helm uninstall myapp
+```
+
+## Environment-Specific Values
+
+### values-staging.yaml
+
+```yaml
+replicaCount: 2
+
+ingress:
+  enabled: true
+  hosts:
+    - host: staging.app.example.com
+      paths:
+        - path: /
+          pathType: Prefix
+  tls:
+    - secretName: staging-tls
+      hosts:
+        - staging.app.example.com
+
+resources:
+  limits:
+    cpu: 250m
+    memory: 256Mi
+  requests:
+    cpu: 50m
+    memory: 64Mi
+
+autoscaling:
+  enabled: false
+```
+
+### values-production.yaml
+
+```yaml
+replicaCount: 3
+
+ingress:
+  enabled: true
+  annotations:
+    nginx.ingress.kubernetes.io/ssl-redirect: "true"
+  hosts:
+    - host: app.example.com
+      paths:
+        - path: /
+          pathType: Prefix
+  tls:
+    - secretName: production-tls
+      hosts:
+        - app.example.com
+
+resources:
+  limits:
+    cpu: 500m
+    memory: 512Mi
+  requests:
+    cpu: 100m
+    memory: 128Mi
+
+autoscaling:
+  enabled: true
+  minReplicas: 3
+  maxReplicas: 20
+
+pdb:
+  enabled: true
+  minAvailable: 2
+```

+ 381 - 0
skills/container-orchestration/references/k8s-manifests.md

@@ -0,0 +1,381 @@
+# Kubernetes Manifests
+
+Production Kubernetes configuration examples.
+
+## Complete Application Stack
+
+### Namespace
+
+```yaml
+apiVersion: v1
+kind: Namespace
+metadata:
+  name: myapp
+  labels:
+    app: myapp
+```
+
+### ConfigMap
+
+```yaml
+apiVersion: v1
+kind: ConfigMap
+metadata:
+  name: app-config
+  namespace: myapp
+data:
+  LOG_LEVEL: "info"
+  CACHE_TTL: "3600"
+  config.yaml: |
+    server:
+      port: 8000
+      workers: 4
+    database:
+      pool_size: 10
+```
+
+### Secret
+
+```yaml
+apiVersion: v1
+kind: Secret
+metadata:
+  name: app-secrets
+  namespace: myapp
+type: Opaque
+stringData:
+  DATABASE_URL: postgres://user:pass@db:5432/app
+  API_KEY: supersecretkey
+---
+# External Secrets (for AWS Secrets Manager, etc.)
+apiVersion: external-secrets.io/v1beta1
+kind: ExternalSecret
+metadata:
+  name: app-secrets
+  namespace: myapp
+spec:
+  refreshInterval: 1h
+  secretStoreRef:
+    name: aws-secrets-manager
+    kind: SecretStore
+  target:
+    name: app-secrets
+  data:
+  - secretKey: DATABASE_URL
+    remoteRef:
+      key: myapp/database-url
+```
+
+### Deployment
+
+```yaml
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: app
+  namespace: myapp
+  labels:
+    app: myapp
+    version: v1
+spec:
+  replicas: 3
+  selector:
+    matchLabels:
+      app: myapp
+  strategy:
+    type: RollingUpdate
+    rollingUpdate:
+      maxSurge: 1
+      maxUnavailable: 0
+  template:
+    metadata:
+      labels:
+        app: myapp
+        version: v1
+      annotations:
+        prometheus.io/scrape: "true"
+        prometheus.io/port: "8000"
+    spec:
+      serviceAccountName: app-service-account
+      securityContext:
+        runAsNonRoot: true
+        runAsUser: 1000
+        fsGroup: 1000
+      containers:
+      - name: app
+        image: myregistry/myapp:1.0.0
+        imagePullPolicy: IfNotPresent
+        ports:
+        - name: http
+          containerPort: 8000
+          protocol: TCP
+        env:
+        - name: LOG_LEVEL
+          valueFrom:
+            configMapKeyRef:
+              name: app-config
+              key: LOG_LEVEL
+        - name: DATABASE_URL
+          valueFrom:
+            secretKeyRef:
+              name: app-secrets
+              key: DATABASE_URL
+        resources:
+          requests:
+            memory: "128Mi"
+            cpu: "100m"
+          limits:
+            memory: "512Mi"
+            cpu: "500m"
+        livenessProbe:
+          httpGet:
+            path: /health
+            port: http
+          initialDelaySeconds: 10
+          periodSeconds: 30
+          timeoutSeconds: 5
+          failureThreshold: 3
+        readinessProbe:
+          httpGet:
+            path: /ready
+            port: http
+          initialDelaySeconds: 5
+          periodSeconds: 10
+          timeoutSeconds: 3
+          failureThreshold: 3
+        securityContext:
+          allowPrivilegeEscalation: false
+          readOnlyRootFilesystem: true
+          capabilities:
+            drop:
+            - ALL
+        volumeMounts:
+        - name: tmp
+          mountPath: /tmp
+        - name: config
+          mountPath: /app/config
+          readOnly: true
+      volumes:
+      - name: tmp
+        emptyDir: {}
+      - name: config
+        configMap:
+          name: app-config
+      affinity:
+        podAntiAffinity:
+          preferredDuringSchedulingIgnoredDuringExecution:
+          - weight: 100
+            podAffinityTerm:
+              labelSelector:
+                matchLabels:
+                  app: myapp
+              topologyKey: kubernetes.io/hostname
+```
+
+### Service
+
+```yaml
+apiVersion: v1
+kind: Service
+metadata:
+  name: app-service
+  namespace: myapp
+spec:
+  type: ClusterIP
+  selector:
+    app: myapp
+  ports:
+  - name: http
+    port: 80
+    targetPort: http
+    protocol: TCP
+```
+
+### Ingress
+
+```yaml
+apiVersion: networking.k8s.io/v1
+kind: Ingress
+metadata:
+  name: app-ingress
+  namespace: myapp
+  annotations:
+    nginx.ingress.kubernetes.io/ssl-redirect: "true"
+    nginx.ingress.kubernetes.io/proxy-body-size: "10m"
+    cert-manager.io/cluster-issuer: "letsencrypt-prod"
+spec:
+  ingressClassName: nginx
+  tls:
+  - hosts:
+    - app.example.com
+    secretName: app-tls
+  rules:
+  - host: app.example.com
+    http:
+      paths:
+      - path: /
+        pathType: Prefix
+        backend:
+          service:
+            name: app-service
+            port:
+              number: 80
+```
+
+### HorizontalPodAutoscaler
+
+```yaml
+apiVersion: autoscaling/v2
+kind: HorizontalPodAutoscaler
+metadata:
+  name: app-hpa
+  namespace: myapp
+spec:
+  scaleTargetRef:
+    apiVersion: apps/v1
+    kind: Deployment
+    name: app
+  minReplicas: 3
+  maxReplicas: 10
+  metrics:
+  - type: Resource
+    resource:
+      name: cpu
+      target:
+        type: Utilization
+        averageUtilization: 70
+  - type: Resource
+    resource:
+      name: memory
+      target:
+        type: Utilization
+        averageUtilization: 80
+  behavior:
+    scaleDown:
+      stabilizationWindowSeconds: 300
+      policies:
+      - type: Percent
+        value: 10
+        periodSeconds: 60
+    scaleUp:
+      stabilizationWindowSeconds: 0
+      policies:
+      - type: Percent
+        value: 100
+        periodSeconds: 15
+```
+
+### PodDisruptionBudget
+
+```yaml
+apiVersion: policy/v1
+kind: PodDisruptionBudget
+metadata:
+  name: app-pdb
+  namespace: myapp
+spec:
+  minAvailable: 2
+  selector:
+    matchLabels:
+      app: myapp
+```
+
+### ServiceAccount and RBAC
+
+```yaml
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+  name: app-service-account
+  namespace: myapp
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: Role
+metadata:
+  name: app-role
+  namespace: myapp
+rules:
+- apiGroups: [""]
+  resources: ["configmaps", "secrets"]
+  verbs: ["get", "list"]
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: RoleBinding
+metadata:
+  name: app-role-binding
+  namespace: myapp
+subjects:
+- kind: ServiceAccount
+  name: app-service-account
+  namespace: myapp
+roleRef:
+  kind: Role
+  name: app-role
+  apiGroup: rbac.authorization.k8s.io
+```
+
+### NetworkPolicy
+
+```yaml
+apiVersion: networking.k8s.io/v1
+kind: NetworkPolicy
+metadata:
+  name: app-network-policy
+  namespace: myapp
+spec:
+  podSelector:
+    matchLabels:
+      app: myapp
+  policyTypes:
+  - Ingress
+  - Egress
+  ingress:
+  - from:
+    - namespaceSelector:
+        matchLabels:
+          name: ingress-nginx
+    ports:
+    - protocol: TCP
+      port: 8000
+  egress:
+  - to:
+    - namespaceSelector:
+        matchLabels:
+          name: database
+    ports:
+    - protocol: TCP
+      port: 5432
+  - to:
+    - namespaceSelector: {}
+    ports:
+    - protocol: UDP
+      port: 53  # DNS
+```
+
+### CronJob
+
+```yaml
+apiVersion: batch/v1
+kind: CronJob
+metadata:
+  name: cleanup-job
+  namespace: myapp
+spec:
+  schedule: "0 2 * * *"  # 2 AM daily
+  concurrencyPolicy: Forbid
+  successfulJobsHistoryLimit: 3
+  failedJobsHistoryLimit: 1
+  jobTemplate:
+    spec:
+      template:
+        spec:
+          restartPolicy: OnFailure
+          containers:
+          - name: cleanup
+            image: myregistry/myapp:1.0.0
+            command: ["python", "-m", "src.jobs.cleanup"]
+            resources:
+              limits:
+                memory: "256Mi"
+                cpu: "200m"
+```

+ 85 - 0
skills/container-orchestration/scripts/build-push.sh

@@ -0,0 +1,85 @@
+#!/bin/bash
+# Build and push Docker image
+# Usage: ./build-push.sh [--tag TAG] [--registry REGISTRY] [--push]
+
+set -e
+
+# Defaults
+REGISTRY="${DOCKER_REGISTRY:-}"
+TAG="${IMAGE_TAG:-latest}"
+PUSH=false
+DOCKERFILE="Dockerfile"
+CONTEXT="."
+
+# Parse arguments
+while [[ $# -gt 0 ]]; do
+    case $1 in
+        --tag|-t)
+            TAG="$2"
+            shift 2
+            ;;
+        --registry|-r)
+            REGISTRY="$2"
+            shift 2
+            ;;
+        --push|-p)
+            PUSH=true
+            shift
+            ;;
+        --dockerfile|-f)
+            DOCKERFILE="$2"
+            shift 2
+            ;;
+        --context|-c)
+            CONTEXT="$2"
+            shift 2
+            ;;
+        *)
+            echo "Unknown option: $1"
+            exit 1
+            ;;
+    esac
+done
+
+# Get image name from directory or git
+if [ -z "$IMAGE_NAME" ]; then
+    IMAGE_NAME=$(basename "$(pwd)")
+fi
+
+# Build full image name
+if [ -n "$REGISTRY" ]; then
+    FULL_IMAGE="${REGISTRY}/${IMAGE_NAME}:${TAG}"
+else
+    FULL_IMAGE="${IMAGE_NAME}:${TAG}"
+fi
+
+echo "=== Building Docker Image ==="
+echo "Image: $FULL_IMAGE"
+echo "Dockerfile: $DOCKERFILE"
+echo "Context: $CONTEXT"
+echo ""
+
+# Build
+docker build \
+    -t "$FULL_IMAGE" \
+    -f "$DOCKERFILE" \
+    --build-arg BUILD_DATE="$(date -u +'%Y-%m-%dT%H:%M:%SZ')" \
+    --build-arg VCS_REF="$(git rev-parse --short HEAD 2>/dev/null || echo 'unknown')" \
+    "$CONTEXT"
+
+echo ""
+echo "=== Build Complete ==="
+echo "Image: $FULL_IMAGE"
+
+# Push if requested
+if [ "$PUSH" = true ]; then
+    echo ""
+    echo "=== Pushing Image ==="
+    docker push "$FULL_IMAGE"
+    echo "Pushed: $FULL_IMAGE"
+fi
+
+# Show image info
+echo ""
+echo "=== Image Info ==="
+docker images "$FULL_IMAGE" --format "table {{.Repository}}\t{{.Tag}}\t{{.Size}}\t{{.CreatedAt}}"

+ 37 - 122
skills/doc-scanner/SKILL.md

@@ -6,165 +6,80 @@ allowed-tools: "Glob Read Write Bash"
 
 # Documentation Scanner
 
-Scan for and synthesize project documentation across AI assistants, IDEs, and CLI tools.
+Scan for and synthesize project documentation.
 
 ## When to Activate
 
-Use this skill when:
 - User asks to review, understand, or explore a codebase
-- User says "review this codebase", "explain this project", "what does this repo do"
-- Starting work in a new or unfamiliar project
-- User asks about project conventions, workflows, or recommended agents
-- User asks "how do I work with this codebase" or similar
-- User asks which agent to use for a task
+- Starting work in a new/unfamiliar project
+- User asks about project conventions or workflows
 - Before making significant architectural decisions
-- User explicitly invokes `doc-scanner` skill
 
 ## Instructions
 
-### Step 0: Load Skill Resources (Do This First)
+### Step 1: Scan for Documentation
 
-Before scanning the project, read the supporting files from this skill directory:
+Use Glob to search project root:
 
-1. Read `~/.claude/skills/doc-scanner/reference.md` - Contains the complete list of documentation files to scan for
-2. Read `~/.claude/skills/doc-scanner/templates.md` - Contains templates for generating AGENTS.md
-
-These files provide the patterns and templates needed for the remaining steps.
-
-### Step 1: Scan for Documentation Files
-
-Use Glob to search the project root for documentation files using the patterns from `reference.md`.
-
-Priority order:
-1. **AGENTS.md** - Platform-agnostic (highest priority)
-2. **CLAUDE.md** - Claude-specific workflows
-3. **Other AI docs** - GEMINI.md, COPILOT.md, CHATGPT.md, CODEIUM.md
-4. **IDE docs** - CURSOR.md, WINDSURF.md, VSCODE.md, JETBRAINS.md
-5. **Terminal docs** - WARP.md, FIG.md, ZELLIJ.md
-6. **Environment docs** - DEVCONTAINER.md, GITPOD.md, CODESPACES.md
-7. **Generic docs** - AI.md, ASSISTANT.md
+```
+AGENTS.md, CLAUDE.md, AI.md, ASSISTANT.md,
+GEMINI.md, COPILOT.md, CHATGPT.md, CODEIUM.md,
+CURSOR.md, WINDSURF.md, VSCODE.md, JETBRAINS.md,
+WARP.md, FIG.md, DEVCONTAINER.md, GITPOD.md
+```
 
 ### Step 2: Read All Found Files
 
-Read the complete contents of every documentation file found. Do not skip any.
+Read complete contents of every documentation file found.
 
-### Step 3: Synthesize and Present
+### Step 3: Synthesize
 
-Combine information from all sources into a unified summary:
+Combine information into unified summary:
 
 ```
 PROJECT DOCUMENTATION
 
-Sources: [list each file found]
+Sources: [list files found]
 
 RECOMMENDED AGENTS
-  Primary: [agents recommended for core work]
+  Primary: [agents for core work]
   Secondary: [agents for specific tasks]
 
 KEY WORKFLOWS
-  [consolidated workflows from all docs]
+  [consolidated workflows]
 
 CONVENTIONS
-  [code style, patterns, architecture guidelines]
+  [code style, patterns]
 
 QUICK COMMANDS
-  [common commands extracted from docs]
+  [common commands]
 ```
 
-When information conflicts between files:
-- Prefer AGENTS.md (platform-agnostic)
-- Then CLAUDE.md (Claude-specific)
-- Note platform-specific details with annotations like "(from CURSOR.md)"
-
 ### Step 4: Offer Consolidation
 
-If 2 or more documentation files exist, ask the user:
-
-"I found [N] documentation files. Would you like me to consolidate them into a single AGENTS.md?
-
-This would:
-- Merge all guidance into one platform-agnostic file
-- Preserve platform-specific notes with annotations
-- Archive originals to `.doc-archive/`
-
-Reply 'yes' to consolidate, or 'no' to keep separate files."
-
-**If user agrees to consolidate, follow these steps IN ORDER:**
-
-#### 4a: Create Archive Directory
-
-Use Bash to create the archive directory:
-```bash
-mkdir -p .doc-archive
-```
-
-#### 4b: Archive Each Original File (REQUIRED)
-
-For EACH documentation file found (except AGENTS.md if it exists), archive it BEFORE creating the new AGENTS.md:
-
-```bash
-# Get today's date for the suffix
-DATE=$(date +%Y-%m-%d)
-
-# Move each file - repeat for every doc file found
-mv CLAUDE.md .doc-archive/CLAUDE.md.$DATE
-mv WARP.md .doc-archive/WARP.md.$DATE
-# etc. for each file
-```
+If 2+ documentation files exist, offer to consolidate:
 
-**Do not skip this step.** Every original file must be safely archived before proceeding.
-
-#### 4c: Verify Archives Exist
-
-Use Glob to confirm files were archived:
-```
-.doc-archive/*.md.*
-```
-
-List what was archived to the user.
-
-#### 4d: Generate Unified AGENTS.md
-
-Now create the new AGENTS.md using the template from `templates.md`. Include:
-- Content merged from all archived files
-- HTML comments marking the source: `<!-- Source: CLAUDE.md -->`
-- Platform-specific notes clearly labeled
-
-#### 4e: Confirm Completion
-
-Report to user:
-```
-Consolidation complete.
-
-Archived to .doc-archive/:
-  - CLAUDE.md.2024-01-15
-  - WARP.md.2024-01-15
-
-Created: AGENTS.md (unified documentation)
-```
+1. Create `.doc-archive/` directory
+2. Archive originals with date suffix
+3. Generate unified AGENTS.md
+4. Report what was consolidated
 
 ### Step 5: No Documentation Found
 
-If no documentation files exist:
+If none found, offer to generate AGENTS.md based on:
+- Project structure and tech stack
+- Patterns observed in codebase
 
-```
-No project documentation found.
-
-Recommended: Create AGENTS.md for AI-agnostic project guidance.
-
-I can generate a starter AGENTS.md based on:
-- This project's structure and tech stack
-- Common patterns I observe in the codebase
-
-Would you like me to create one?
-```
+## Priority Order
 
-If user agrees, analyze the project and generate appropriate AGENTS.md using the template structure from `templates.md`.
+1. AGENTS.md (platform-agnostic)
+2. CLAUDE.md (Claude-specific)
+3. Other AI docs
+4. IDE docs
+5. Terminal docs
 
-## Important Notes
+## Additional Resources
 
-- Always read documentation files completely before summarizing
-- Preserve original intent when synthesizing multiple sources
-- Platform-specific instructions (e.g., Cursor keybindings) should be noted but marked as potentially non-applicable
-- Never delete original files without archiving first
-- Keep summaries concise but comprehensive
+For detailed patterns, load:
+- `./references/file-patterns.md` - Complete list of files to scan
+- `./references/templates.md` - AGENTS.md generation templates

+ 178 - 0
skills/doc-scanner/references/file-patterns.md

@@ -0,0 +1,178 @@
+# Documentation File Patterns
+
+Complete list of documentation files to scan for project-level AI assistant guidance.
+
+## Priority 1: Platform-Agnostic
+
+| File | Purpose |
+|------|---------|
+| `AGENTS.md` | AI-agnostic project guidance (highest priority) |
+| `AI.md` | General AI assistant instructions |
+| `ASSISTANT.md` | Generic assistant documentation |
+
+## Priority 2: Claude-Specific
+
+| File | Purpose |
+|------|---------|
+| `CLAUDE.md` | Claude Code specific instructions |
+| `.claude/CLAUDE.md` | Claude in config directory |
+| `claude.md` | Lowercase variant |
+
+## Priority 3: Other AI Assistants
+
+| File | Purpose |
+|------|---------|
+| `GEMINI.md` | Google Gemini instructions |
+| `COPILOT.md` | GitHub Copilot instructions |
+| `CHATGPT.md` | ChatGPT/OpenAI instructions |
+| `CODEIUM.md` | Codeium assistant instructions |
+
+## Priority 4: IDE-Specific
+
+| File | Purpose |
+|------|---------|
+| `CURSOR.md` | Cursor IDE instructions |
+| `WINDSURF.md` | Windsurf IDE instructions |
+| `VSCODE.md` | VS Code with AI extensions |
+| `JETBRAINS.md` | JetBrains AI Assistant |
+
+## Priority 5: Terminal/CLI Tools
+
+| File | Purpose |
+|------|---------|
+| `WARP.md` | Warp terminal AI instructions |
+| `FIG.md` | Fig/Amazon Q instructions |
+| `ZELLIJ.md` | Zellij terminal multiplexer |
+
+## Priority 6: Cloud Development Environments
+
+| File | Purpose |
+|------|---------|
+| `DEVCONTAINER.md` | VS Code Dev Containers |
+| `GITPOD.md` | Gitpod workspaces |
+| `CODESPACES.md` | GitHub Codespaces |
+
+## Glob Patterns for Scanning
+
+```bash
+# Root level (most common)
+*.md          # All markdown in root
+
+# Standard patterns
+AGENTS.md
+CLAUDE.md
+AI.md
+ASSISTANT.md
+
+# Case variations
+[Aa][Gg][Ee][Nn][Tt][Ss].md
+[Cc][Ll][Aa][Uu][Dd][Ee].md
+
+# Hidden directories
+.claude/*.md
+.cursor/*.md
+.github/*.md
+
+# Documentation directories
+docs/AGENTS.md
+docs/AI.md
+.docs/*.md
+```
+
+## Full Pattern List
+
+```
+# Platform-agnostic
+AGENTS.md
+AI.md
+ASSISTANT.md
+
+# Claude
+CLAUDE.md
+.claude/CLAUDE.md
+.claude/README.md
+
+# Other AI
+GEMINI.md
+COPILOT.md
+CHATGPT.md
+OPENAI.md
+CODEIUM.md
+
+# IDEs
+CURSOR.md
+.cursor/RULES.md
+WINDSURF.md
+VSCODE.md
+JETBRAINS.md
+
+# Terminals
+WARP.md
+FIG.md
+ZELLIJ.md
+
+# Dev environments
+DEVCONTAINER.md
+.devcontainer/README.md
+GITPOD.md
+.gitpod.md
+CODESPACES.md
+.codespaces/README.md
+
+# Other documentation that may help
+CONTRIBUTING.md
+DEVELOPMENT.md
+ARCHITECTURE.md
+CONVENTIONS.md
+STYLE.md
+```
+
+## File Content Expectations
+
+### AGENTS.md Structure
+
+```markdown
+# Project Name - Agent Guidelines
+
+## Overview
+Brief project description
+
+## Recommended Agents
+Which agents work best for this project
+
+## Key Workflows
+Common development tasks
+
+## Conventions
+Code style and patterns
+
+## Commands
+Quick reference commands
+```
+
+### CLAUDE.md Structure
+
+```markdown
+# Claude Code Instructions
+
+## Project Context
+What this project does
+
+## Key Patterns
+Important code patterns
+
+## Tools and Workflows
+Available commands
+
+## Constraints
+What to avoid
+```
+
+## Scanning Best Practices
+
+1. **Check root first** - Most docs are in project root
+2. **Respect case variations** - Some use lowercase
+3. **Check hidden directories** - `.claude/`, `.cursor/`
+4. **Read completely** - Don't truncate important docs
+5. **Preserve intent** - When consolidating, keep original meaning
+6. **Note platform specifics** - Mark IDE/tool-specific instructions

+ 349 - 0
skills/doc-scanner/references/templates.md

@@ -0,0 +1,349 @@
+# Documentation Templates
+
+Templates for generating AGENTS.md and consolidating project documentation.
+
+## Minimal AGENTS.md Template
+
+```markdown
+# Project Name
+
+Brief description of what this project does.
+
+## Quick Start
+
+\`\`\`bash
+# Setup
+npm install  # or pip install, etc.
+
+# Run
+npm start    # or relevant command
+\`\`\`
+
+## Key Files
+
+- `src/` - Source code
+- `tests/` - Test files
+- `package.json` - Dependencies
+
+## Conventions
+
+- [Convention 1]
+- [Convention 2]
+```
+
+## Standard AGENTS.md Template
+
+```markdown
+# Project Name
+
+## Overview
+
+Brief description of what this project does and its main purpose.
+
+## Recommended Agents
+
+| Agent | Use For |
+|-------|---------|
+| [agent-name] | [when to use] |
+
+## Tech Stack
+
+- **Language:** [language]
+- **Framework:** [framework]
+- **Database:** [database]
+- **Deployment:** [platform]
+
+## Key Workflows
+
+### Development
+\`\`\`bash
+[dev commands]
+\`\`\`
+
+### Testing
+\`\`\`bash
+[test commands]
+\`\`\`
+
+### Deployment
+\`\`\`bash
+[deploy commands]
+\`\`\`
+
+## Project Structure
+
+\`\`\`
+project/
+├── src/           # Source code
+├── tests/         # Test files
+├── docs/          # Documentation
+└── config/        # Configuration
+\`\`\`
+
+## Conventions
+
+### Code Style
+- [style convention 1]
+- [style convention 2]
+
+### Naming
+- [naming convention 1]
+- [naming convention 2]
+
+### Architecture
+- [architecture pattern]
+- [key decisions]
+
+## Quick Commands
+
+| Task | Command |
+|------|---------|
+| Install deps | `npm install` |
+| Run dev server | `npm run dev` |
+| Run tests | `npm test` |
+| Build | `npm run build` |
+```
+
+## Comprehensive AGENTS.md Template
+
+```markdown
+# Project Name
+
+## Overview
+
+[Detailed project description - what it does, why it exists, who it's for]
+
+## Recommended Agents
+
+### Primary
+| Agent | Use For |
+|-------|---------|
+| [framework-expert] | Main development work |
+| [language-expert] | Core language tasks |
+
+### Secondary
+| Agent | Use For |
+|-------|---------|
+| [database-expert] | Data layer tasks |
+| [testing-expert] | Test implementation |
+
+### Specialized
+| Agent | Use For |
+|-------|---------|
+| [deployment-expert] | Deployment tasks |
+| [security-expert] | Security review |
+
+## Tech Stack
+
+### Core
+- **Language:** [language with version]
+- **Framework:** [framework with version]
+- **Runtime:** [runtime]
+
+### Data
+- **Database:** [database]
+- **Cache:** [cache system]
+- **Queue:** [message queue]
+
+### Infrastructure
+- **Hosting:** [platform]
+- **CDN:** [cdn]
+- **CI/CD:** [ci system]
+
+## Project Structure
+
+\`\`\`
+project/
+├── src/
+│   ├── components/    # UI components
+│   ├── services/      # Business logic
+│   ├── utils/         # Utilities
+│   └── types/         # Type definitions
+├── tests/
+│   ├── unit/          # Unit tests
+│   ├── integration/   # Integration tests
+│   └── e2e/           # End-to-end tests
+├── docs/              # Documentation
+├── scripts/           # Build/deploy scripts
+└── config/            # Configuration files
+\`\`\`
+
+## Key Workflows
+
+### Local Development
+
+\`\`\`bash
+# Initial setup
+git clone [repo]
+cd [project]
+[package manager] install
+
+# Environment
+cp .env.example .env
+# Edit .env with local settings
+
+# Start development
+[dev command]
+\`\`\`
+
+### Testing
+
+\`\`\`bash
+# Unit tests
+[unit test command]
+
+# Integration tests
+[integration test command]
+
+# E2E tests
+[e2e test command]
+
+# Coverage
+[coverage command]
+\`\`\`
+
+### Deployment
+
+\`\`\`bash
+# Build
+[build command]
+
+# Deploy to staging
+[staging deploy]
+
+# Deploy to production
+[production deploy]
+\`\`\`
+
+## Conventions
+
+### Code Style
+
+- **Formatting:** [tool] with [config file]
+- **Linting:** [linter] with [rules]
+- **Import order:** [order]
+- **File naming:** [pattern]
+
+### Git
+
+- **Branch naming:** `[type]/[ticket]-[description]`
+- **Commit format:** `[type]: [description]`
+- **PR process:** [process]
+
+### Architecture
+
+- **State management:** [pattern]
+- **Error handling:** [pattern]
+- **API design:** [pattern]
+- **Database access:** [pattern]
+
+### Testing
+
+- **Unit test location:** `tests/unit/`
+- **Naming:** `test_[function]_[scenario]`
+- **Mocking strategy:** [strategy]
+- **Coverage target:** [percentage]
+
+## Environment Variables
+
+| Variable | Purpose | Required |
+|----------|---------|----------|
+| `DATABASE_URL` | Database connection | Yes |
+| `API_KEY` | External API key | Yes |
+| `DEBUG` | Enable debug mode | No |
+
+## Quick Commands
+
+| Task | Command |
+|------|---------|
+| Install | `[install]` |
+| Dev | `[dev]` |
+| Test | `[test]` |
+| Lint | `[lint]` |
+| Format | `[format]` |
+| Build | `[build]` |
+| Deploy | `[deploy]` |
+
+## Common Issues
+
+### Issue: [Common problem]
+**Solution:** [How to fix]
+
+### Issue: [Another problem]
+**Solution:** [How to fix]
+
+## Resources
+
+- [Documentation link]
+- [API reference]
+- [Related projects]
+```
+
+## Consolidation Template
+
+When merging multiple doc files:
+
+```markdown
+# Project Name
+
+<!-- Consolidated from: CLAUDE.md, WARP.md -->
+<!-- Generated: YYYY-MM-DD -->
+
+## Overview
+
+[Merged overview from all sources]
+
+## Recommended Agents
+
+[Combined agent recommendations]
+
+## Workflows
+
+[Merged workflows, removing duplicates]
+
+## Conventions
+
+[Combined conventions]
+
+<!-- Platform-specific notes -->
+
+### Claude-specific
+<!-- Source: CLAUDE.md -->
+[Claude-specific instructions]
+
+### Terminal-specific
+<!-- Source: WARP.md -->
+[Terminal-specific instructions]
+
+---
+*Consolidated from multiple documentation files. Originals archived in `.doc-archive/`*
+```
+
+## Generation Guidelines
+
+When creating AGENTS.md from project analysis:
+
+1. **Analyze project structure**
+   - Check package.json, pyproject.toml, Cargo.toml
+   - Identify framework from imports
+   - Find test directories
+
+2. **Identify conventions**
+   - Check for linter configs (.eslintrc, ruff.toml)
+   - Check for formatter configs (prettier, black)
+   - Look at existing code patterns
+
+3. **Extract commands**
+   - From package.json scripts
+   - From Makefile or justfile
+   - From README.md
+
+4. **Recommend agents**
+   - Based on language/framework
+   - Based on project complexity
+   - Based on common tasks
+
+5. **Keep it concise**
+   - Focus on actionable info
+   - Avoid redundancy
+   - Update when project evolves

+ 43 - 154
skills/file-search/SKILL.md

@@ -7,203 +7,92 @@ allowed-tools: "Bash"
 
 # File Search
 
-Modern file and content search using fd, ripgrep (rg), and fzf for interactive selection.
+Modern file and content search.
 
-## fd - Find Files (Better than find)
+## fd - Find Files
 
-### Basic Usage
 ```bash
-# Find by name (case-insensitive by default)
+# Find by name
 fd config                    # Files containing "config"
-fd "\.ts$"                   # TypeScript files (regex)
-fd -e py                     # Python files by extension
+fd -e py                     # Python files
 
-# Multiple extensions
-fd -e js -e ts               # JS and TS files
-fd -e md -e txt              # Markdown and text files
-```
-
-### Filtering
-```bash
 # By type
 fd -t f config               # Files only
 fd -t d src                  # Directories only
-fd -t l                      # Symlinks only
 
-# By depth
-fd -d 2 config               # Max 2 levels deep
-fd --min-depth 2 config      # At least 2 levels deep
+# Exclude
+fd -E node_modules           # Exclude directory
+fd -E "*.min.js"             # Exclude pattern
 
-# Include hidden/ignored
-fd -H config                 # Include hidden files
-fd -I config                 # Include .gitignore'd files
-fd -HI config                # Include both
+# Execute command
+fd -e py -x wc -l            # Line count per file
 ```
 
-### Exclusion
-```bash
-# Exclude patterns
-fd -E "*.min.js" -E "dist/"  # Exclude minified and dist
-fd -E node_modules           # Exclude node_modules
-fd config -E "*.bak"         # Find config, exclude backups
-```
+## rg - Search Content
 
-### Execute Commands
-```bash
-# Run command on each result
-fd -e py -x wc -l            # Line count for each Python file
-fd -e ts -x bat {}           # View each TypeScript file with bat
-fd -e json -x jq . {}        # Pretty print each JSON file
-```
-
-## ripgrep (rg) - Search Content (Better than grep)
-
-### Basic Usage
 ```bash
 # Simple search
-rg "TODO"                    # Find TODO in all files
-rg "function \w+"            # Regex pattern
+rg "TODO"                    # Find TODO
 rg -i "error"                # Case-insensitive
-rg -w "log"                  # Word boundary (not "catalog")
-```
 
-### File Filtering
-```bash
-# By type
-rg -t py "import"            # Search Python files only
-rg -t js -t ts "async"       # JS and TS files
-rg --type-list               # Show all known types
-
-# By glob
-rg -g "*.tsx" "useState"     # Search .tsx files
-rg -g "!*.test.*" "fetch"    # Exclude test files
-rg -g "src/**" "config"      # Only in src directory
-```
+# By file type
+rg -t py "import"            # Python files only
+rg -t js -t ts "async"       # JS and TS
 
-### Context and Format
-```bash
-# Show context lines
-rg -C 3 "function"           # 3 lines before and after
-rg -B 2 -A 5 "class"         # 2 before, 5 after
+# Context
+rg -C 3 "function"           # 3 lines before/after
 
-# Output format
+# Output modes
 rg -l "TODO"                 # File names only
 rg -c "TODO"                 # Count per file
-rg --json "TODO"             # JSON output
-rg -n "TODO"                 # With line numbers (default)
-```
-
-### Advanced Patterns
-```bash
-# Multiline
-rg -U "class.*\n.*constructor"   # Across lines
-
-# Fixed strings (no regex)
-rg -F "[]"                   # Literal brackets
-
-# Invert match
-rg -v "console.log"          # Lines NOT containing
-
-# Replace (preview)
-rg "oldFunc" -r "newFunc"    # Show replacements (use sd to apply)
 ```
 
 ## fzf - Interactive Selection
 
-### Basic Workflows
 ```bash
-# Find and open file
-fd | fzf                             # Select file interactively
-fd -e py | fzf                       # Select from Python files
+# Find and select
+fd | fzf
 
-# Find and edit
-nvim $(fd -e ts | fzf)               # Open selected in nvim
-code $(fd | fzf -m)                  # Open multiple in VS Code
-```
-
-### With Preview
-```bash
-# Preview with bat
+# With preview
 fd | fzf --preview 'bat --color=always {}'
 
-# Preview with rg context
-rg -l "TODO" | fzf --preview 'rg -C 3 "TODO" {}'
-```
-
-### Multi-Select
-```bash
-# Select multiple (Tab to mark, Enter to confirm)
-fd -e ts | fzf -m                    # Multi-select mode
-fd -e ts | fzf -m | xargs rm         # Delete selected
-```
-
-### Combined Workflows
-```bash
-# Fuzzy grep: search content, select file, open at line
-rg -n "pattern" | fzf --preview 'bat {1} --highlight-line {2}'
-
-# Kill process interactively
-procs | fzf | awk '{print $1}' | xargs kill
-
-# Git branch checkout
-git branch | fzf | xargs git checkout
-
-# Git log with preview
-git log --oneline | fzf --preview 'git show --color=always {1}'
+# Multi-select
+fd -e ts | fzf -m | xargs code
 ```
 
 ## Combined Patterns
 
-### Find and Search
 ```bash
-# Find Python files, search for pattern
+# Find files, search content
 fd -e py -x rg "async def" {}
 
-# Search specific directories
-rg "import" $(fd -t d src lib)
+# Search, select, open
+rg -l "pattern" | fzf --preview 'rg -C 3 "pattern" {}' | xargs vim
 ```
 
-### Find, Select, Act
-```bash
-# Interactive file deletion
-fd -t f "\.bak$" | fzf -m | xargs rm -i
-
-# Interactive config editing
-fd -g "*.config.*" | fzf --preview 'bat {}' | xargs nvim
-```
-
-### Codebase Exploration
-```bash
-# Find all entry points
-rg -l "^(export )?function main|^if __name__"
-
-# Find all TODO/FIXME with context
-rg -C 2 "TODO|FIXME|HACK|XXX"
+## Quick Reference
 
-# Find unused exports (basic)
-rg "export (const|function|class) (\w+)" -o -r '$2' | sort | uniq
-```
+| Task | Command |
+|------|---------|
+| Find TS files | `fd -e ts` |
+| Find in src | `fd -e ts src/` |
+| Search pattern | `rg "pattern"` |
+| Search in type | `rg -t py "import"` |
+| Files with match | `rg -l "pattern"` |
+| Count matches | `rg -c "pattern"` |
+| Interactive | `fd \| fzf` |
+| With preview | `fd \| fzf --preview 'bat {}'` |
 
 ## Performance Tips
 
 | Tip | Why |
 |-----|-----|
-| Both respect `.gitignore` | Automatically skip node_modules, dist, etc. |
-| Use `-t` over `-g` when possible | Type flags are faster than globs |
-| Narrow the path | `rg pattern src/` faster than `rg pattern` |
-| Use `-F` for literal strings | Avoids regex engine overhead |
-| Add `-u` for unignored only when needed | Hidden files slow things down |
+| Both respect `.gitignore` | Auto-skip node_modules, dist |
+| Use `-t` over `-g` | Type flags are faster |
+| Narrow the path | `rg pattern src/` faster |
+| Use `-F` for literals | Avoids regex overhead |
 
-## Quick Reference
+## Additional Resources
 
-| Task | Command |
-|------|---------|
-| Find TS files | `fd -e ts` |
-| Find in src only | `fd -e ts src/` |
-| Search for pattern | `rg "pattern"` |
-| Search in type | `rg -t py "import"` |
-| Files containing | `rg -l "pattern"` |
-| Count matches | `rg -c "pattern"` |
-| Interactive select | `fd \| fzf` |
-| Multi-select | `fd \| fzf -m` |
-| Preview files | `fd \| fzf --preview 'bat {}'` |
+For detailed patterns, load:
+- `./references/advanced-workflows.md` - Git integration, shell functions, power workflows

+ 314 - 0
skills/file-search/references/advanced-workflows.md

@@ -0,0 +1,314 @@
+# File Search Advanced Workflows
+
+Advanced patterns combining fd, ripgrep (rg), and fzf for powerful file operations.
+
+## fd Advanced Patterns
+
+### Execution Patterns
+
+```bash
+# Execute command on each result
+fd -e py -x wc -l {}                    # Line count per file
+fd -e ts -x prettier --write {}         # Format each file
+fd -e json -x jq '.name' {}             # Extract JSON field
+fd -e md -x bat {}                      # Preview each with bat
+
+# Parallel execution
+fd -e ts -x -j4 tsc --noEmit {}         # 4 parallel type checks
+
+# Batch mode (all files at once)
+fd -e ts -X prettier --write            # Single prettier call
+fd -e py -X wc -l                       # Single wc call
+```
+
+### Pattern Matching
+
+```bash
+# Regex patterns
+fd "^test_.*\.py$"                      # Files starting with test_
+fd ".*\.(ts|tsx)$"                      # TypeScript files
+fd "\d{4}-\d{2}-\d{2}"                  # Date in filename
+
+# Glob patterns
+fd -g "*.test.ts"                       # Glob mode
+fd -g "config.{json,yaml,toml}"         # Multiple extensions
+
+# Case sensitivity
+fd -s "README"                          # Case-sensitive
+fd -i "readme"                          # Case-insensitive (default)
+```
+
+### Time-based Filtering
+
+```bash
+# Modified within time range
+fd --changed-within 1h                  # Last hour
+fd --changed-within 1d                  # Last day
+fd --changed-before 1w                  # Older than 1 week
+
+# Combine with other filters
+fd -e py --changed-within 1d            # Python files modified today
+```
+
+### Size Filtering
+
+```bash
+# Filter by size
+fd --size +1m                           # Larger than 1MB
+fd --size -100k                         # Smaller than 100KB
+fd -e log --size +10m                   # Large log files
+
+# Find empty files
+fd --type f --size 0                    # Empty files
+fd --type d --type empty                # Empty directories
+```
+
+## ripgrep Advanced Patterns
+
+### Multiline Matching
+
+```bash
+# Match across lines
+rg -U "class.*\n.*def __init__"         # Class with __init__
+rg -U "import.*\n.*from"                # Consecutive imports
+
+# Dotall mode (. matches newline)
+rg -U "(?s)""".*?""""                   # Python docstrings
+```
+
+### Replacement Preview
+
+```bash
+# Preview replacements without applying
+rg "old_function" -r "new_function"     # Shows what would change
+rg "v1" -r "v2" -n                      # With line numbers
+
+# Apply with sd
+sd "old_function" "new_function" $(rg -l "old_function")
+```
+
+### Stats and Counts
+
+```bash
+# Statistics
+rg --stats "TODO"                       # Match stats
+rg -c "TODO"                            # Count per file
+rg -c "TODO" | sort -t: -k2 -rn         # Sort by count
+
+# File-level info
+rg -l "pattern"                         # Files with matches
+rg -L "pattern"                         # Files without matches
+rg --files-without-match "pattern"      # Explicit no-match
+```
+
+### Context Control
+
+```bash
+# Show context
+rg -C 3 "error"                         # 3 lines before/after
+rg -B 5 "def main"                      # 5 lines before
+rg -A 10 "BEGIN"                        # 10 lines after
+
+# Context separator
+rg -C 2 --context-separator="---" "fn"  # Custom separator
+```
+
+## fzf Power Workflows
+
+### Preview Commands
+
+```bash
+# File preview with bat
+fd | fzf --preview 'bat --color=always --style=numbers --line-range :500 {}'
+
+# Directory preview with eza
+fd -t d | fzf --preview 'eza --tree --level=2 --color=always {}'
+
+# Git status preview
+git status -s | fzf --preview 'git diff --color=always {2}'
+
+# Search result preview
+rg -l "pattern" | fzf --preview 'rg -C 3 --color=always "pattern" {}'
+```
+
+### Key Bindings
+
+```bash
+# Select and action
+fd | fzf --bind 'enter:become(vim {})'
+fd | fzf --bind 'ctrl-o:execute(code {})'
+fd | fzf --bind 'ctrl-y:execute-silent(pbcopy < {})'
+
+# Multiple bindings
+fd | fzf \
+  --bind 'enter:become(vim {})' \
+  --bind 'ctrl-v:execute(code {})' \
+  --bind 'ctrl-p:toggle-preview'
+```
+
+### Multi-select Operations
+
+```bash
+# Select multiple files
+fd | fzf -m | xargs rm -i               # Delete selected
+fd -e ts | fzf -m | xargs code          # Open selected in VS Code
+
+# With confirmation
+fd -t f | fzf -m --header "Select files to delete" | \
+  xargs -p rm
+
+# Process each selection
+fd -e py | fzf -m | while read f; do
+  echo "Processing: $f"
+  python "$f" --check
+done
+```
+
+## Combined Workflows
+
+### Code Investigation
+
+```bash
+# Find function definition
+rg -n "def $FUNC" | fzf --preview 'bat {1} -H {2}'
+
+# Find and open at line
+rg -n "pattern" | fzf | awk -F: '{print "+" $2, $1}' | xargs nvim
+
+# Interactive grep with live reload
+fd -e py | fzf --ansi \
+  --preview 'rg --color=always "pattern" {} || cat {}' \
+  --bind 'change:reload(rg -l {} src/)'
+```
+
+### Batch Operations
+
+```bash
+# Rename files matching pattern
+fd "old" | while read f; do
+  new="${f//old/new}"
+  mv "$f" "$new"
+done
+
+# Find and convert
+fd -e csv -x csvtojson {} > {.}.json
+
+# Find, filter, act
+fd -e ts | rg -l "deprecated" | fzf -m | xargs rm
+```
+
+### Git Integration
+
+```bash
+# Changed files
+git diff --name-only | fzf --preview 'git diff --color=always {}'
+
+# Stage files interactively
+git status -s | fzf -m | awk '{print $2}' | xargs git add
+
+# Checkout branch
+git branch | fzf | xargs git checkout
+
+# Cherry-pick commits
+git log --oneline | fzf | awk '{print $1}' | xargs git cherry-pick
+
+# Interactive rebase
+git log --oneline | fzf -m | tail -1 | awk '{print $1}' | xargs git rebase -i
+```
+
+### Project Analysis
+
+```bash
+# Find TODO/FIXME with stats
+rg -c "TODO|FIXME" | sort -t: -k2 -rn | head -10
+
+# Large files in project
+fd -t f -x du -b {} | sort -rn | head -20 | \
+  awk '{printf "%.2f MB %s\n", $1/1048576, $2}'
+
+# Files by extension
+fd -t f | sed 's/.*\.//' | sort | uniq -c | sort -rn
+
+# Dead code detection (imports not used)
+rg "^import (\w+)" -o -r '$1' | sort -u > imports.txt
+for imp in $(cat imports.txt); do
+  count=$(rg "\b$imp\b" | wc -l)
+  if [ "$count" -lt 2 ]; then
+    echo "Possibly unused: $imp"
+  fi
+done
+```
+
+## Shell Integration
+
+### Bash/Zsh Functions
+
+```bash
+# Interactive cd with preview
+fcd() {
+  local dir
+  dir=$(fd -t d | fzf --preview 'eza --tree --level=2 {}') && cd "$dir"
+}
+
+# Find and edit
+fe() {
+  local file
+  file=$(fd -t f | fzf --preview 'bat --color=always {}') && ${EDITOR:-vim} "$file"
+}
+
+# Search and edit at line
+fge() {
+  local result
+  result=$(rg -n "" | fzf --preview 'bat {1} -H {2}')
+  if [[ -n "$result" ]]; then
+    local file=$(echo "$result" | cut -d: -f1)
+    local line=$(echo "$result" | cut -d: -f2)
+    ${EDITOR:-vim} "+$line" "$file"
+  fi
+}
+
+# Git add with preview
+fga() {
+  git status -s | fzf -m --preview 'git diff --color=always {2}' | \
+    awk '{print $2}' | xargs git add
+}
+```
+
+### Environment Variables
+
+```bash
+# fzf defaults
+export FZF_DEFAULT_COMMAND='fd --type f --hidden --follow --exclude .git'
+export FZF_DEFAULT_OPTS='
+  --height 40% --layout=reverse --border
+  --preview-window=right:60%
+  --bind ctrl-/:toggle-preview
+'
+
+# Ctrl+T for file finder
+export FZF_CTRL_T_COMMAND='fd --type f'
+export FZF_CTRL_T_OPTS='--preview "bat --color=always {}"'
+
+# Alt+C for directory finder
+export FZF_ALT_C_COMMAND='fd --type d'
+export FZF_ALT_C_OPTS='--preview "eza --tree --level=2 {}"'
+```
+
+## Performance Optimization
+
+| Technique | Example | Speedup |
+|-----------|---------|---------|
+| Narrow path | `rg pattern src/` | 2-10x |
+| Use types | `rg -t py pattern` | 1.5-3x |
+| Fixed strings | `rg -F "[literal]"` | 1.2-2x |
+| Limit depth | `fd -d 3 pattern` | Variable |
+| Ignore more | `fd -E "*.log" -E "tmp/"` | Variable |
+| Parallel | `fd -x -j8 command` | 2-8x |
+
+## Tips
+
+1. **Use `.ignore` files** - Create project-specific ignore rules
+2. **Combine tools** - fd for finding, rg for searching, fzf for selecting
+3. **Preview everything** - Use `--preview` to verify before acting
+4. **Bind common actions** - Set up fzf key bindings for frequent operations
+5. **Shell functions** - Create aliases for common workflows

+ 31 - 165
skills/find-replace/SKILL.md

@@ -7,11 +7,10 @@ allowed-tools: "Bash"
 
 # Find Replace
 
-Modern find-and-replace using sd (simpler than sed) and batch replacement patterns.
+Modern find-and-replace using sd.
 
 ## sd Basics
 
-### Simple Replacement
 ```bash
 # Replace in file (in-place)
 sd 'oldText' 'newText' file.txt
@@ -19,206 +18,73 @@ sd 'oldText' 'newText' file.txt
 # Replace in multiple files
 sd 'oldText' 'newText' *.js
 
-# Preview without changing (pipe instead of file)
+# Preview without changing (pipe)
 cat file.txt | sd 'old' 'new'
 ```
 
-### sd vs sed Comparison
+## sd vs sed
 
-| sed | sd | Notes |
-|-----|-----|-------|
-| `sed 's/old/new/g'` | `sd 'old' 'new'` | Global by default |
-| `sed -i 's/old/new/g'` | `sd 'old' 'new' file` | In-place by default |
-| `sed 's/\./dot/g'` | `sd '\.' 'dot'` | Same escaping |
-| `sed 's#path/to#new/path#g'` | `sd 'path/to' 'new/path'` | No delimiter issues |
-
-## Common Patterns
+| sed | sd |
+|-----|-----|
+| `sed 's/old/new/g'` | `sd 'old' 'new'` |
+| `sed -i 's/old/new/g'` | `sd 'old' 'new' file` |
+| `sed 's#path/to#new/path#g'` | `sd 'path/to' 'new/path'` |
 
-### Variable Rename
-```bash
-# Rename variable across files
-sd 'oldVarName' 'newVarName' src/**/*.ts
+**Key difference:** sd is global by default, no delimiter issues.
 
-# Preview first with rg
-rg 'oldVarName' src/
-# Then apply
-sd 'oldVarName' 'newVarName' $(rg -l 'oldVarName' src/)
-```
+## Common Patterns
 
-### Function Rename
 ```bash
-# Rename function (all usages)
-sd 'getUserData' 'fetchUserProfile' src/**/*.ts
+# Variable/function rename
+sd 'oldName' 'newName' src/**/*.ts
 
-# More precise with word boundaries
-sd '\bgetUserData\b' 'fetchUserProfile' src/**/*.ts
-```
+# Word boundaries (avoid partial matches)
+sd '\boldName\b' 'newName' src/**/*.ts
 
-### Import Path Update
-```bash
-# Update import paths
+# Import path update
 sd "from '../utils'" "from '@/utils'" src/**/*.ts
-sd "require\('./config'\)" "require('@/config')" src/**/*.js
-```
-
-### String Quotes
-```bash
-# Single to double quotes
-sd "'" '"' file.json
-
-# Template literals
-sd '"\$\{(\w+)\}"' '`${$1}`' src/**/*.ts
-```
-
-## Regex Patterns
-
-### Capture Groups
-```bash
-# Reorder parts
-sd '(\w+)@(\w+)\.com' '$2/$1' emails.txt
-# john@example.com → example/john
 
-# Wrap in function
+# Capture groups
 sd 'console\.log\((.*)\)' 'logger.info($1)' src/**/*.js
 ```
 
-### Optional Matching
-```bash
-# Handle optional whitespace
-sd 'function\s*\(' 'const fn = (' src/**/*.js
-```
-
-### Multiline (with -s flag)
-```bash
-# Replace across lines
-sd -s 'start\n.*\nend' 'replacement' file.txt
-```
-
-## Batch Workflows
+## Safe Batch Workflow
 
-### Find Then Replace
 ```bash
-# 1. Find files with pattern
+# 1. List affected files
 rg -l 'oldPattern' src/
 
 # 2. Preview replacements
 rg 'oldPattern' -r 'newPattern' src/
 
-# 3. Apply to found files
+# 3. Apply
 sd 'oldPattern' 'newPattern' $(rg -l 'oldPattern' src/)
-```
-
-### With fd
-```bash
-# Replace in specific file types
-fd -e ts -x sd 'old' 'new' {}
-
-# Replace in files matching name pattern
-fd 'config' -e json -x sd '"dev"' '"prod"' {}
-```
-
-### Dry Run Pattern
-```bash
-# Safe workflow: preview → verify → apply
-
-# Step 1: List affected files
-rg -l 'oldText' src/
-
-# Step 2: Show what will change
-rg 'oldText' -r 'newText' src/
 
-# Step 3: Apply (only after verification)
-sd 'oldText' 'newText' $(rg -l 'oldText' src/)
-
-# Step 4: Verify
-rg 'oldText' src/  # Should return nothing
-git diff           # Review changes
+# 4. Verify
+rg 'oldPattern' src/  # Should return nothing
+git diff              # Review changes
 ```
 
 ## Special Characters
 
-### Escaping
-```bash
-# Literal dot
-sd '\.' ',' file.txt
-
-# Literal brackets
-sd '\[' '(' file.txt
-
-# Literal dollar sign
-sd '\$' '€' file.txt
-
-# Literal backslash
-sd '\\' '/' paths.txt
-```
-
-### Common Escapes
 | Character | Escape |
 |-----------|--------|
 | `.` | `\.` |
 | `*` | `\*` |
-| `?` | `\?` |
 | `[` `]` | `\[` `\]` |
-| `(` `)` | `\(` `\)` |
-| `{` `}` | `\{` `\}` |
 | `$` | `\$` |
-| `^` | `\^` |
 | `\` | `\\` |
 
-## Real-World Examples
-
-### Update Package Version
-```bash
-sd '"version": "\d+\.\d+\.\d+"' '"version": "2.0.0"' package.json
-```
-
-### Fix File Extensions in Imports
-```bash
-sd "from '(\./[^']+)'" "from '\$1.js'" src/**/*.ts
-```
-
-### Convert CSS Class Names
-```bash
-# kebab-case to camelCase (simple cases)
-sd 'class="(\w+)-(\w+)"' 'className="$1$2"' src/**/*.jsx
-```
-
-### Update API Endpoints
-```bash
-sd '/api/v1/' '/api/v2/' src/**/*.ts
-sd 'api\.example\.com' 'api.newdomain.com' src/**/*.ts
-```
-
-### Remove Console Logs
-```bash
-# Remove entire console.log statements
-sd 'console\.log\([^)]*\);?\n?' '' src/**/*.ts
-```
-
-### Add Prefix to IDs
-```bash
-sd 'id="(\w+)"' 'id="prefix-$1"' src/**/*.html
-```
-
 ## Tips
 
-| Tip | Why |
-|-----|-----|
-| Always preview with `rg -r` first | Avoid accidental mass changes |
-| Use `git diff` after | Verify changes before commit |
-| Prefer specific patterns | `\bword\b` over `word` to avoid partial matches |
-| Quote patterns | Avoid shell interpretation |
-| Use fd to target files | More precise than `**/*.ext` |
+| Tip | Reason |
+|-----|--------|
+| Always preview with `rg -r` first | Avoid mistakes |
+| Use git before bulk changes | Easy rollback |
+| Use `\b` for word boundaries | Avoid partial matches |
+| Quote patterns | Prevent shell interpretation |
 
-## Installation
+## Additional Resources
 
-```bash
-# Cargo (Rust)
-cargo install sd
-
-# Homebrew (macOS)
-brew install sd
-
-# Windows (scoop)
-scoop install sd
-```
+For detailed patterns, load:
+- `./references/advanced-patterns.md` - Regex, batch workflows, real-world examples

+ 257 - 0
skills/find-replace/references/advanced-patterns.md

@@ -0,0 +1,257 @@
+# sd Advanced Patterns
+
+Advanced find-and-replace patterns using sd (simpler than sed).
+
+## Regex Patterns
+
+### Capture Groups
+
+```bash
+# Reorder parts
+sd '(\w+)@(\w+)\.com' '$2/$1' emails.txt
+# john@example.com → example/john
+
+# Wrap in function
+sd 'console\.log\((.*)\)' 'logger.info($1)' src/**/*.js
+# console.log(msg) → logger.info(msg)
+
+# Extract and transform
+sd 'class (\w+)' 'export class $1' src/**/*.ts
+```
+
+### Word Boundaries
+
+```bash
+# Match whole words only
+sd '\bfoo\b' 'bar' file.txt
+# "foo" matches, "foobar" doesn't
+
+# Function rename without affecting variables
+sd '\bgetUser\b' 'fetchUser' src/**/*.ts
+```
+
+### Optional and Alternation
+
+```bash
+# Optional whitespace
+sd 'function\s*\(' 'const fn = (' src/**/*.js
+
+# Match alternatives
+sd '(let|var)\s+' 'const ' src/**/*.js
+```
+
+### Multiline Patterns
+
+```bash
+# Match across lines (-s flag)
+sd -s 'start\n.*\nend' 'replacement' file.txt
+
+# Remove multiline blocks
+sd -s '\/\*\*[\s\S]*?\*\/' '' src/**/*.ts
+```
+
+## Real-World Patterns
+
+### Import Transformations
+
+```bash
+# CommonJS to ES modules
+sd "const (\w+) = require\('([^']+)'\)" "import $1 from '$2'" src/**/*.js
+
+# Relative to absolute imports
+sd "from '\.\./\.\./utils'" "from '@/utils'" src/**/*.ts
+
+# Named imports reorganization
+sd "import \{ (\w+), (\w+) \}" "import { $2, $1 }" src/**/*.ts
+```
+
+### API Endpoint Updates
+
+```bash
+# Version bump
+sd '/api/v1/' '/api/v2/' src/**/*.ts
+
+# Domain migration
+sd 'api\.old\.com' 'api.new.com' src/**/*.ts
+
+# Path restructuring
+sd '/users/(\d+)/posts' '/posts?user_id=$1' src/**/*.ts
+```
+
+### Configuration Updates
+
+```bash
+# Environment variable rename
+sd 'DATABASE_URL' 'DB_CONNECTION_STRING' .env* src/**/*.ts
+
+# Port number change
+sd 'port:\s*3000' 'port: 8080' **/*.yaml **/*.json
+
+# Version strings
+sd '"version":\s*"\d+\.\d+\.\d+"' '"version": "2.0.0"' package.json
+```
+
+### Code Modernization
+
+```bash
+# Async/await from promises
+sd '\.then\(\((\w+)\)\s*=>\s*\{' 'const $1 = await ' src/**/*.ts
+
+# Template literals
+sd '"\s*\+\s*(\w+)\s*\+\s*"' '${$1}' src/**/*.ts
+
+# Optional chaining
+sd '(\w+)\s*&&\s*\1\.(\w+)' '$1?.$2' src/**/*.ts
+```
+
+### React/JSX Patterns
+
+```bash
+# className to class (or vice versa)
+sd 'className="' 'class="' src/**/*.jsx
+sd 'class="' 'className="' src/**/*.jsx
+
+# Event handler rename
+sd 'onClick=\{' 'onPress={' src/**/*.tsx
+
+# Hook migration
+sd 'componentDidMount\(\)' 'useEffect(() => {' src/**/*.tsx
+```
+
+### Remove Code
+
+```bash
+# Console logs
+sd 'console\.log\([^)]*\);?\s*\n?' '' src/**/*.ts
+
+# Debug statements
+sd '// DEBUG:.*\n' '' src/**/*.ts
+
+# Commented code blocks
+sd '//\s*[A-Za-z].*\n' '' src/**/*.ts  # Single line comments with code
+
+# TODO comments
+sd '// TODO:.*\n' '' src/**/*.ts
+```
+
+## Batch Workflows
+
+### Safe Preview Pattern
+
+```bash
+# 1. List affected files
+rg -l 'oldPattern' src/
+
+# 2. Preview replacements (rg with -r)
+rg 'oldPattern' -r 'newPattern' src/
+
+# 3. Apply to found files
+sd 'oldPattern' 'newPattern' $(rg -l 'oldPattern' src/)
+
+# 4. Verify
+rg 'oldPattern' src/  # Should return nothing
+
+# 5. Review changes
+git diff
+```
+
+### With fd for File Selection
+
+```bash
+# TypeScript files only
+fd -e ts -x sd 'old' 'new' {}
+
+# Specific directories
+fd -e js . src/ lib/ -x sd 'old' 'new' {}
+
+# Exclude patterns
+fd -e ts -E "*.test.ts" -E "*.spec.ts" -x sd 'old' 'new' {}
+
+# By filename pattern
+fd 'config' -e json -x sd '"dev"' '"prod"' {}
+```
+
+### Multiple Replacements
+
+```bash
+# Chain with &&
+sd 'pattern1' 'replacement1' file.txt && \
+sd 'pattern2' 'replacement2' file.txt && \
+sd 'pattern3' 'replacement3' file.txt
+
+# Or use a script
+#!/bin/bash
+files=$(rg -l 'oldApi' src/)
+for file in $files; do
+    sd 'oldApi\.get' 'newApi.fetch' "$file"
+    sd 'oldApi\.post' 'newApi.send' "$file"
+    sd 'oldApi\.delete' 'newApi.remove' "$file"
+done
+```
+
+## Special Characters
+
+### Escaping Reference
+
+| Character | Escape | Example |
+|-----------|--------|---------|
+| `.` | `\.` | `sd '1\.0' '2.0'` |
+| `*` | `\*` | `sd '\*important\*' '**important**'` |
+| `?` | `\?` | `sd 'what\?' 'what!'` |
+| `[` `]` | `\[` `\]` | `sd '\[x\]' '[✓]'` |
+| `(` `)` | `\(` `\)` | `sd 'func\(\)' 'func(arg)'` |
+| `{` `}` | `\{` `\}` | `sd '\{0,1\}' '?'` |
+| `$` | `\$` | `sd '\$100' '€100'` |
+| `^` | `\^` | `sd '\^note' 'NOTE'` |
+| `\` | `\\` | `sd '\\n' '\n'` |
+| `\|` | `\|` | `sd 'a\|b' 'a or b'` |
+
+### Literal Mode
+
+```bash
+# When you have many special chars, consider preprocessing
+# or use fixed-string replacement with rg first
+
+# For checking matches
+rg -F '[TODO]' src/
+
+# sd doesn't have -F, so escape carefully
+sd '\[TODO\]' '[DONE]' src/**/*.md
+```
+
+## Platform-Specific
+
+### With Git
+
+```bash
+# Only changed files
+sd 'old' 'new' $(git diff --name-only)
+
+# Staged files only
+sd 'old' 'new' $(git diff --cached --name-only)
+
+# Files changed in last commit
+sd 'old' 'new' $(git diff-tree --no-commit-id --name-only -r HEAD)
+```
+
+### In Docker
+
+```bash
+# Inside container
+docker exec -it container sd 'old' 'new' /app/config.json
+
+# Or with volume mount
+docker run -v $(pwd):/data alpine sh -c "apk add sd && sd 'old' 'new' /data/file.txt"
+```
+
+## Tips and Best Practices
+
+| Tip | Reason |
+|-----|--------|
+| Always preview with `rg -r` first | Catch mistakes before applying |
+| Use git before bulk changes | Easy rollback with `git checkout` |
+| Quote patterns | Prevent shell interpretation |
+| Use `\b` for word boundaries | Avoid partial matches |
+| Start specific, then broaden | Easier to control scope |
+| Test on single file first | Verify pattern works |
+| Use `fd -x` for file selection | More precise than globs |

+ 39 - 268
skills/git-workflow/SKILL.md

@@ -1,13 +1,12 @@
 ---
 name: git-workflow
-description: "Enhanced git operations using lazygit, gh (GitHub CLI), and delta. Triggers on stage changes, create PR, review PR, check issues, git diff, commit interactively, GitHub operations, rebase, stash, bisect."
+description: "Enhanced git operations using lazygit, gh (GitHub CLI), and delta. Triggers on: stage changes, create PR, review PR, check issues, git diff, commit interactively, GitHub operations, rebase, stash, bisect."
 compatibility: "Requires git, gh (GitHub CLI), lazygit, and delta. Network access needed for GitHub operations."
 allowed-tools: "Bash"
 ---
 
 # Git Workflow
 
-## Purpose
 Streamline git operations with visual tools and GitHub CLI integration.
 
 ## Tools
@@ -18,308 +17,74 @@ Streamline git operations with visual tools and GitHub CLI integration.
 | gh | `gh pr create` | GitHub CLI operations |
 | delta | `git diff \| delta` | Beautiful diff viewing |
 
-## Usage Examples
-
-### Interactive Git with lazygit
+## lazygit Essentials
 
 ```bash
-# Open git TUI
+# Open interactive TUI
 lazygit
 
-# Key bindings in lazygit:
+# Key bindings:
 # Space - stage/unstage file
-# c - commit
-# p - push
-# P - pull
-# b - branch operations
-# r - rebase menu
-# s - stash menu
-# ? - help
+# c     - commit
+# p     - push
+# P     - pull
+# b     - branch operations
+# r     - rebase menu
+# s     - stash menu
+# ?     - help
 ```
 
-### GitHub CLI with gh
+## GitHub CLI (gh) Essentials
 
 ```bash
-# Create pull request
+# Pull Requests
 gh pr create --title "Feature: Add X" --body "Description"
-
-# Create PR with web editor
-gh pr create --web
-
-# List open PRs
-gh pr list
-
-# View PR details
-gh pr view 123
-
-# Check out PR locally
-gh pr checkout 123
-
-# Merge PR
-gh pr merge 123 --squash --delete-branch
-
-# Create issue
-gh issue create --title "Bug: X" --body "Steps to reproduce"
-
-# List issues
+gh pr create --web           # Open in browser
+gh pr list                   # List open PRs
+gh pr view 123               # View PR details
+gh pr checkout 123           # Check out PR locally
+gh pr merge 123 --squash     # Squash and merge
+
+# Issues
+gh issue create --title "Bug: X"
 gh issue list --label bug
 
-# View repo in browser
-gh repo view --web
+# Repository
+gh repo view --web           # Open in browser
 
-# Run workflow
+# Actions
 gh workflow run deploy.yml
-
-# View workflow runs
 gh run list --workflow=ci.yml
 ```
 
-### Beautiful Diffs with delta
+## Delta (Beautiful Diffs)
 
 ```bash
-# View diff with delta
+# View diff with syntax highlighting
 git diff | delta
 
 # Side-by-side view
 git diff | delta --side-by-side
 
-# Configure git to use delta by default
+# Configure as default pager
 git config --global core.pager delta
 ```
 
-## Interactive Rebase
-
-Clean up commit history before merging.
-
-```bash
-# Rebase last N commits
-git rebase -i HEAD~5
-
-# Rebase onto main
-git rebase -i main
-
-# Commands in interactive rebase:
-# pick   - use commit as-is
-# reword - edit commit message
-# edit   - stop to amend commit
-# squash - meld into previous commit (keep message)
-# fixup  - meld into previous (discard message)
-# drop   - remove commit
-```
-
-### Common Rebase Workflows
-
-```bash
-# Squash all feature commits into one
-git rebase -i main
-# Change all but first 'pick' to 'squash'
-
-# Reorder commits
-git rebase -i HEAD~3
-# Move lines to change order
-
-# Continue after resolving conflicts
-git rebase --continue
-
-# Abort if things go wrong
-git rebase --abort
-```
-
-## Stash Operations
-
-Save work temporarily without committing.
-
-```bash
-# Save current changes
-git stash
-
-# Save with description
-git stash push -m "WIP: feature X"
-
-# Stash including untracked files
-git stash -u
-
-# List all stashes
-git stash list
-
-# Apply most recent stash (keep in stash list)
-git stash apply
-
-# Apply and remove from list
-git stash pop
-
-# Apply specific stash
-git stash apply stash@{2}
-
-# Show stash contents
-git stash show -p stash@{0}
-
-# Drop specific stash
-git stash drop stash@{1}
-
-# Clear all stashes
-git stash clear
-```
-
-### Stash Workflow Pattern
-
-```bash
-# Mid-feature, need to switch branches
-git stash push -m "WIP: auth flow"
-git checkout hotfix-branch
-# ... fix bug ...
-git checkout feature-branch
-git stash pop
-```
-
-## Git Bisect
-
-Find the commit that introduced a bug using binary search.
-
-```bash
-# Start bisect
-git bisect start
-
-# Mark current commit as bad
-git bisect bad
-
-# Mark known good commit
-git bisect good v1.0.0
-
-# Git checks out middle commit, test it, then:
-git bisect good  # if this commit is OK
-git bisect bad   # if this commit has the bug
-
-# Repeat until git finds the culprit
-# "abc123 is the first bad commit"
-
-# End bisect session
-git bisect reset
-```
-
-### Automated Bisect
-
-```bash
-# Run a test script automatically
-git bisect start HEAD v1.0.0
-git bisect run npm test
-# Git will find first failing commit automatically
-```
-
-## Cherry-Pick
-
-Apply specific commits to current branch.
-
-```bash
-# Apply single commit
-git cherry-pick abc123
-
-# Apply multiple commits
-git cherry-pick abc123 def456
-
-# Apply range of commits
-git cherry-pick abc123..xyz789
-
-# Cherry-pick without committing (stage only)
-git cherry-pick -n abc123
-
-# Continue after resolving conflicts
-git cherry-pick --continue
-
-# Abort cherry-pick
-git cherry-pick --abort
-```
-
-## Worktrees
-
-Work on multiple branches simultaneously without stashing.
-
-```bash
-# Create worktree for a branch
-git worktree add ../project-hotfix hotfix-branch
-
-# Create worktree with new branch
-git worktree add ../project-feature -b new-feature
-
-# List worktrees
-git worktree list
-
-# Remove worktree
-git worktree remove ../project-hotfix
-
-# Prune stale worktree info
-git worktree prune
-```
-
-### Worktree Workflow
-
-```bash
-# Main repo at ~/project
-# Need to work on hotfix while keeping feature work
-git worktree add ~/project-hotfix hotfix-branch
-cd ~/project-hotfix
-# ... make fixes, commit, push ...
-cd ~/project
-git worktree remove ~/project-hotfix
-```
-
-## Reflog (Recovery)
-
-Find and recover "lost" commits.
-
-```bash
-# Show reflog (all HEAD movements)
-git reflog
-
-# Show reflog for specific branch
-git reflog show feature-branch
-
-# Recover deleted branch
-git reflog
-# Find commit hash before deletion
-git checkout -b recovered-branch abc123
-
-# Undo a rebase
-git reflog
-# Find commit before rebase started
-git reset --hard HEAD@{5}
-
-# Recover after hard reset
-git reflog
-git reset --hard HEAD@{1}
-```
-
-## Conflict Resolution
-
-```bash
-# See which files have conflicts
-git status
-
-# Use merge tool
-git mergetool
-
-# Accept all changes from one side
-git checkout --ours file.txt    # Keep current branch
-git checkout --theirs file.txt  # Keep incoming branch
-
-# After resolving
-git add file.txt
-git rebase --continue  # or git merge --continue
-```
-
 ## Quick Reference
 
 | Task | Command |
 |------|---------|
+| Interactive git | `lazygit` |
+| Create PR | `gh pr create` |
+| Merge PR | `gh pr merge --squash` |
+| Beautiful diff | `git diff \| delta` |
 | Interactive rebase | `git rebase -i HEAD~N` |
 | Stash changes | `git stash push -m "msg"` |
 | Apply stash | `git stash pop` |
 | Find bug commit | `git bisect start` |
-| Cherry-pick commit | `git cherry-pick <hash>` |
+| Cherry-pick | `git cherry-pick <hash>` |
 | Parallel worktree | `git worktree add <path> <branch>` |
 | Recover commits | `git reflog` |
-| Create PR | `gh pr create` |
-| Merge PR | `gh pr merge --squash` |
 
 ## When to Use
 
@@ -327,9 +92,15 @@ git rebase --continue  # or git merge --continue
 - Creating pull requests from terminal
 - Reviewing PRs and issues
 - Visual diff viewing
-- Branch management
 - Cleaning up commit history (rebase)
 - Temporary work saving (stash)
 - Bug hunting (bisect)
 - Parallel feature work (worktrees)
 - Recovering lost work (reflog)
+
+## Additional Resources
+
+For detailed patterns, load:
+- `./references/rebase-patterns.md` - Interactive rebase workflows
+- `./references/stash-patterns.md` - Stash operations and workflows
+- `./references/advanced-git.md` - Bisect, cherry-pick, worktrees, reflog, conflicts

+ 261 - 0
skills/git-workflow/references/advanced-git.md

@@ -0,0 +1,261 @@
+# Advanced Git Operations
+
+Git bisect, cherry-pick, worktrees, reflog, and conflict resolution.
+
+## Git Bisect
+
+Find the commit that introduced a bug using binary search.
+
+### Basic Bisect
+
+```bash
+# Start bisect
+git bisect start
+
+# Mark current commit as bad
+git bisect bad
+
+# Mark known good commit
+git bisect good v1.0.0
+
+# Git checks out middle commit, test it, then:
+git bisect good  # if this commit is OK
+git bisect bad   # if this commit has the bug
+
+# Repeat until git finds the culprit
+# "abc123 is the first bad commit"
+
+# End bisect session
+git bisect reset
+```
+
+### Automated Bisect
+
+```bash
+# Run a test script automatically
+git bisect start HEAD v1.0.0
+git bisect run npm test
+# Git will find first failing commit automatically
+
+# With custom script
+git bisect run ./test-for-bug.sh
+# Script should exit 0 (good) or 1 (bad)
+```
+
+### Bisect Commands
+
+```bash
+# Skip current commit (can't test it)
+git bisect skip
+
+# View bisect log
+git bisect log
+
+# Replay a bisect session
+git bisect replay bisect.log
+
+# Visualize remaining commits
+git bisect visualize
+```
+
+---
+
+## Cherry-Pick
+
+Apply specific commits to current branch.
+
+```bash
+# Apply single commit
+git cherry-pick abc123
+
+# Apply multiple commits
+git cherry-pick abc123 def456
+
+# Apply range of commits (exclusive start)
+git cherry-pick abc123..xyz789
+
+# Apply range (inclusive)
+git cherry-pick abc123^..xyz789
+```
+
+### Cherry-Pick Options
+
+```bash
+# Stage only, don't commit
+git cherry-pick -n abc123
+
+# Edit commit message
+git cherry-pick -e abc123
+
+# Record original commit in message
+git cherry-pick -x abc123
+# Adds: "(cherry picked from commit abc123)"
+
+# Preserve original author
+git cherry-pick --signoff abc123
+```
+
+### Handling Conflicts
+
+```bash
+# Continue after resolving conflicts
+git cherry-pick --continue
+
+# Abort cherry-pick
+git cherry-pick --abort
+
+# Skip current commit
+git cherry-pick --skip
+```
+
+---
+
+## Worktrees
+
+Work on multiple branches simultaneously without stashing.
+
+```bash
+# Create worktree for existing branch
+git worktree add ../project-hotfix hotfix-branch
+
+# Create worktree with new branch
+git worktree add ../project-feature -b new-feature
+
+# Create worktree from specific commit
+git worktree add ../project-v1 v1.0.0
+
+# List worktrees
+git worktree list
+
+# Remove worktree
+git worktree remove ../project-hotfix
+
+# Prune stale worktree info
+git worktree prune
+```
+
+### Worktree Workflow
+
+```bash
+# Main repo at ~/project
+# Need to work on hotfix while keeping feature work
+cd ~/project
+git worktree add ~/project-hotfix hotfix-branch
+
+# Work in hotfix
+cd ~/project-hotfix
+# ... make fixes, commit, push ...
+
+# Back to main work
+cd ~/project
+git worktree remove ~/project-hotfix
+```
+
+---
+
+## Reflog (Recovery)
+
+Find and recover "lost" commits.
+
+```bash
+# Show reflog (all HEAD movements)
+git reflog
+
+# Show reflog for specific branch
+git reflog show feature-branch
+
+# Show reflog with dates
+git reflog --date=relative
+```
+
+### Recovery Scenarios
+
+#### Recover Deleted Branch
+
+```bash
+git reflog
+# Find commit hash before deletion
+git checkout -b recovered-branch abc123
+```
+
+#### Undo a Rebase
+
+```bash
+git reflog
+# Find commit before rebase started (look for "rebase: start")
+git reset --hard HEAD@{5}
+```
+
+#### Recover After Hard Reset
+
+```bash
+git reflog
+# Find the commit you want
+git reset --hard HEAD@{1}
+```
+
+#### Find Lost Commits
+
+```bash
+# Show all dangling commits
+git fsck --lost-found
+
+# Check reflog for specific date
+git reflog --date=local | grep "Dec 15"
+```
+
+---
+
+## Conflict Resolution
+
+```bash
+# See which files have conflicts
+git status
+
+# View conflict markers in file
+cat file.txt
+# <<<<<<< HEAD
+# your changes
+# =======
+# their changes
+# >>>>>>> branch-name
+```
+
+### Resolution Strategies
+
+```bash
+# Use merge tool
+git mergetool
+
+# Accept all changes from one side
+git checkout --ours file.txt    # Keep current branch
+git checkout --theirs file.txt  # Keep incoming branch
+
+# Accept both (for non-overlapping changes)
+git checkout --merge file.txt
+```
+
+### After Resolving
+
+```bash
+# Stage resolved file
+git add file.txt
+
+# Continue operation
+git rebase --continue   # During rebase
+git merge --continue    # During merge
+git cherry-pick --continue  # During cherry-pick
+```
+
+### Conflict Prevention
+
+```bash
+# Before merging, check for conflicts
+git merge --no-commit --no-ff feature-branch
+git diff --cached  # Review what would be merged
+git merge --abort  # If you don't want to proceed
+
+# Rebase frequently to avoid big conflicts
+git fetch origin
+git rebase origin/main
+```

+ 134 - 0
skills/git-workflow/references/rebase-patterns.md

@@ -0,0 +1,134 @@
+# Interactive Rebase Patterns
+
+Clean up commit history before merging.
+
+## Basic Rebase
+
+```bash
+# Rebase last N commits
+git rebase -i HEAD~5
+
+# Rebase onto main
+git rebase -i main
+
+# Commands in interactive rebase:
+# pick   - use commit as-is
+# reword - edit commit message
+# edit   - stop to amend commit
+# squash - meld into previous commit (keep message)
+# fixup  - meld into previous (discard message)
+# drop   - remove commit
+```
+
+## Common Rebase Workflows
+
+### Squash Feature Commits
+
+```bash
+# Squash all feature commits into one
+git rebase -i main
+# Change all but first 'pick' to 'squash'
+
+# Example edit:
+# pick abc123 Add feature base
+# squash def456 Fix typo
+# squash ghi789 Add tests
+# squash jkl012 Polish UI
+```
+
+### Reorder Commits
+
+```bash
+git rebase -i HEAD~3
+# Move lines to change order
+
+# Before:
+# pick abc123 Add tests
+# pick def456 Add feature
+# pick ghi789 Fix bug
+
+# After (reordered):
+# pick def456 Add feature
+# pick ghi789 Fix bug
+# pick abc123 Add tests
+```
+
+### Edit a Commit Mid-History
+
+```bash
+git rebase -i HEAD~5
+# Change 'pick' to 'edit' for target commit
+
+# Git stops at that commit
+# Make changes
+git add .
+git commit --amend
+git rebase --continue
+```
+
+### Split a Commit
+
+```bash
+git rebase -i HEAD~3
+# Change 'pick' to 'edit' for commit to split
+
+# Git stops at that commit
+git reset HEAD^  # Undo commit but keep changes
+git add file1.js
+git commit -m "Part 1: Add file1"
+git add file2.js
+git commit -m "Part 2: Add file2"
+git rebase --continue
+```
+
+## Rebase Safety
+
+```bash
+# Continue after resolving conflicts
+git rebase --continue
+
+# Skip current commit (use with caution)
+git rebase --skip
+
+# Abort if things go wrong
+git rebase --abort
+
+# Check reflog if you need to recover
+git reflog
+```
+
+## Rebase vs Merge
+
+| Scenario | Use |
+|----------|-----|
+| Feature branch → main | Rebase for clean history |
+| Shared/public branches | Merge (don't rewrite history) |
+| Long-lived feature branch | Rebase onto main periodically |
+| After code review changes | Rebase to clean up |
+
+## Autosquash
+
+```bash
+# Create fixup commit (will auto-squash)
+git commit --fixup=abc123
+
+# Create squash commit with message
+git commit --squash=abc123
+
+# Rebase with autosquash
+git rebase -i --autosquash main
+# Fixup commits auto-positioned after their targets
+```
+
+## Rebase Configuration
+
+```bash
+# Enable autosquash by default
+git config --global rebase.autosquash true
+
+# Use vim for rebase editor
+git config --global sequence.editor vim
+
+# Preserve merge commits during rebase
+git rebase -i --rebase-merges main
+```

+ 141 - 0
skills/git-workflow/references/stash-patterns.md

@@ -0,0 +1,141 @@
+# Stash Patterns
+
+Save work temporarily without committing.
+
+## Basic Stash Operations
+
+```bash
+# Save current changes
+git stash
+
+# Save with description
+git stash push -m "WIP: feature X"
+
+# Stash including untracked files
+git stash -u
+
+# Stash including ignored files
+git stash -a
+
+# Stash only staged changes
+git stash push --staged
+```
+
+## Managing Stashes
+
+```bash
+# List all stashes
+git stash list
+
+# Show stash contents (summary)
+git stash show stash@{0}
+
+# Show stash contents (full diff)
+git stash show -p stash@{0}
+
+# Show stash with stats
+git stash show --stat stash@{0}
+```
+
+## Applying Stashes
+
+```bash
+# Apply most recent stash (keep in stash list)
+git stash apply
+
+# Apply and remove from list
+git stash pop
+
+# Apply specific stash
+git stash apply stash@{2}
+
+# Apply specific stash and drop
+git stash pop stash@{2}
+```
+
+## Removing Stashes
+
+```bash
+# Drop specific stash
+git stash drop stash@{1}
+
+# Drop most recent stash
+git stash drop
+
+# Clear all stashes
+git stash clear
+```
+
+## Common Workflows
+
+### Switch Branches Mid-Work
+
+```bash
+# Mid-feature, need to switch branches
+git stash push -m "WIP: auth flow"
+git checkout hotfix-branch
+# ... fix bug, commit, push ...
+git checkout feature-branch
+git stash pop
+```
+
+### Partial Stashing
+
+```bash
+# Stash specific files
+git stash push -m "WIP" -- file1.js file2.js
+
+# Interactive stash (select hunks)
+git stash push -p
+# y - stash this hunk
+# n - don't stash this hunk
+# s - split into smaller hunks
+# q - quit (stash selected hunks)
+```
+
+### Stash to Branch
+
+```bash
+# Create branch from stash
+git stash branch new-feature stash@{0}
+# Creates branch, checks it out, applies stash, drops stash
+```
+
+### Apply Stash to Different Branch
+
+```bash
+git checkout target-branch
+git stash apply stash@{1}
+# Resolve any conflicts
+git add .
+git commit
+```
+
+## Stash Conflicts
+
+```bash
+# If stash apply/pop has conflicts
+git stash apply
+# CONFLICT messages appear
+
+# Resolve conflicts manually, then
+git add .
+git stash drop  # Remove the stash after resolving
+
+# Or abort and keep stash
+git checkout -- .  # Discard changes
+```
+
+## Tips
+
+```bash
+# Always use descriptive messages
+git stash push -m "WIP: halfway through refactoring auth"
+
+# Check what's in stash before applying
+git stash show -p stash@{0}
+
+# Don't let stash list grow too long
+git stash list  # Review periodically
+git stash drop stash@{5}  # Clean old stashes
+```

+ 10 - 0
skills/mcp-patterns/SKILL.md

@@ -3,6 +3,8 @@ name: mcp-patterns
 description: "Model Context Protocol (MCP) server patterns for building integrations with Claude Code. Triggers on: mcp server, model context protocol, tool handler, mcp resource, mcp tool."
 compatibility: "Requires Python 3.10+ or Node.js 18+ for MCP server development."
 allowed-tools: "Read Write Bash"
+depends-on: []
+related-skills: [claude-code-hooks, claude-code-debug]
 ---
 
 # MCP Patterns
@@ -123,6 +125,14 @@ my-mcp-server/
 | Timeout errors | Add timeout to httpx calls, use async properly |
 | JSON parse errors | Ensure `call_tool` returns proper content structure |
 
+## Official Documentation
+
+- https://modelcontextprotocol.io - MCP specification
+- https://modelcontextprotocol.io/docs/concepts/tools - Tools reference
+- https://modelcontextprotocol.io/docs/concepts/resources - Resources reference
+- https://github.com/modelcontextprotocol/python-sdk - Python SDK
+- https://github.com/modelcontextprotocol/servers - Official MCP servers
+
 ## Additional Resources
 
 For detailed patterns, load:

+ 61 - 275
skills/rest-patterns/SKILL.md

@@ -1,12 +1,12 @@
 ---
 name: rest-patterns
-description: "Quick reference for RESTful API design patterns, HTTP semantics, caching, and rate limiting. Triggers on: rest api, http methods, status codes, api design, endpoint design, api versioning, rate limiting, caching."
+description: "Quick reference for RESTful API design patterns, HTTP semantics, caching, and rate limiting. Triggers on: rest api, http methods, status codes, api design, endpoint design, api versioning, rate limiting, caching headers."
 allowed-tools: "Read Write"
 ---
 
 # REST Patterns
 
-Quick reference for RESTful API design patterns, HTTP semantics, caching, and rate limiting.
+Quick reference for RESTful API design patterns and HTTP semantics.
 
 ## HTTP Methods
 
@@ -17,294 +17,80 @@ Quick reference for RESTful API design patterns, HTTP semantics, caching, and ra
 | **PUT** | Replace entire resource | Yes | No |
 | **PATCH** | Partial update | Maybe | No |
 | **DELETE** | Remove resource | Yes | No |
-| **HEAD** | GET headers only | Yes | Yes |
-| **OPTIONS** | CORS preflight | Yes | No |
 
-## Status Codes Quick Reference
+## Essential Status Codes
 
-### Success (2xx)
+| Code | Name | Use |
+|------|------|-----|
+| **200** | OK | Success with body |
+| **201** | Created | POST success (add `Location` header) |
+| **204** | No Content | Success, no body |
+| **400** | Bad Request | Invalid syntax |
+| **401** | Unauthorized | Not authenticated |
+| **403** | Forbidden | Not authorized |
+| **404** | Not Found | Resource doesn't exist |
+| **422** | Unprocessable | Validation error |
+| **429** | Too Many Requests | Rate limited |
+| **500** | Server Error | Internal failure |
 
-| Code | When to Use |
-|------|-------------|
-| **200 OK** | GET, PUT, PATCH, DELETE success |
-| **201 Created** | POST success (include `Location` header) |
-| **202 Accepted** | Request queued for async processing |
-| **204 No Content** | Success with no response body |
-| **206 Partial Content** | Range request fulfilled |
+## Resource Design
 
-### Redirection (3xx)
-
-| Code | When to Use |
-|------|-------------|
-| **301 Moved Permanently** | Resource permanently relocated |
-| **302 Found** | Temporary redirect (avoid in APIs) |
-| **304 Not Modified** | Client cache is valid (ETag match) |
-| **307 Temporary Redirect** | Redirect preserving method |
-| **308 Permanent Redirect** | Like 301, preserves method |
-
-### Client Errors (4xx)
-
-| Code | When to Use |
-|------|-------------|
-| **400 Bad Request** | Invalid syntax, malformed JSON |
-| **401 Unauthorized** | Missing or invalid auth |
-| **403 Forbidden** | Authenticated but not authorized |
-| **404 Not Found** | Resource doesn't exist |
-| **405 Method Not Allowed** | HTTP method not supported |
-| **409 Conflict** | State conflict (duplicate, version mismatch) |
-| **410 Gone** | Resource permanently removed |
-| **412 Precondition Failed** | If-Match header condition failed |
-| **422 Unprocessable Entity** | Validation errors (valid syntax, bad semantics) |
-| **429 Too Many Requests** | Rate limit exceeded |
-
-### Server Errors (5xx)
-
-| Code | When to Use |
-|------|-------------|
-| **500 Internal Server Error** | Generic server failure |
-| **502 Bad Gateway** | Upstream returned invalid response |
-| **503 Service Unavailable** | Temporarily unavailable |
-| **504 Gateway Timeout** | Upstream timeout |
-
-## Resource Design Patterns
-
-```
-# Collections (plural nouns)
-GET    /users              # List all
-POST   /users              # Create one
+```http
+GET    /users              # List
+POST   /users              # Create
 GET    /users/{id}         # Get one
-PUT    /users/{id}         # Replace one
-PATCH  /users/{id}         # Update one
-DELETE /users/{id}         # Delete one
-
-# Nested resources (max 2-3 levels)
-GET    /users/{id}/orders           # User's orders
-GET    /users/{id}/orders/{orderId} # Specific order
+PUT    /users/{id}         # Replace
+PATCH  /users/{id}         # Update
+DELETE /users/{id}         # Delete
 
 # Query parameters
-GET /users?role=admin&status=active     # Filtering
-GET /users?page=2&limit=20              # Pagination
-GET /users?sort=created_at&order=desc   # Sorting
-GET /users?fields=id,name,email         # Sparse fieldsets
-```
-
-## Caching Headers
-
-### Response Headers
-
-```http
-# Time-based caching
-Cache-Control: max-age=3600              # Cache for 1 hour
-Cache-Control: max-age=0, must-revalidate # Always revalidate
-Cache-Control: no-store                  # Never cache (sensitive data)
-Cache-Control: private, max-age=600      # Browser only, not CDN
-
-# Validation
-ETag: "abc123"                           # Content fingerprint
-Last-Modified: Wed, 21 Oct 2024 07:28:00 GMT
-```
-
-### Request Headers
-
-```http
-# Conditional requests
-If-None-Match: "abc123"                  # Validate ETag
-If-Modified-Since: Wed, 21 Oct 2024 07:28:00 GMT
-
-# Bypass cache
-Cache-Control: no-cache                  # Force revalidation
-```
-
-### Caching Strategy by Resource Type
-
-| Resource | Strategy | Headers |
-|----------|----------|---------|
-| Static assets | Long-lived | `max-age=31536000, immutable` |
-| API responses | Short/revalidate | `max-age=60, must-revalidate` |
-| User data | Private | `private, max-age=0` |
-| Sensitive data | Never | `no-store` |
-| Public lists | Shared | `public, max-age=300` |
-
-### ETag Workflow
-
-```
-# First request
-GET /users/123
-→ 200 OK
-→ ETag: "v1-abc123"
-
-# Subsequent request
-GET /users/123
-If-None-Match: "v1-abc123"
-→ 304 Not Modified (no body, use cached)
-
-# Or if changed
-→ 200 OK
-→ ETag: "v2-def456"
-```
-
-## Rate Limiting
-
-### Standard Headers
-
-```http
-# Response headers
-X-RateLimit-Limit: 1000          # Max requests per window
-X-RateLimit-Remaining: 847       # Requests left
-X-RateLimit-Reset: 1698415200    # Unix timestamp when limit resets
-Retry-After: 60                  # Seconds to wait (on 429)
+GET /users?page=2&limit=20          # Pagination
+GET /users?sort=created_at:desc     # Sorting
+GET /users?role=admin               # Filtering
 ```
 
-### Rate Limit Response (429)
-
-```json
-{
-  "error": {
-    "code": "RATE_LIMIT_EXCEEDED",
-    "message": "Too many requests",
-    "retry_after": 60
-  }
-}
-```
-
-### Rate Limiting Strategies
-
-| Strategy | Use Case | Example |
-|----------|----------|---------|
-| **Fixed window** | Simple limits | 100 req/minute |
-| **Sliding window** | Smoother limits | 100 req in rolling 60s |
-| **Token bucket** | Burst allowance | 10 req/s, 100 burst |
-| **Per-endpoint** | Expensive operations | /search: 10/min |
-| **Per-user tier** | Freemium APIs | Free: 100/hr, Pro: 10000/hr |
-
-## Error Response Format
-
-```json
-{
-  "error": {
-    "code": "VALIDATION_ERROR",
-    "message": "Invalid input data",
-    "details": [
-      {"field": "email", "message": "Invalid email format"},
-      {"field": "age", "message": "Must be 18 or older"}
-    ],
-    "request_id": "abc-123",
-    "documentation_url": "https://api.example.com/docs/errors#validation"
-  }
-}
-```
-
-## Versioning Strategies
-
-| Strategy | Example | Pros/Cons |
-|----------|---------|-----------|
-| **URI** | `/v1/users` | Clear, easy to implement, URL pollution |
-| **Header** | `Accept: application/vnd.api.v1+json` | Clean URLs, harder to test |
-| **Query** | `/users?version=1` | Easy to implement, less RESTful |
-
-## Bulk Operations
-
-### Batch Endpoint
-
-```http
-POST /batch
-Content-Type: application/json
-
-{
-  "operations": [
-    {"method": "POST", "path": "/users", "body": {"name": "Alice"}},
-    {"method": "PATCH", "path": "/users/123", "body": {"status": "active"}},
-    {"method": "DELETE", "path": "/users/456"}
-  ]
-}
-
-Response:
-{
-  "results": [
-    {"status": 201, "body": {"id": 789, "name": "Alice"}},
-    {"status": 200, "body": {"id": 123, "status": "active"}},
-    {"status": 204, "body": null}
-  ]
-}
-```
-
-### Bulk Create/Update
-
-```http
-POST /users/bulk
-Content-Type: application/json
-
-[
-  {"name": "Alice", "email": "alice@example.com"},
-  {"name": "Bob", "email": "bob@example.com"}
-]
+## Security Checklist
 
-Response:
-{
-  "created": 2,
-  "errors": []
-}
-```
+- [ ] HTTPS/TLS only
+- [ ] OAuth 2.0 or JWT for auth
+- [ ] Validate all inputs
+- [ ] Rate limit per client
+- [ ] CORS headers configured
+- [ ] No sensitive data in URLs
+- [ ] Use `no-store` for sensitive responses
 
-## HATEOAS Links
+## Common Mistakes
 
-```json
-{
-  "id": 123,
-  "name": "Alice",
-  "email": "alice@example.com",
-  "_links": {
-    "self": {"href": "/users/123"},
-    "orders": {"href": "/users/123/orders"},
-    "profile": {"href": "/users/123/profile"},
-    "update": {"href": "/users/123", "method": "PATCH"},
-    "delete": {"href": "/users/123", "method": "DELETE"}
-  }
-}
-```
+| Mistake | Fix |
+|---------|-----|
+| Verbs in URLs | `/getUsers` → `/users` |
+| Deep nesting | Flatten or use query params |
+| 200 for errors | Use proper 4xx/5xx |
+| No pagination | Always paginate collections |
+| Missing rate limits | Protect against abuse |
 
-### Collection with Pagination Links
+## Quick Reference
 
-```json
-{
-  "data": [...],
-  "meta": {
-    "total": 150,
-    "page": 2,
-    "per_page": 20
-  },
-  "_links": {
-    "self": {"href": "/users?page=2"},
-    "first": {"href": "/users?page=1"},
-    "prev": {"href": "/users?page=1"},
-    "next": {"href": "/users?page=3"},
-    "last": {"href": "/users?page=8"}
-  }
-}
-```
+| Task | Pattern |
+|------|---------|
+| Paginate | `?page=2&limit=20` |
+| Sort | `?sort=field:asc` |
+| Filter | `?status=active` |
+| Sparse fields | `?fields=id,name` |
+| Include related | `?include=orders` |
 
-## Security Checklist
+## When to Use
 
-- Always HTTPS/TLS
-- OAuth 2.0 or JWT for auth
-- API keys for service-to-service
-- Validate all inputs
-- Rate limit per client
-- CORS headers configured
-- No sensitive data in URLs
-- Security headers (HSTS, CSP)
-- Use `no-store` for sensitive responses
+- Designing new API endpoints
+- Choosing HTTP methods and status codes
+- Implementing caching headers
+- Setting up rate limiting
+- Structuring error responses
 
-## Common Mistakes
+## Additional Resources
 
-| Mistake | Fix |
-|---------|-----|
-| Using verbs in URLs | `/getUsers` → `/users` |
-| Deep nesting | `/a/1/b/2/c/3/d` → flatten or use query params |
-| 200 for errors | Return appropriate 4xx/5xx |
-| POST for everything | Use proper HTTP methods |
-| Returning 500 for client errors | 4xx for client, 5xx for server |
-| No pagination on lists | Always paginate collections |
-| Ignoring caching | Add ETag, Cache-Control headers |
-| Missing rate limits | Protect against abuse |
-| No versioning strategy | Plan for breaking changes |
+For detailed patterns, load:
+- `./references/status-codes.md` - Complete status code reference with examples
+- `./references/caching-patterns.md` - Cache-Control, ETag, CDN patterns
+- `./references/rate-limiting.md` - Rate limiting strategies and headers
+- `./references/response-formats.md` - Errors, versioning, bulk ops, HATEOAS

+ 192 - 0
skills/rest-patterns/references/caching-patterns.md

@@ -0,0 +1,192 @@
+# Caching Patterns
+
+HTTP caching strategies for REST APIs.
+
+## Response Headers
+
+### Cache-Control
+
+```http
+# Cache for 1 hour
+Cache-Control: max-age=3600
+
+# Cache, but always revalidate
+Cache-Control: max-age=0, must-revalidate
+
+# Never cache (sensitive data)
+Cache-Control: no-store
+
+# Browser only, not CDN
+Cache-Control: private, max-age=600
+
+# Shared/CDN caching
+Cache-Control: public, max-age=3600
+
+# Stale content while revalidating
+Cache-Control: max-age=3600, stale-while-revalidate=60
+```
+
+### Validation Headers
+
+```http
+# Content fingerprint
+ETag: "abc123"
+ETag: W/"abc123"  # Weak ETag (semantic equivalence)
+
+# Last modification time
+Last-Modified: Wed, 21 Oct 2024 07:28:00 GMT
+```
+
+## Request Headers
+
+### Conditional Requests
+
+```http
+# Validate ETag
+If-None-Match: "abc123"
+
+# Validate last modified
+If-Modified-Since: Wed, 21 Oct 2024 07:28:00 GMT
+
+# Only update if ETag matches (optimistic locking)
+If-Match: "abc123"
+```
+
+### Bypass Cache
+
+```http
+# Force revalidation
+Cache-Control: no-cache
+
+# Bypass entirely (use sparingly)
+Cache-Control: no-store
+Pragma: no-cache
+```
+
+## Caching Strategies by Resource
+
+| Resource Type | Strategy | Headers |
+|---------------|----------|---------|
+| Static assets (JS, CSS) | Long-lived | `max-age=31536000, immutable` |
+| Versioned assets | Permanent | `max-age=31536000` with hash in filename |
+| API responses | Short/revalidate | `max-age=60, must-revalidate` |
+| User-specific data | Private | `private, max-age=0` |
+| Sensitive data | Never cache | `no-store` |
+| Public lists | Shared | `public, max-age=300` |
+| Search results | Short-lived | `max-age=60` |
+
+## ETag Workflow
+
+### Initial Request
+
+```http
+GET /users/123
+
+→ 200 OK
+→ ETag: "v1-abc123"
+→ Cache-Control: max-age=60
+→ {"id": 123, "name": "Alice", "updated_at": "..."}
+```
+
+### Revalidation (Cache Valid)
+
+```http
+GET /users/123
+If-None-Match: "v1-abc123"
+
+→ 304 Not Modified
+(No body, client uses cached version)
+```
+
+### Revalidation (Cache Stale)
+
+```http
+GET /users/123
+If-None-Match: "v1-abc123"
+
+→ 200 OK
+→ ETag: "v2-def456"
+→ {"id": 123, "name": "Alice Updated", "updated_at": "..."}
+```
+
+## Optimistic Locking with ETag
+
+Prevent concurrent update conflicts:
+
+```http
+# Get current version
+GET /users/123
+→ ETag: "v1"
+
+# Update with version check
+PATCH /users/123
+If-Match: "v1"
+{"name": "New Name"}
+
+→ 200 OK (if still v1)
+→ 412 Precondition Failed (if changed)
+```
+
+## CDN Caching
+
+### Vary Header
+
+Tell CDN which headers affect response:
+
+```http
+# Different response per Accept-Language
+Vary: Accept-Language
+
+# Different per auth (don't cache auth-dependent responses in CDN)
+Vary: Authorization
+Cache-Control: private
+```
+
+### Surrogate Keys
+
+For targeted cache invalidation:
+
+```http
+Surrogate-Key: user-123 users-list homepage
+```
+
+## Cache Invalidation Patterns
+
+### Active Invalidation
+
+```bash
+# Purge by URL
+curl -X PURGE https://cdn.example.com/api/users/123
+
+# Purge by surrogate key
+curl -X PURGE https://cdn.example.com \
+  -H "Surrogate-Key: user-123"
+```
+
+### Passive Invalidation
+
+- Use short `max-age` with `stale-while-revalidate`
+- Version in URL: `/v2/users` instead of `/users`
+- Hash in filename for assets
+
+## Common Patterns
+
+### API Responses
+
+```http
+Cache-Control: private, max-age=0, must-revalidate
+ETag: "content-hash"
+```
+
+### Authenticated Endpoints
+
+```http
+Cache-Control: private, no-store
+```
+
+### Public Data (rarely changes)
+
+```http
+Cache-Control: public, max-age=3600, stale-while-revalidate=60
+ETag: "content-hash"
+```

+ 201 - 0
skills/rest-patterns/references/rate-limiting.md

@@ -0,0 +1,201 @@
+# Rate Limiting Patterns
+
+Strategies and headers for API rate limiting.
+
+## Standard Headers
+
+### Response Headers
+
+```http
+X-RateLimit-Limit: 1000          # Max requests per window
+X-RateLimit-Remaining: 847       # Requests remaining
+X-RateLimit-Reset: 1698415200    # Unix timestamp when limit resets
+Retry-After: 60                  # Seconds to wait (on 429)
+```
+
+### Rate Limit Response (429)
+
+```json
+{
+  "error": {
+    "code": "RATE_LIMIT_EXCEEDED",
+    "message": "Too many requests",
+    "retry_after": 60,
+    "limit": 1000,
+    "remaining": 0,
+    "reset_at": "2024-10-27T12:00:00Z"
+  }
+}
+```
+
+## Rate Limiting Strategies
+
+### Fixed Window
+
+Simple: count requests in fixed time periods.
+
+```
+Window: 1 minute (00:00-00:59, 01:00-01:59, ...)
+Limit: 100 requests
+
+Pros: Simple to implement
+Cons: Burst at window edges (200 in 2 seconds across boundary)
+```
+
+### Sliding Window
+
+Smoother: use weighted average across windows.
+
+```
+Current window: 50% through
+Previous window: 60 requests
+Current window: 40 requests
+
+Weighted count = (60 × 0.5) + 40 = 70
+Remaining = 100 - 70 = 30
+
+Pros: Smoother limits
+Cons: More complex, needs previous window data
+```
+
+### Token Bucket
+
+Allows bursts with steady refill.
+
+```
+Bucket capacity: 100 tokens
+Refill rate: 10 tokens/second
+
+- Start with 100 tokens
+- Each request costs 1 token
+- Tokens refill at 10/sec
+- Burst allowed up to 100, then steady 10/sec
+
+Pros: Allows bursts, intuitive
+Cons: More state to track
+```
+
+### Leaky Bucket
+
+Fixed output rate, queue excess.
+
+```
+Processing rate: 10 requests/second
+Queue size: 50
+
+- Requests queue up
+- Processed at constant rate
+- Queue overflow = 429
+
+Pros: Smooth output, protects backend
+Cons: Adds latency
+```
+
+## Rate Limit Tiers
+
+### By User/Plan
+
+```http
+# Free tier
+X-RateLimit-Limit: 100
+X-RateLimit-Window: 3600   # per hour
+
+# Pro tier
+X-RateLimit-Limit: 10000
+X-RateLimit-Window: 3600
+```
+
+### By Endpoint
+
+```http
+# Search (expensive)
+X-RateLimit-Limit: 10
+X-RateLimit-Window: 60
+
+# Read (cheap)
+X-RateLimit-Limit: 1000
+X-RateLimit-Window: 60
+```
+
+### By Operation Type
+
+```http
+# Writes
+POST/PUT/DELETE: 100/minute
+
+# Reads
+GET: 1000/minute
+```
+
+## Implementation Headers
+
+### GitHub Style
+
+```http
+X-RateLimit-Limit: 5000
+X-RateLimit-Remaining: 4999
+X-RateLimit-Reset: 1372700873
+X-RateLimit-Used: 1
+X-RateLimit-Resource: core
+```
+
+### RFC Draft (RateLimit Headers)
+
+```http
+RateLimit-Limit: 100
+RateLimit-Remaining: 50
+RateLimit-Reset: 60
+```
+
+## Client Handling
+
+### Retry Logic
+
+```javascript
+async function fetchWithRetry(url, options, maxRetries = 3) {
+  for (let i = 0; i < maxRetries; i++) {
+    const response = await fetch(url, options);
+
+    if (response.status === 429) {
+      const retryAfter = response.headers.get('Retry-After') || 60;
+      await sleep(retryAfter * 1000);
+      continue;
+    }
+
+    return response;
+  }
+  throw new Error('Rate limit exceeded after retries');
+}
+```
+
+### Proactive Backoff
+
+```javascript
+function checkRateLimit(response) {
+  const remaining = response.headers.get('X-RateLimit-Remaining');
+  const reset = response.headers.get('X-RateLimit-Reset');
+
+  if (remaining < 10) {
+    const waitMs = (reset - Date.now()) / remaining;
+    // Slow down requests
+  }
+}
+```
+
+## Best Practices
+
+### Server Side
+
+1. Include rate limit headers in all responses
+2. Return 429 with clear error message
+3. Always include `Retry-After`
+4. Consider different limits per endpoint
+5. Log rate limit hits for monitoring
+
+### Client Side
+
+1. Respect `Retry-After` header
+2. Implement exponential backoff
+3. Monitor remaining quota
+4. Cache responses to reduce requests
+5. Batch operations when possible

+ 289 - 0
skills/rest-patterns/references/response-formats.md

@@ -0,0 +1,289 @@
+# Response Formats
+
+Error responses, versioning, bulk operations, and HATEOAS patterns.
+
+## Error Response Format
+
+### Standard Structure
+
+```json
+{
+  "error": {
+    "code": "VALIDATION_ERROR",
+    "message": "Invalid input data",
+    "details": [
+      {"field": "email", "message": "Invalid email format"},
+      {"field": "age", "message": "Must be 18 or older"}
+    ],
+    "request_id": "abc-123",
+    "documentation_url": "https://api.example.com/docs/errors#validation"
+  }
+}
+```
+
+### Minimal Error
+
+```json
+{
+  "error": {
+    "code": "NOT_FOUND",
+    "message": "User not found"
+  }
+}
+```
+
+### Validation Errors (422)
+
+```json
+{
+  "error": {
+    "code": "VALIDATION_ERROR",
+    "message": "Validation failed",
+    "details": [
+      {
+        "field": "email",
+        "code": "INVALID_FORMAT",
+        "message": "Must be a valid email address"
+      },
+      {
+        "field": "password",
+        "code": "TOO_SHORT",
+        "message": "Must be at least 8 characters"
+      }
+    ]
+  }
+}
+```
+
+### RFC 7807 Problem Details
+
+```json
+{
+  "type": "https://api.example.com/errors/validation",
+  "title": "Validation Error",
+  "status": 422,
+  "detail": "The request body contains invalid data",
+  "instance": "/users/123",
+  "errors": [
+    {"pointer": "/email", "detail": "Invalid format"}
+  ]
+}
+```
+
+---
+
+## Versioning Strategies
+
+### URI Versioning (Most Common)
+
+```http
+GET /v1/users
+GET /v2/users
+```
+
+**Pros:** Clear, easy to route, cacheable
+**Cons:** URL pollution, hard to deprecate
+
+### Header Versioning
+
+```http
+GET /users
+Accept: application/vnd.api.v1+json
+```
+
+**Pros:** Clean URLs
+**Cons:** Harder to test, less visible
+
+### Query Parameter
+
+```http
+GET /users?version=1
+GET /users?api-version=2024-01-15
+```
+
+**Pros:** Easy to implement
+**Cons:** Less RESTful, affects caching
+
+### Date-Based Versioning
+
+```http
+GET /users
+API-Version: 2024-01-15
+```
+
+**Pros:** Fine-grained, Stripe-style
+**Cons:** Complex to maintain
+
+---
+
+## Bulk Operations
+
+### Batch Endpoint
+
+```http
+POST /batch
+Content-Type: application/json
+
+{
+  "operations": [
+    {"method": "POST", "path": "/users", "body": {"name": "Alice"}},
+    {"method": "PATCH", "path": "/users/123", "body": {"status": "active"}},
+    {"method": "DELETE", "path": "/users/456"}
+  ]
+}
+```
+
+**Response:**
+
+```json
+{
+  "results": [
+    {"status": 201, "body": {"id": 789, "name": "Alice"}},
+    {"status": 200, "body": {"id": 123, "status": "active"}},
+    {"status": 204, "body": null}
+  ]
+}
+```
+
+### Bulk Create
+
+```http
+POST /users/bulk
+Content-Type: application/json
+
+[
+  {"name": "Alice", "email": "alice@example.com"},
+  {"name": "Bob", "email": "bob@example.com"}
+]
+```
+
+**Response:**
+
+```json
+{
+  "created": 2,
+  "items": [
+    {"id": 123, "name": "Alice"},
+    {"id": 124, "name": "Bob"}
+  ]
+}
+```
+
+### Bulk Create with Partial Failure
+
+```json
+{
+  "created": 1,
+  "failed": 1,
+  "items": [
+    {"id": 123, "name": "Alice", "status": "created"}
+  ],
+  "errors": [
+    {"index": 1, "error": {"code": "DUPLICATE", "message": "Email exists"}}
+  ]
+}
+```
+
+### Bulk Delete
+
+```http
+DELETE /users/bulk
+Content-Type: application/json
+
+{"ids": [1, 2, 3, 4, 5]}
+```
+
+**Response:**
+
+```json
+{
+  "deleted": 5
+}
+```
+
+---
+
+## HATEOAS Links
+
+### Single Resource
+
+```json
+{
+  "id": 123,
+  "name": "Alice",
+  "email": "alice@example.com",
+  "_links": {
+    "self": {"href": "/users/123"},
+    "orders": {"href": "/users/123/orders"},
+    "profile": {"href": "/users/123/profile"},
+    "update": {"href": "/users/123", "method": "PATCH"},
+    "delete": {"href": "/users/123", "method": "DELETE"}
+  }
+}
+```
+
+### Collection with Pagination
+
+```json
+{
+  "data": [
+    {"id": 1, "name": "Alice"},
+    {"id": 2, "name": "Bob"}
+  ],
+  "meta": {
+    "total": 150,
+    "page": 2,
+    "per_page": 20,
+    "total_pages": 8
+  },
+  "_links": {
+    "self": {"href": "/users?page=2"},
+    "first": {"href": "/users?page=1"},
+    "prev": {"href": "/users?page=1"},
+    "next": {"href": "/users?page=3"},
+    "last": {"href": "/users?page=8"}
+  }
+}
+```
+
+### HAL Format
+
+```json
+{
+  "_embedded": {
+    "users": [
+      {"id": 1, "name": "Alice", "_links": {"self": {"href": "/users/1"}}},
+      {"id": 2, "name": "Bob", "_links": {"self": {"href": "/users/2"}}}
+    ]
+  },
+  "_links": {
+    "self": {"href": "/users?page=1"},
+    "next": {"href": "/users?page=2"}
+  },
+  "page": 1,
+  "total": 100
+}
+```
+
+### JSON:API Format
+
+```json
+{
+  "data": [
+    {
+      "type": "users",
+      "id": "1",
+      "attributes": {"name": "Alice"},
+      "relationships": {
+        "orders": {"links": {"related": "/users/1/orders"}}
+      },
+      "links": {"self": "/users/1"}
+    }
+  ],
+  "links": {
+    "self": "/users?page=1",
+    "next": "/users?page=2"
+  },
+  "meta": {"total": 100}
+}
+```

+ 172 - 0
skills/rest-patterns/references/status-codes.md

@@ -0,0 +1,172 @@
+# HTTP Status Codes Reference
+
+Complete reference for HTTP status codes in REST APIs.
+
+## Success (2xx)
+
+| Code | Name | When to Use |
+|------|------|-------------|
+| **200 OK** | Success | GET, PUT, PATCH, DELETE success with body |
+| **201 Created** | Created | POST success (include `Location` header) |
+| **202 Accepted** | Accepted | Request queued for async processing |
+| **204 No Content** | No Content | Success with no response body |
+| **206 Partial Content** | Partial | Range request fulfilled |
+
+### Usage Examples
+
+```http
+# 200 OK - Successful GET
+GET /users/123
+→ 200 OK
+→ {"id": 123, "name": "Alice"}
+
+# 201 Created - Successful POST
+POST /users
+→ 201 Created
+→ Location: /users/456
+→ {"id": 456, "name": "Bob"}
+
+# 202 Accepted - Async operation
+POST /jobs
+→ 202 Accepted
+→ {"job_id": "abc123", "status": "pending"}
+
+# 204 No Content - Successful DELETE
+DELETE /users/123
+→ 204 No Content
+```
+
+## Redirection (3xx)
+
+| Code | Name | When to Use |
+|------|------|-------------|
+| **301 Moved Permanently** | Moved | Resource permanently relocated |
+| **302 Found** | Found | Temporary redirect (avoid in APIs) |
+| **304 Not Modified** | Not Modified | Client cache is valid (ETag match) |
+| **307 Temporary Redirect** | Temp Redirect | Redirect preserving HTTP method |
+| **308 Permanent Redirect** | Perm Redirect | Like 301, preserves method |
+
+### 301 vs 308
+
+- **301**: Browser may change POST to GET on redirect
+- **308**: Guarantees method is preserved
+
+### 304 Workflow
+
+```http
+# First request
+GET /users/123
+→ 200 OK
+→ ETag: "abc123"
+
+# Subsequent request with validation
+GET /users/123
+If-None-Match: "abc123"
+→ 304 Not Modified (use cached version)
+```
+
+## Client Errors (4xx)
+
+| Code | Name | When to Use |
+|------|------|-------------|
+| **400 Bad Request** | Bad Request | Invalid syntax, malformed JSON |
+| **401 Unauthorized** | Unauthorized | Missing or invalid authentication |
+| **403 Forbidden** | Forbidden | Authenticated but not authorized |
+| **404 Not Found** | Not Found | Resource doesn't exist |
+| **405 Method Not Allowed** | Not Allowed | HTTP method not supported |
+| **406 Not Acceptable** | Not Acceptable | Can't produce requested content type |
+| **409 Conflict** | Conflict | State conflict (duplicate, version mismatch) |
+| **410 Gone** | Gone | Resource permanently removed |
+| **412 Precondition Failed** | Precondition | If-Match header condition failed |
+| **413 Payload Too Large** | Too Large | Request body exceeds limit |
+| **415 Unsupported Media Type** | Bad Media | Content-Type not supported |
+| **422 Unprocessable Entity** | Unprocessable | Valid syntax, invalid semantics |
+| **429 Too Many Requests** | Rate Limited | Rate limit exceeded |
+
+### 400 vs 422
+
+- **400**: Malformed request (invalid JSON, wrong types)
+- **422**: Valid request, but business logic rejects it
+
+```http
+# 400 - Syntax error
+POST /users
+{"name": "Alice", age: 30}  # Missing quotes around age
+→ 400 Bad Request
+→ {"error": "Invalid JSON"}
+
+# 422 - Validation error
+POST /users
+{"name": "Alice", "age": -5}  # Age can't be negative
+→ 422 Unprocessable Entity
+→ {"error": {"field": "age", "message": "Must be positive"}}
+```
+
+### 401 vs 403
+
+- **401**: "Who are you?" (not authenticated)
+- **403**: "I know who you are, but no" (not authorized)
+
+```http
+# 401 - Missing token
+GET /admin/users
+→ 401 Unauthorized
+→ {"error": "Authentication required"}
+
+# 403 - Valid token, wrong permissions
+GET /admin/users
+Authorization: Bearer <user_token>
+→ 403 Forbidden
+→ {"error": "Admin access required"}
+```
+
+### 409 Conflict Examples
+
+```http
+# Duplicate resource
+POST /users
+{"email": "existing@example.com"}
+→ 409 Conflict
+→ {"error": "Email already exists"}
+
+# Version mismatch (optimistic locking)
+PATCH /users/123
+If-Match: "old-version"
+→ 409 Conflict
+→ {"error": "Resource was modified"}
+```
+
+## Server Errors (5xx)
+
+| Code | Name | When to Use |
+|------|------|-------------|
+| **500 Internal Server Error** | Server Error | Generic server failure |
+| **501 Not Implemented** | Not Implemented | Feature not available |
+| **502 Bad Gateway** | Bad Gateway | Upstream returned invalid response |
+| **503 Service Unavailable** | Unavailable | Temporarily unavailable |
+| **504 Gateway Timeout** | Timeout | Upstream timeout |
+
+### 503 with Retry-After
+
+```http
+GET /api/resource
+→ 503 Service Unavailable
+→ Retry-After: 300
+→ {"error": "Service temporarily unavailable", "retry_after": 300}
+```
+
+## Decision Tree
+
+```
+Is the request valid?
+├─ No → Is it syntax? → 400 Bad Request
+│       Is it validation? → 422 Unprocessable Entity
+│
+└─ Yes → Is auth provided?
+         ├─ No → 401 Unauthorized
+         └─ Yes → Is authorized?
+                  ├─ No → 403 Forbidden
+                  └─ Yes → Does resource exist?
+                           ├─ No → 404 Not Found
+                           └─ Yes → Success! 2xx
+```

+ 182 - 0
skills/security-patterns/SKILL.md

@@ -0,0 +1,182 @@
+---
+name: security-patterns
+description: "Security patterns and OWASP guidelines. Triggers on: security review, OWASP, XSS, SQL injection, CSRF, authentication, authorization, secrets management, input validation, secure coding."
+compatibility: "Language-agnostic patterns with framework-specific examples in references."
+allowed-tools: "Read Write Bash Grep"
+---
+
+# Security Patterns
+
+Essential security patterns for web applications.
+
+## OWASP Top 10 Quick Reference
+
+| Rank | Vulnerability | Prevention |
+|------|--------------|------------|
+| A01 | Broken Access Control | Check permissions server-side, deny by default |
+| A02 | Cryptographic Failures | Use TLS, hash passwords, encrypt sensitive data |
+| A03 | Injection | Parameterized queries, validate input |
+| A04 | Insecure Design | Threat modeling, secure defaults |
+| A05 | Security Misconfiguration | Harden configs, disable unused features |
+| A06 | Vulnerable Components | Update dependencies, audit regularly |
+| A07 | Auth Failures | MFA, rate limiting, secure session management |
+| A08 | Data Integrity Failures | Verify signatures, use trusted sources |
+| A09 | Logging Failures | Log security events, protect logs |
+| A10 | SSRF | Validate URLs, allowlist destinations |
+
+## Input Validation
+
+```python
+# WRONG - Trust user input
+def search(query):
+    return db.execute(f"SELECT * FROM users WHERE name = '{query}'")
+
+# CORRECT - Parameterized query
+def search(query):
+    return db.execute("SELECT * FROM users WHERE name = ?", [query])
+```
+
+### Validation Rules
+```
+Always validate:
+- Type (string, int, email format)
+- Length (min/max bounds)
+- Range (numeric bounds)
+- Format (regex for patterns)
+- Allowlist (known good values)
+
+Never trust:
+- URL parameters
+- Form data
+- HTTP headers
+- Cookies
+- File uploads
+```
+
+## Output Encoding
+
+```javascript
+// WRONG - Direct HTML insertion
+element.innerHTML = userInput;
+
+// CORRECT - Text content (auto-escapes)
+element.textContent = userInput;
+
+// CORRECT - Template with escaping
+render(`<div>${escapeHtml(userInput)}</div>`);
+```
+
+### Encoding by Context
+| Context | Encoding |
+|---------|----------|
+| HTML body | HTML entity encode |
+| HTML attribute | Attribute encode + quote |
+| JavaScript | JS encode |
+| URL parameter | URL encode |
+| CSS | CSS encode |
+
+## Authentication
+
+```python
+# Password hashing (use bcrypt, argon2, or scrypt)
+import bcrypt
+
+def hash_password(password: str) -> bytes:
+    return bcrypt.hashpw(password.encode(), bcrypt.gensalt(rounds=12))
+
+def verify_password(password: str, hashed: bytes) -> bool:
+    return bcrypt.checkpw(password.encode(), hashed)
+```
+
+### Auth Checklist
+- [ ] Hash passwords with bcrypt/argon2 (cost factor 12+)
+- [ ] Implement rate limiting on login
+- [ ] Use secure session tokens (random, long)
+- [ ] Set secure cookie flags (HttpOnly, Secure, SameSite)
+- [ ] Implement account lockout after failed attempts
+- [ ] Support MFA for sensitive operations
+
+## Authorization
+
+```python
+# WRONG - Check only authentication
+@login_required
+def delete_post(post_id):
+    post = Post.get(post_id)
+    post.delete()
+
+# CORRECT - Check authorization
+@login_required
+def delete_post(post_id):
+    post = Post.get(post_id)
+    if post.author_id != current_user.id and not current_user.is_admin:
+        raise Forbidden("Not authorized to delete this post")
+    post.delete()
+```
+
+## Secrets Management
+
+```bash
+# WRONG - Hardcoded secrets
+API_KEY = "sk-1234567890abcdef"
+
+# CORRECT - Environment variables
+API_KEY = os.environ["API_KEY"]
+
+# BETTER - Secrets manager
+API_KEY = secrets_client.get_secret("api-key")
+```
+
+### Secret Handling Rules
+```
+DO:
+- Use environment variables or secrets manager
+- Rotate secrets regularly
+- Use different secrets per environment
+- Audit secret access
+
+DON'T:
+- Commit secrets to git
+- Log secrets
+- Include secrets in error messages
+- Share secrets in plain text
+```
+
+## Security Headers
+
+```
+Content-Security-Policy: default-src 'self'; script-src 'self'
+X-Content-Type-Options: nosniff
+X-Frame-Options: DENY
+Strict-Transport-Security: max-age=31536000; includeSubDomains
+Referrer-Policy: strict-origin-when-cross-origin
+Permissions-Policy: geolocation=(), camera=()
+```
+
+## Quick Security Audit
+
+```bash
+# Find hardcoded secrets
+rg -i "(password|secret|api_key|token)\s*=\s*['\"][^'\"]+['\"]" --type py
+
+# Find SQL injection risks
+rg "execute\(f['\"]|format\(" --type py
+
+# Find eval/exec usage
+rg "\b(eval|exec)\s*\(" --type py
+
+# Check for TODO security items
+rg -i "TODO.*security|FIXME.*security"
+```
+
+## Additional Resources
+
+- `./references/owasp-detailed.md` - Full OWASP Top 10 details
+- `./references/auth-patterns.md` - JWT, OAuth, session management
+- `./references/crypto-patterns.md` - Encryption, hashing, signatures
+- `./references/secure-headers.md` - HTTP security headers guide
+
+## Scripts
+
+- `./scripts/security-scan.sh` - Quick security grep patterns
+- `./scripts/dependency-audit.sh` - Check for vulnerable dependencies

+ 322 - 0
skills/security-patterns/references/auth-patterns.md

@@ -0,0 +1,322 @@
+# Authentication Patterns
+
+Secure authentication implementation patterns.
+
+## Password Hashing
+
+### bcrypt (Recommended)
+
+```python
+import bcrypt
+
+def hash_password(password: str) -> bytes:
+    """Hash password with bcrypt."""
+    salt = bcrypt.gensalt(rounds=12)  # Cost factor 12
+    return bcrypt.hashpw(password.encode('utf-8'), salt)
+
+def verify_password(password: str, hashed: bytes) -> bool:
+    """Verify password against hash."""
+    return bcrypt.checkpw(password.encode('utf-8'), hashed)
+
+# Usage
+hashed = hash_password("user_password")
+is_valid = verify_password("user_password", hashed)
+```
+
+### Argon2 (Modern Alternative)
+
+```python
+from argon2 import PasswordHasher
+
+ph = PasswordHasher(
+    time_cost=3,      # Iterations
+    memory_cost=65536, # 64MB
+    parallelism=4,     # Threads
+)
+
+def hash_password(password: str) -> str:
+    return ph.hash(password)
+
+def verify_password(password: str, hashed: str) -> bool:
+    try:
+        ph.verify(hashed, password)
+        return True
+    except:
+        return False
+```
+
+## Session Management
+
+### Secure Session Configuration
+
+```python
+from flask import Flask
+from datetime import timedelta
+
+app = Flask(__name__)
+
+app.config.update(
+    SECRET_KEY=os.environ['SECRET_KEY'],  # Strong random key
+    SESSION_COOKIE_NAME='__session',
+    SESSION_COOKIE_SECURE=True,           # HTTPS only
+    SESSION_COOKIE_HTTPONLY=True,         # No JavaScript access
+    SESSION_COOKIE_SAMESITE='Strict',     # CSRF protection
+    PERMANENT_SESSION_LIFETIME=timedelta(hours=1),
+)
+```
+
+### Session Token Generation
+
+```python
+import secrets
+
+def generate_session_id() -> str:
+    """Generate cryptographically secure session ID."""
+    return secrets.token_urlsafe(32)  # 256 bits of entropy
+
+def generate_csrf_token() -> str:
+    """Generate CSRF token."""
+    return secrets.token_hex(32)
+```
+
+## JWT Patterns
+
+### JWT Generation
+
+```python
+import jwt
+from datetime import datetime, timedelta
+
+SECRET_KEY = os.environ['JWT_SECRET']
+ALGORITHM = "HS256"
+
+def create_token(user_id: int, expires_delta: timedelta = timedelta(hours=1)) -> str:
+    expire = datetime.utcnow() + expires_delta
+    payload = {
+        "sub": str(user_id),
+        "exp": expire,
+        "iat": datetime.utcnow(),
+        "jti": secrets.token_urlsafe(16),  # Unique token ID
+    }
+    return jwt.encode(payload, SECRET_KEY, algorithm=ALGORITHM)
+
+def verify_token(token: str) -> dict:
+    try:
+        payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
+        return payload
+    except jwt.ExpiredSignatureError:
+        raise AuthError("Token expired")
+    except jwt.InvalidTokenError:
+        raise AuthError("Invalid token")
+```
+
+### JWT Best Practices
+
+```python
+# DO
+- Use strong secret (256+ bits)
+- Set short expiration (15min - 1hr)
+- Include jti for revocation
+- Use HTTPS only
+- Store in httpOnly cookie (not localStorage)
+
+# DON'T
+- Store sensitive data in payload (it's base64, not encrypted)
+- Use long expiration times
+- Send in URL parameters
+- Use weak algorithms (none, HS256 with weak key)
+```
+
+### Refresh Token Pattern
+
+```python
+def create_tokens(user_id: int) -> tuple[str, str]:
+    """Create access and refresh token pair."""
+    access_token = create_token(
+        user_id,
+        expires_delta=timedelta(minutes=15),
+        token_type="access"
+    )
+    refresh_token = create_token(
+        user_id,
+        expires_delta=timedelta(days=7),
+        token_type="refresh"
+    )
+    return access_token, refresh_token
+
+def refresh_access_token(refresh_token: str) -> str:
+    """Generate new access token from refresh token."""
+    payload = verify_token(refresh_token)
+
+    if payload.get("token_type") != "refresh":
+        raise AuthError("Not a refresh token")
+
+    # Check if refresh token is revoked
+    if is_token_revoked(payload["jti"]):
+        raise AuthError("Token revoked")
+
+    return create_token(payload["sub"], token_type="access")
+```
+
+## OAuth 2.0 Flow
+
+### Authorization Code Flow
+
+```python
+from authlib.integrations.flask_client import OAuth
+
+oauth = OAuth(app)
+oauth.register(
+    name='google',
+    client_id=os.environ['GOOGLE_CLIENT_ID'],
+    client_secret=os.environ['GOOGLE_CLIENT_SECRET'],
+    access_token_url='https://oauth2.googleapis.com/token',
+    authorize_url='https://accounts.google.com/o/oauth2/auth',
+    api_base_url='https://www.googleapis.com/',
+    client_kwargs={'scope': 'openid email profile'},
+)
+
+@app.route('/login/google')
+def google_login():
+    redirect_uri = url_for('google_callback', _external=True)
+    return oauth.google.authorize_redirect(redirect_uri)
+
+@app.route('/callback/google')
+def google_callback():
+    token = oauth.google.authorize_access_token()
+    user_info = oauth.google.get('oauth2/v3/userinfo').json()
+
+    # Find or create user
+    user = find_or_create_user(
+        email=user_info['email'],
+        name=user_info['name'],
+        oauth_provider='google',
+        oauth_id=user_info['sub']
+    )
+
+    login_user(user)
+    return redirect('/')
+```
+
+## Multi-Factor Authentication
+
+### TOTP Implementation
+
+```python
+import pyotp
+
+def generate_totp_secret() -> str:
+    """Generate new TOTP secret for user."""
+    return pyotp.random_base32()
+
+def get_totp_uri(secret: str, email: str) -> str:
+    """Generate URI for authenticator app."""
+    totp = pyotp.TOTP(secret)
+    return totp.provisioning_uri(name=email, issuer_name="MyApp")
+
+def verify_totp(secret: str, code: str) -> bool:
+    """Verify TOTP code."""
+    totp = pyotp.TOTP(secret)
+    return totp.verify(code, valid_window=1)  # Allow 30s drift
+```
+
+### Backup Codes
+
+```python
+def generate_backup_codes(count: int = 10) -> list[str]:
+    """Generate one-time backup codes."""
+    return [secrets.token_hex(4) for _ in range(count)]
+
+def use_backup_code(user_id: int, code: str) -> bool:
+    """Verify and consume backup code."""
+    user = get_user(user_id)
+    if code in user.backup_codes:
+        user.backup_codes.remove(code)
+        user.save()
+        return True
+    return False
+```
+
+## Rate Limiting
+
+```python
+from flask_limiter import Limiter
+from flask_limiter.util import get_remote_address
+
+limiter = Limiter(
+    app,
+    key_func=get_remote_address,
+    default_limits=["200 per day", "50 per hour"]
+)
+
+@app.route("/login", methods=["POST"])
+@limiter.limit("5 per minute")
+def login():
+    # Rate limited to 5 attempts per minute per IP
+    pass
+
+@app.route("/api/sensitive")
+@limiter.limit("10 per minute", key_func=lambda: current_user.id)
+def sensitive_endpoint():
+    # Rate limited per user, not IP
+    pass
+```
+
+## Account Security
+
+### Account Lockout
+
+```python
+MAX_FAILED_ATTEMPTS = 5
+LOCKOUT_DURATION = timedelta(minutes=30)
+
+def record_failed_login(user_id: int) -> None:
+    user = get_user(user_id)
+    user.failed_login_attempts += 1
+    user.last_failed_login = datetime.utcnow()
+
+    if user.failed_login_attempts >= MAX_FAILED_ATTEMPTS:
+        user.locked_until = datetime.utcnow() + LOCKOUT_DURATION
+        security_logger.warning(f"Account locked: {user.email}")
+
+    user.save()
+
+def check_account_locked(user_id: int) -> bool:
+    user = get_user(user_id)
+    if user.locked_until and user.locked_until > datetime.utcnow():
+        return True
+    return False
+
+def reset_failed_attempts(user_id: int) -> None:
+    user = get_user(user_id)
+    user.failed_login_attempts = 0
+    user.locked_until = None
+    user.save()
+```
+
+### Password Reset
+
+```python
+def create_reset_token(user_id: int) -> str:
+    """Create password reset token."""
+    token = secrets.token_urlsafe(32)
+    expires = datetime.utcnow() + timedelta(hours=1)
+
+    # Store hash of token, not token itself
+    token_hash = hashlib.sha256(token.encode()).hexdigest()
+    store_reset_token(user_id, token_hash, expires)
+
+    return token
+
+def verify_reset_token(token: str) -> int | None:
+    """Verify reset token and return user_id."""
+    token_hash = hashlib.sha256(token.encode()).hexdigest()
+    record = get_reset_token(token_hash)
+
+    if not record or record.expires < datetime.utcnow():
+        return None
+
+    # Invalidate token after use
+    delete_reset_token(token_hash)
+    return record.user_id
+```

+ 302 - 0
skills/security-patterns/references/crypto-patterns.md

@@ -0,0 +1,302 @@
+# Cryptography Patterns
+
+Secure cryptographic implementations.
+
+## Symmetric Encryption
+
+### AES-GCM (Recommended)
+
+```python
+from cryptography.hazmat.primitives.ciphers.aead import AESGCM
+import os
+
+def encrypt(plaintext: bytes, key: bytes) -> bytes:
+    """Encrypt data with AES-GCM."""
+    # Generate random 96-bit nonce
+    nonce = os.urandom(12)
+    aesgcm = AESGCM(key)
+    ciphertext = aesgcm.encrypt(nonce, plaintext, associated_data=None)
+    # Prepend nonce to ciphertext
+    return nonce + ciphertext
+
+def decrypt(data: bytes, key: bytes) -> bytes:
+    """Decrypt AES-GCM encrypted data."""
+    nonce = data[:12]
+    ciphertext = data[12:]
+    aesgcm = AESGCM(key)
+    return aesgcm.decrypt(nonce, ciphertext, associated_data=None)
+
+# Generate a secure key
+key = AESGCM.generate_key(bit_length=256)
+```
+
+### Fernet (Simple, Safe)
+
+```python
+from cryptography.fernet import Fernet
+
+# Generate key
+key = Fernet.generate_key()
+
+# Encrypt
+f = Fernet(key)
+token = f.encrypt(b"secret message")
+
+# Decrypt
+plaintext = f.decrypt(token)
+```
+
+## Key Derivation
+
+### PBKDF2
+
+```python
+from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
+from cryptography.hazmat.primitives import hashes
+import os
+
+def derive_key(password: str, salt: bytes = None) -> tuple[bytes, bytes]:
+    """Derive encryption key from password."""
+    if salt is None:
+        salt = os.urandom(16)
+
+    kdf = PBKDF2HMAC(
+        algorithm=hashes.SHA256(),
+        length=32,
+        salt=salt,
+        iterations=600000,  # OWASP 2023 recommendation
+    )
+    key = kdf.derive(password.encode())
+    return key, salt
+```
+
+### Argon2 for Key Derivation
+
+```python
+from argon2.low_level import hash_secret_raw, Type
+
+def derive_key_argon2(password: str, salt: bytes = None) -> tuple[bytes, bytes]:
+    """Derive key using Argon2id."""
+    if salt is None:
+        salt = os.urandom(16)
+
+    key = hash_secret_raw(
+        secret=password.encode(),
+        salt=salt,
+        time_cost=3,
+        memory_cost=65536,
+        parallelism=4,
+        hash_len=32,
+        type=Type.ID,
+    )
+    return key, salt
+```
+
+## Hashing
+
+### SHA-256 (Data Integrity)
+
+```python
+import hashlib
+
+def hash_data(data: bytes) -> str:
+    """Hash data for integrity checking."""
+    return hashlib.sha256(data).hexdigest()
+
+def verify_integrity(data: bytes, expected_hash: str) -> bool:
+    """Verify data hasn't been modified."""
+    return hashlib.sha256(data).hexdigest() == expected_hash
+```
+
+### HMAC (Message Authentication)
+
+```python
+import hmac
+import hashlib
+
+def create_signature(message: bytes, key: bytes) -> str:
+    """Create HMAC signature."""
+    return hmac.new(key, message, hashlib.sha256).hexdigest()
+
+def verify_signature(message: bytes, signature: str, key: bytes) -> bool:
+    """Verify HMAC signature (timing-safe)."""
+    expected = hmac.new(key, message, hashlib.sha256).hexdigest()
+    return hmac.compare_digest(expected, signature)
+```
+
+## Digital Signatures
+
+### RSA Signatures
+
+```python
+from cryptography.hazmat.primitives import hashes
+from cryptography.hazmat.primitives.asymmetric import rsa, padding
+from cryptography.hazmat.primitives import serialization
+
+# Generate key pair
+private_key = rsa.generate_private_key(
+    public_exponent=65537,
+    key_size=4096,
+)
+public_key = private_key.public_key()
+
+def sign(message: bytes, private_key) -> bytes:
+    """Sign message with RSA."""
+    return private_key.sign(
+        message,
+        padding.PSS(
+            mgf=padding.MGF1(hashes.SHA256()),
+            salt_length=padding.PSS.MAX_LENGTH
+        ),
+        hashes.SHA256()
+    )
+
+def verify(message: bytes, signature: bytes, public_key) -> bool:
+    """Verify RSA signature."""
+    try:
+        public_key.verify(
+            signature,
+            message,
+            padding.PSS(
+                mgf=padding.MGF1(hashes.SHA256()),
+                salt_length=padding.PSS.MAX_LENGTH
+            ),
+            hashes.SHA256()
+        )
+        return True
+    except:
+        return False
+```
+
+### Ed25519 (Modern Alternative)
+
+```python
+from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
+
+# Generate keys
+private_key = Ed25519PrivateKey.generate()
+public_key = private_key.public_key()
+
+# Sign
+signature = private_key.sign(message)
+
+# Verify
+try:
+    public_key.verify(signature, message)
+    print("Valid signature")
+except:
+    print("Invalid signature")
+```
+
+## Secure Random
+
+```python
+import secrets
+import os
+
+# Cryptographically secure random bytes
+random_bytes = os.urandom(32)
+
+# Secure token generation
+token = secrets.token_hex(32)      # 64 hex chars
+token = secrets.token_urlsafe(32)  # URL-safe base64
+token = secrets.token_bytes(32)    # Raw bytes
+
+# Secure random integer
+pin = secrets.randbelow(1000000)   # 0-999999
+
+# Secure random choice
+selected = secrets.choice(options)
+```
+
+## Key Storage
+
+### Environment Variables
+
+```python
+import os
+
+# Load key from environment
+key = os.environ.get('ENCRYPTION_KEY')
+if not key:
+    raise RuntimeError("ENCRYPTION_KEY not set")
+key_bytes = bytes.fromhex(key)
+```
+
+### Key Management Service (AWS KMS)
+
+```python
+import boto3
+
+kms = boto3.client('kms')
+
+def encrypt_with_kms(plaintext: bytes, key_id: str) -> bytes:
+    """Encrypt using AWS KMS."""
+    response = kms.encrypt(
+        KeyId=key_id,
+        Plaintext=plaintext,
+    )
+    return response['CiphertextBlob']
+
+def decrypt_with_kms(ciphertext: bytes) -> bytes:
+    """Decrypt using AWS KMS."""
+    response = kms.decrypt(CiphertextBlob=ciphertext)
+    return response['Plaintext']
+```
+
+## Common Mistakes
+
+### DON'T: Use ECB Mode
+
+```python
+# WRONG - ECB reveals patterns
+cipher = Cipher(algorithms.AES(key), modes.ECB())
+
+# CORRECT - Use GCM or CBC with HMAC
+cipher = Cipher(algorithms.AES(key), modes.GCM(iv))
+```
+
+### DON'T: Reuse Nonces/IVs
+
+```python
+# WRONG - Static IV
+iv = b'1234567890123456'
+
+# CORRECT - Random IV each time
+iv = os.urandom(16)
+```
+
+### DON'T: Roll Your Own Crypto
+
+```python
+# WRONG - Custom encryption
+def encrypt(data, key):
+    return bytes([b ^ key[i % len(key)] for i, b in enumerate(data)])
+
+# CORRECT - Use established libraries
+from cryptography.fernet import Fernet
+```
+
+### DON'T: Use MD5 or SHA1 for Security
+
+```python
+# WRONG - Weak hash
+import hashlib
+hash = hashlib.md5(password.encode())
+
+# CORRECT - Use bcrypt for passwords
+import bcrypt
+hash = bcrypt.hashpw(password.encode(), bcrypt.gensalt())
+```
+
+## Quick Reference
+
+| Purpose | Algorithm | Library |
+|---------|-----------|---------|
+| Password hashing | bcrypt, Argon2 | `bcrypt`, `argon2-cffi` |
+| Symmetric encryption | AES-256-GCM | `cryptography` |
+| Key derivation | PBKDF2, Argon2 | `cryptography`, `argon2` |
+| Data integrity | SHA-256 | `hashlib` |
+| Message auth | HMAC-SHA256 | `hmac` |
+| Digital signatures | Ed25519, RSA-PSS | `cryptography` |
+| Random bytes | CSPRNG | `secrets`, `os.urandom` |

+ 329 - 0
skills/security-patterns/references/owasp-detailed.md

@@ -0,0 +1,329 @@
+# OWASP Top 10 Detailed Guide
+
+In-depth coverage of OWASP Top 10 2021 vulnerabilities.
+
+## A01: Broken Access Control
+
+### Description
+Access control enforces policy such that users cannot act outside their intended permissions.
+
+### Examples
+- Bypassing access control by modifying URL, state, or HTML
+- Viewing or editing someone else's account
+- Privilege escalation (acting as user without login, or user acting as admin)
+- Metadata manipulation (replay/tampering JWT, cookies, hidden fields)
+- CORS misconfiguration allowing unauthorized API access
+- Force browsing to authenticated pages or privileged pages
+
+### Prevention
+
+```python
+# WRONG - Client-side check only
+if user.role == "admin":
+    show_admin_button()
+
+# CORRECT - Server-side enforcement
+@app.route("/admin/users")
+def admin_users():
+    if not current_user.has_role("admin"):
+        abort(403)
+    return render_template("admin/users.html")
+
+# CORRECT - Deny by default
+def get_resource(resource_id):
+    resource = Resource.get(resource_id)
+    if resource.owner_id != current_user.id:
+        raise Forbidden("Not your resource")
+    return resource
+```
+
+### Checklist
+- [ ] Deny by default except for public resources
+- [ ] Implement access control once, reuse everywhere
+- [ ] Record access control failures, alert on repeated attempts
+- [ ] Disable web server directory listing
+- [ ] Ensure file metadata not accessible
+
+## A02: Cryptographic Failures
+
+### Description
+Failures related to cryptography leading to exposure of sensitive data.
+
+### Examples
+- Data transmitted in clear text (HTTP, SMTP, FTP)
+- Old/weak cryptographic algorithms (MD5, SHA1, DES)
+- Default or weak crypto keys
+- Improper certificate validation
+- Passwords stored without salted hashing
+
+### Prevention
+
+```python
+# WRONG - Weak hashing
+import hashlib
+password_hash = hashlib.md5(password.encode()).hexdigest()
+
+# CORRECT - bcrypt with cost factor
+import bcrypt
+password_hash = bcrypt.hashpw(password.encode(), bcrypt.gensalt(rounds=12))
+
+# WRONG - ECB mode
+from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
+cipher = Cipher(algorithms.AES(key), modes.ECB())
+
+# CORRECT - GCM mode with random IV
+cipher = Cipher(algorithms.AES(key), modes.GCM(iv))
+```
+
+### Checklist
+- [ ] Classify data by sensitivity
+- [ ] Don't store sensitive data unnecessarily
+- [ ] Encrypt all sensitive data at rest
+- [ ] Use TLS for all data in transit
+- [ ] Use strong, standard algorithms
+- [ ] Store passwords with bcrypt, scrypt, Argon2, or PBKDF2
+
+## A03: Injection
+
+### Description
+Hostile data sent to an interpreter as part of a command or query.
+
+### Examples
+- SQL Injection
+- NoSQL Injection
+- OS Command Injection
+- LDAP Injection
+- XPath Injection
+- Template Injection
+
+### Prevention
+
+```python
+# WRONG - SQL Injection
+query = f"SELECT * FROM users WHERE name = '{name}'"
+
+# CORRECT - Parameterized query
+cursor.execute("SELECT * FROM users WHERE name = ?", [name])
+
+# WRONG - Command Injection
+os.system(f"ping {host}")
+
+# CORRECT - Use subprocess with list
+subprocess.run(["ping", "-c", "4", host], capture_output=True)
+
+# WRONG - Template Injection
+template = Template(user_input)
+
+# CORRECT - Safe templating
+template = env.get_template("page.html")
+template.render(user_data=user_input)
+```
+
+### Detection Patterns
+
+```bash
+# Find SQL injection risks
+rg "execute\(f['\"]|format\(|\.format\(" --type py
+
+# Find command injection
+rg "os\.system\(|subprocess\.(run|call|Popen)\([^,\[]*\+" --type py
+```
+
+## A04: Insecure Design
+
+### Description
+Missing or ineffective security controls from design phase.
+
+### Prevention
+- Use threat modeling during design
+- Integrate security requirements in user stories
+- Use secure design patterns
+- Write unit and integration tests for security controls
+- Segregate tenants robustly
+
+## A05: Security Misconfiguration
+
+### Description
+Missing or improper security hardening across the application stack.
+
+### Examples
+- Default accounts enabled
+- Unnecessary features enabled
+- Error messages revealing stack traces
+- Missing security headers
+- Out of date software
+
+### Prevention
+
+```yaml
+# Secure headers middleware
+security_headers:
+  Content-Security-Policy: "default-src 'self'"
+  X-Frame-Options: "DENY"
+  X-Content-Type-Options: "nosniff"
+  Strict-Transport-Security: "max-age=31536000"
+
+# Disable debug in production
+DEBUG: false
+ALLOWED_HOSTS: ["example.com"]
+```
+
+## A06: Vulnerable and Outdated Components
+
+### Description
+Using components with known vulnerabilities.
+
+### Prevention
+
+```bash
+# Python - pip audit
+pip install pip-audit
+pip-audit
+
+# JavaScript - npm audit
+npm audit
+npm audit fix
+
+# General - Snyk
+snyk test
+snyk monitor
+
+# GitHub Dependabot
+# .github/dependabot.yml
+version: 2
+updates:
+  - package-ecosystem: "pip"
+    directory: "/"
+    schedule:
+      interval: "weekly"
+```
+
+## A07: Identification and Authentication Failures
+
+### Description
+Confirmation of user's identity and session management weaknesses.
+
+### Examples
+- Permits brute force attacks
+- Permits weak passwords
+- Weak credential recovery
+- Plain text or weakly hashed passwords
+- Missing MFA
+- Session IDs in URL
+
+### Prevention
+
+```python
+# Rate limiting
+from flask_limiter import Limiter
+
+limiter = Limiter(app, key_func=get_remote_address)
+
+@app.route("/login", methods=["POST"])
+@limiter.limit("5 per minute")
+def login():
+    # Login logic
+
+# Secure session configuration
+app.config.update(
+    SESSION_COOKIE_SECURE=True,
+    SESSION_COOKIE_HTTPONLY=True,
+    SESSION_COOKIE_SAMESITE='Strict',
+    PERMANENT_SESSION_LIFETIME=timedelta(hours=1)
+)
+```
+
+## A08: Software and Data Integrity Failures
+
+### Description
+Code and infrastructure without integrity verification.
+
+### Examples
+- Insecure CI/CD pipeline
+- Auto-update without verification
+- Untrusted deserialization
+
+### Prevention
+
+```python
+# WRONG - Pickle from untrusted source
+import pickle
+data = pickle.loads(user_input)  # RCE vulnerability!
+
+# CORRECT - Use JSON for untrusted data
+import json
+data = json.loads(user_input)
+
+# Verify signatures
+import hmac
+
+def verify_webhook(payload, signature, secret):
+    expected = hmac.new(secret, payload, 'sha256').hexdigest()
+    return hmac.compare_digest(expected, signature)
+```
+
+## A09: Security Logging and Monitoring Failures
+
+### Description
+Without logging and monitoring, breaches cannot be detected.
+
+### What to Log
+- Login successes and failures
+- Access control failures
+- Input validation failures
+- High-value transactions
+
+### Prevention
+
+```python
+import logging
+
+security_logger = logging.getLogger("security")
+
+def login(username, password):
+    user = authenticate(username, password)
+    if user:
+        security_logger.info(f"Login success: {username}")
+        return user
+    else:
+        security_logger.warning(f"Login failed: {username}")
+        raise AuthenticationError()
+
+# Alert on suspicious patterns
+if failed_logins_count > 10:
+    security_logger.critical(f"Brute force detected: {ip_address}")
+    alert_security_team(ip_address)
+```
+
+## A10: Server-Side Request Forgery (SSRF)
+
+### Description
+Application fetches remote resource without validating user-supplied URL.
+
+### Examples
+- Accessing internal services
+- Reading cloud metadata
+- Port scanning internal network
+
+### Prevention
+
+```python
+# WRONG - Direct URL fetch
+import requests
+
+def fetch(url):
+    return requests.get(url)  # Can fetch internal URLs!
+
+# CORRECT - Validate URL
+from urllib.parse import urlparse
+
+ALLOWED_HOSTS = {"api.example.com", "cdn.example.com"}
+
+def fetch(url):
+    parsed = urlparse(url)
+    if parsed.hostname not in ALLOWED_HOSTS:
+        raise ValueError("Host not allowed")
+    if parsed.scheme not in ("http", "https"):
+        raise ValueError("Scheme not allowed")
+    return requests.get(url)
+```

+ 240 - 0
skills/security-patterns/references/secure-headers.md

@@ -0,0 +1,240 @@
+# HTTP Security Headers
+
+Essential security headers for web applications.
+
+## Complete Header Set
+
+```
+Content-Security-Policy: default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self'; connect-src 'self' https://api.example.com; frame-ancestors 'none'; base-uri 'self'; form-action 'self'
+X-Content-Type-Options: nosniff
+X-Frame-Options: DENY
+Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
+Referrer-Policy: strict-origin-when-cross-origin
+Permissions-Policy: accelerometer=(), camera=(), geolocation=(), gyroscope=(), magnetometer=(), microphone=(), payment=(), usb=()
+X-XSS-Protection: 0
+```
+
+## Content-Security-Policy (CSP)
+
+### Basic CSP
+
+```
+Content-Security-Policy: default-src 'self'
+```
+
+### Detailed CSP Directives
+
+| Directive | Purpose | Example |
+|-----------|---------|---------|
+| `default-src` | Fallback for other directives | `'self'` |
+| `script-src` | JavaScript sources | `'self' https://cdn.example.com` |
+| `style-src` | CSS sources | `'self' 'unsafe-inline'` |
+| `img-src` | Image sources | `'self' data: https:` |
+| `font-src` | Font sources | `'self' https://fonts.gstatic.com` |
+| `connect-src` | AJAX, WebSocket, fetch | `'self' https://api.example.com` |
+| `frame-src` | iframe sources | `'none'` |
+| `frame-ancestors` | Who can embed this page | `'none'` |
+| `base-uri` | Restrict base element | `'self'` |
+| `form-action` | Form submission targets | `'self'` |
+| `upgrade-insecure-requests` | Upgrade HTTP to HTTPS | (no value) |
+
+### CSP Values
+
+```
+'self'          - Same origin
+'none'          - Block all
+'unsafe-inline' - Allow inline (avoid!)
+'unsafe-eval'   - Allow eval() (avoid!)
+'strict-dynamic' - Trust scripts loaded by trusted scripts
+'nonce-abc123'  - Allow specific inline with nonce
+'sha256-...'    - Allow specific inline by hash
+https:          - Any HTTPS URL
+data:           - Data URLs
+```
+
+### CSP for Common Frameworks
+
+#### React/Vue/Angular (Production)
+
+```
+Content-Security-Policy: default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self' data:; connect-src 'self' https://api.yourapp.com
+```
+
+#### With CDN
+
+```
+Content-Security-Policy: default-src 'self'; script-src 'self' https://cdn.jsdelivr.net; style-src 'self' 'unsafe-inline' https://cdn.jsdelivr.net
+```
+
+### Report-Only Mode
+
+```
+Content-Security-Policy-Report-Only: default-src 'self'; report-uri /csp-report
+```
+
+## Strict-Transport-Security (HSTS)
+
+```
+Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
+```
+
+- `max-age=31536000` - Browser remembers for 1 year
+- `includeSubDomains` - Apply to all subdomains
+- `preload` - Submit to browser preload lists
+
+### Implementation
+
+```python
+# Flask
+@app.after_request
+def add_hsts(response):
+    response.headers['Strict-Transport-Security'] = 'max-age=31536000; includeSubDomains'
+    return response
+
+# Express
+app.use(helmet.hsts({
+    maxAge: 31536000,
+    includeSubDomains: true,
+    preload: true
+}))
+```
+
+## X-Frame-Options
+
+```
+X-Frame-Options: DENY
+```
+
+- `DENY` - Never allow framing
+- `SAMEORIGIN` - Only same origin can frame
+- `ALLOW-FROM uri` - Specific origin (deprecated, use CSP)
+
+## X-Content-Type-Options
+
+```
+X-Content-Type-Options: nosniff
+```
+
+Prevents MIME type sniffing. Always use this.
+
+## Referrer-Policy
+
+```
+Referrer-Policy: strict-origin-when-cross-origin
+```
+
+| Value | Behavior |
+|-------|----------|
+| `no-referrer` | Never send referrer |
+| `same-origin` | Only to same origin |
+| `strict-origin` | Send origin only, not path |
+| `strict-origin-when-cross-origin` | Full URL same-origin, origin cross-origin |
+
+## Permissions-Policy
+
+```
+Permissions-Policy: accelerometer=(), camera=(), geolocation=(), gyroscope=(), magnetometer=(), microphone=(), payment=(), usb=()
+```
+
+Disable browser features you don't use:
+
+```
+Permissions-Policy:
+  camera=(),              # Disable camera
+  microphone=(),          # Disable microphone
+  geolocation=(self),     # Only this origin
+  payment=*               # Allow all
+```
+
+## Implementation Examples
+
+### Python Flask
+
+```python
+from flask import Flask
+
+app = Flask(__name__)
+
+@app.after_request
+def add_security_headers(response):
+    response.headers['Content-Security-Policy'] = "default-src 'self'"
+    response.headers['X-Content-Type-Options'] = 'nosniff'
+    response.headers['X-Frame-Options'] = 'DENY'
+    response.headers['Strict-Transport-Security'] = 'max-age=31536000; includeSubDomains'
+    response.headers['Referrer-Policy'] = 'strict-origin-when-cross-origin'
+    return response
+```
+
+### Python FastAPI
+
+```python
+from fastapi import FastAPI
+from starlette.middleware import Middleware
+from starlette.middleware.httpsredirect import HTTPSRedirectMiddleware
+
+app = FastAPI()
+
+@app.middleware("http")
+async def add_security_headers(request, call_next):
+    response = await call_next(request)
+    response.headers["Content-Security-Policy"] = "default-src 'self'"
+    response.headers["X-Content-Type-Options"] = "nosniff"
+    response.headers["X-Frame-Options"] = "DENY"
+    return response
+```
+
+### Node.js Express (Helmet)
+
+```javascript
+const helmet = require('helmet');
+
+app.use(helmet());
+
+// Or with custom config
+app.use(helmet({
+    contentSecurityPolicy: {
+        directives: {
+            defaultSrc: ["'self'"],
+            scriptSrc: ["'self'", "cdn.example.com"],
+        }
+    },
+    hsts: {
+        maxAge: 31536000,
+        includeSubDomains: true,
+    }
+}));
+```
+
+### Nginx
+
+```nginx
+add_header Content-Security-Policy "default-src 'self'" always;
+add_header X-Content-Type-Options "nosniff" always;
+add_header X-Frame-Options "DENY" always;
+add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
+add_header Referrer-Policy "strict-origin-when-cross-origin" always;
+```
+
+## Testing Headers
+
+```bash
+# Check headers with curl
+curl -I https://example.com
+
+# Security header scanner
+# https://securityheaders.com
+
+# Mozilla Observatory
+# https://observatory.mozilla.org
+```
+
+## Quick Checklist
+
+- [ ] CSP with restrictive default-src
+- [ ] HSTS with 1 year max-age
+- [ ] X-Frame-Options: DENY
+- [ ] X-Content-Type-Options: nosniff
+- [ ] Referrer-Policy set
+- [ ] Permissions-Policy restricting unused features
+- [ ] No X-Powered-By header (remove it)
+- [ ] Test with securityheaders.com

+ 90 - 0
skills/security-patterns/scripts/dependency-audit.sh

@@ -0,0 +1,90 @@
+#!/bin/bash
+# Audit dependencies for known vulnerabilities
+# Usage: ./dependency-audit.sh
+
+set -e
+
+RED='\033[0;31m'
+GREEN='\033[0;32m'
+YELLOW='\033[1;33m'
+NC='\033[0m'
+
+echo "=== Dependency Security Audit ==="
+echo ""
+
+# Python
+if [ -f "requirements.txt" ] || [ -f "pyproject.toml" ]; then
+    echo "--- Python Dependencies ---"
+
+    if command -v pip-audit &> /dev/null; then
+        echo "Running pip-audit..."
+        pip-audit || true
+    elif command -v safety &> /dev/null; then
+        echo "Running safety check..."
+        safety check || true
+    else
+        echo -e "${YELLOW}Install pip-audit or safety for Python vulnerability scanning${NC}"
+        echo "  pip install pip-audit"
+    fi
+    echo ""
+fi
+
+# Node.js
+if [ -f "package.json" ]; then
+    echo "--- Node.js Dependencies ---"
+
+    if command -v npm &> /dev/null; then
+        echo "Running npm audit..."
+        npm audit --audit-level=moderate || true
+    fi
+    echo ""
+fi
+
+# Go
+if [ -f "go.mod" ]; then
+    echo "--- Go Dependencies ---"
+
+    if command -v govulncheck &> /dev/null; then
+        echo "Running govulncheck..."
+        govulncheck ./... || true
+    else
+        echo -e "${YELLOW}Install govulncheck for Go vulnerability scanning${NC}"
+        echo "  go install golang.org/x/vuln/cmd/govulncheck@latest"
+    fi
+    echo ""
+fi
+
+# Rust
+if [ -f "Cargo.toml" ]; then
+    echo "--- Rust Dependencies ---"
+
+    if command -v cargo-audit &> /dev/null; then
+        echo "Running cargo audit..."
+        cargo audit || true
+    else
+        echo -e "${YELLOW}Install cargo-audit for Rust vulnerability scanning${NC}"
+        echo "  cargo install cargo-audit"
+    fi
+    echo ""
+fi
+
+# Docker
+if [ -f "Dockerfile" ]; then
+    echo "--- Docker Image ---"
+
+    if command -v trivy &> /dev/null; then
+        echo "Running trivy on Dockerfile..."
+        trivy config Dockerfile || true
+    else
+        echo -e "${YELLOW}Install trivy for container vulnerability scanning${NC}"
+        echo "  brew install trivy"
+    fi
+    echo ""
+fi
+
+echo "=== Audit Complete ==="
+echo ""
+echo "Recommended actions:"
+echo "1. Update vulnerable packages to patched versions"
+echo "2. Review advisories for workarounds if updates unavailable"
+echo "3. Consider alternative packages for unmaintained dependencies"

+ 89 - 0
skills/security-patterns/scripts/security-scan.sh

@@ -0,0 +1,89 @@
+#!/bin/bash
+# Quick security scan using grep patterns
+# Usage: ./security-scan.sh [directory]
+
+set -e
+
+DIR="${1:-.}"
+
+RED='\033[0;31m'
+YELLOW='\033[1;33m'
+GREEN='\033[0;32m'
+NC='\033[0m'
+
+echo "=== Security Scan: $DIR ==="
+echo ""
+
+ISSUES=0
+
+check_pattern() {
+    local name="$1"
+    local pattern="$2"
+    local type="$3"
+
+    echo -n "Checking: $name... "
+
+    if rg -l "$pattern" "$DIR" --type "$type" 2>/dev/null | head -5 | grep -q .; then
+        echo -e "${RED}FOUND${NC}"
+        rg -n "$pattern" "$DIR" --type "$type" 2>/dev/null | head -10
+        echo ""
+        ISSUES=$((ISSUES + 1))
+    else
+        echo -e "${GREEN}OK${NC}"
+    fi
+}
+
+# Python checks
+echo "--- Python Security Checks ---"
+check_pattern "Hardcoded secrets" "(password|secret|api_key|token)\s*=\s*['\"][^'\"]{8,}['\"]" "py"
+check_pattern "SQL injection (f-strings)" "execute\(f['\"]" "py"
+check_pattern "SQL injection (format)" "execute\(.*\.format\(" "py"
+check_pattern "eval() usage" "\beval\s*\(" "py"
+check_pattern "exec() usage" "\bexec\s*\(" "py"
+check_pattern "pickle.loads" "pickle\.loads?\(" "py"
+check_pattern "os.system" "os\.system\(" "py"
+check_pattern "shell=True" "subprocess.*shell\s*=\s*True" "py"
+check_pattern "MD5 hashing" "hashlib\.md5\(" "py"
+check_pattern "SHA1 hashing" "hashlib\.sha1\(" "py"
+
+echo ""
+
+# JavaScript checks
+echo "--- JavaScript Security Checks ---"
+check_pattern "innerHTML" "\.innerHTML\s*=" "js"
+check_pattern "eval() usage" "\beval\s*\(" "js"
+check_pattern "document.write" "document\.write\(" "js"
+
+echo ""
+
+# General checks
+echo "--- General Security Checks ---"
+
+echo -n "Checking: .env files in git... "
+if git ls-files | grep -E "\.env$|\.env\." | grep -q .; then
+    echo -e "${RED}FOUND${NC}"
+    git ls-files | grep -E "\.env$|\.env\."
+    ISSUES=$((ISSUES + 1))
+else
+    echo -e "${GREEN}OK${NC}"
+fi
+
+echo -n "Checking: TODO/FIXME security items... "
+if rg -i "TODO.*security|FIXME.*security|HACK.*security" "$DIR" 2>/dev/null | head -5 | grep -q .; then
+    echo -e "${YELLOW}FOUND${NC}"
+    rg -i "TODO.*security|FIXME.*security|HACK.*security" "$DIR" 2>/dev/null | head -10
+    ISSUES=$((ISSUES + 1))
+else
+    echo -e "${GREEN}OK${NC}"
+fi
+
+echo ""
+echo "=== Summary ==="
+if [ $ISSUES -eq 0 ]; then
+    echo -e "${GREEN}No issues found!${NC}"
+    exit 0
+else
+    echo -e "${RED}Found $ISSUES potential security issues${NC}"
+    echo "Review the findings above and address any real vulnerabilities."
+    exit 1
+fi

+ 38 - 162
skills/sql-patterns/SKILL.md

@@ -6,11 +6,10 @@ allowed-tools: "Read Write"
 
 # SQL Patterns
 
-Quick reference for common SQL patterns, CTEs, window functions, and indexing strategies.
+Quick reference for common SQL patterns.
 
 ## CTE (Common Table Expressions)
 
-### Basic CTE
 ```sql
 WITH active_users AS (
     SELECT id, name, email
@@ -21,6 +20,7 @@ SELECT * FROM active_users WHERE created_at > '2024-01-01';
 ```
 
 ### Chained CTEs
+
 ```sql
 WITH
     active_users AS (
@@ -28,197 +28,73 @@ WITH
     ),
     user_orders AS (
         SELECT user_id, COUNT(*) as order_count
-        FROM orders
-        GROUP BY user_id
+        FROM orders GROUP BY user_id
     )
 SELECT u.name, COALESCE(o.order_count, 0) as orders
 FROM active_users u
 LEFT JOIN user_orders o ON u.id = o.user_id;
 ```
 
-### Recursive CTE (Hierarchies)
-```sql
-WITH RECURSIVE org_tree AS (
-    -- Base case: top-level managers
-    SELECT id, name, manager_id, 1 as level
-    FROM employees
-    WHERE manager_id IS NULL
-
-    UNION ALL
-
-    -- Recursive case: employees under managers
-    SELECT e.id, e.name, e.manager_id, t.level + 1
-    FROM employees e
-    JOIN org_tree t ON e.manager_id = t.id
-)
-SELECT * FROM org_tree ORDER BY level, name;
-```
-
-## Window Functions
-
-### ROW_NUMBER (Unique sequential)
-```sql
-SELECT
-    name,
-    department,
-    salary,
-    ROW_NUMBER() OVER (PARTITION BY department ORDER BY salary DESC) as rank
-FROM employees;
-```
+## Window Functions (Quick Reference)
 
-### RANK / DENSE_RANK (Ties allowed)
-```sql
--- RANK: 1, 2, 2, 4 (skips after ties)
--- DENSE_RANK: 1, 2, 2, 3 (no skip)
-SELECT
-    name,
-    score,
-    RANK() OVER (ORDER BY score DESC) as rank,
-    DENSE_RANK() OVER (ORDER BY score DESC) as dense_rank
-FROM contestants;
-```
+| Function | Use |
+|----------|-----|
+| `ROW_NUMBER()` | Unique sequential numbering |
+| `RANK()` | Rank with gaps (1, 2, 2, 4) |
+| `DENSE_RANK()` | Rank without gaps (1, 2, 2, 3) |
+| `LAG(col, n)` | Previous row value |
+| `LEAD(col, n)` | Next row value |
+| `SUM() OVER` | Running total |
+| `AVG() OVER` | Moving average |
 
-### LAG / LEAD (Previous/Next row)
 ```sql
 SELECT
     date,
     revenue,
     LAG(revenue, 1) OVER (ORDER BY date) as prev_day,
-    revenue - LAG(revenue, 1) OVER (ORDER BY date) as change
+    SUM(revenue) OVER (ORDER BY date) as running_total
 FROM daily_sales;
 ```
 
-### Running Total
-```sql
-SELECT
-    date,
-    amount,
-    SUM(amount) OVER (ORDER BY date) as running_total
-FROM transactions;
-```
-
-### Moving Average
-```sql
-SELECT
-    date,
-    value,
-    AVG(value) OVER (ORDER BY date ROWS BETWEEN 6 PRECEDING AND CURRENT ROW) as moving_avg_7day
-FROM metrics;
-```
-
 ## JOIN Reference
 
 | Type | Returns |
 |------|---------|
-| `INNER JOIN` | Only matching rows from both |
-| `LEFT JOIN` | All from left + matching from right |
-| `RIGHT JOIN` | All from right + matching from left |
-| `FULL JOIN` | All from both, NULL where no match |
-| `CROSS JOIN` | Cartesian product (all combinations) |
-
-### Self Join (Same table)
-```sql
-SELECT e.name as employee, m.name as manager
-FROM employees e
-LEFT JOIN employees m ON e.manager_id = m.id;
-```
-
-## Pagination Patterns
+| `INNER JOIN` | Only matching rows |
+| `LEFT JOIN` | All left + matching right |
+| `RIGHT JOIN` | All right + matching left |
+| `FULL JOIN` | All rows, NULL where no match |
 
-### OFFSET/LIMIT (Simple, slow for large offsets)
-```sql
-SELECT * FROM products
-ORDER BY id
-LIMIT 20 OFFSET 40;  -- Page 3, 20 per page
-```
+## Pagination
 
-### Keyset Pagination (Fast, scalable)
 ```sql
--- First page
-SELECT * FROM products ORDER BY id LIMIT 20;
+-- OFFSET/LIMIT (simple, slow for large offsets)
+SELECT * FROM products ORDER BY id LIMIT 20 OFFSET 40;
 
--- Next page (where last id was 42)
+-- Keyset (fast, scalable)
 SELECT * FROM products WHERE id > 42 ORDER BY id LIMIT 20;
 ```
 
-## Index Strategies
+## Index Quick Reference
 
 | Index Type | Best For |
 |------------|----------|
-| **B-tree** | Default, range queries, ORDER BY |
-| **Hash** | Exact equality only |
-| **GIN** | Arrays, JSONB, full-text |
-| **GiST** | Geometric, full-text |
-| **Covering** | Include columns to avoid table lookup |
-
-### Covering Index
-```sql
--- Query needs name but filters on email
-CREATE INDEX idx_users_email_name ON users(email) INCLUDE (name);
-
--- Now this is index-only:
-SELECT name FROM users WHERE email = 'x@y.com';
-```
-
-### Composite Index Order
-```sql
--- Leftmost prefix rule: (a, b, c) supports:
--- WHERE a = ?
--- WHERE a = ? AND b = ?
--- WHERE a = ? AND b = ? AND c = ?
--- NOT: WHERE b = ? (a must be present)
-CREATE INDEX idx_orders ON orders(user_id, status, created_at);
-```
-
-## EXISTS vs IN
+| B-tree | Range queries, ORDER BY |
+| Hash | Exact equality only |
+| GIN | Arrays, JSONB, full-text |
+| Covering | Avoid table lookup |
 
-```sql
--- EXISTS: Often faster for large outer, small inner
-SELECT * FROM orders o
-WHERE EXISTS (SELECT 1 FROM users u WHERE u.id = o.user_id AND u.status = 'active');
-
--- IN: Often faster for small list, can be optimized
-SELECT * FROM orders
-WHERE user_id IN (SELECT id FROM users WHERE status = 'active');
-```
-
-## Anti-Patterns to Avoid
-
-| Anti-Pattern | Problem | Fix |
-|--------------|---------|-----|
-| `SELECT *` | Over-fetches, breaks on schema change | List columns explicitly |
-| Function on indexed column | `WHERE YEAR(date) = 2024` prevents index | `WHERE date >= '2024-01-01'` |
-| `OR` in WHERE | May prevent index usage | Use `UNION` or rewrite |
-| N+1 queries | Loop with query per item | Single JOIN or batch |
-| `DISTINCT` to fix duplicates | Masks JOIN issues | Fix the JOIN logic |
-| `NOT IN` with NULLs | Returns wrong results | Use `NOT EXISTS` instead |
-
-## NULL Handling
+## Anti-Patterns
 
-```sql
--- NULL comparisons
-WHERE column IS NULL        -- Correct
-WHERE column IS NOT NULL    -- Correct
-WHERE column = NULL         -- WRONG (always false)
-
--- COALESCE for defaults
-SELECT COALESCE(nickname, name, 'Anonymous') as display_name FROM users;
-
--- NULLIF to create NULLs
-SELECT amount / NULLIF(count, 0) as average FROM stats;  -- Avoids divide by zero
-```
+| Mistake | Fix |
+|---------|-----|
+| `SELECT *` | List columns explicitly |
+| `WHERE YEAR(date) = 2024` | `WHERE date >= '2024-01-01'` |
+| `NOT IN` with NULLs | Use `NOT EXISTS` |
+| N+1 queries | Use JOIN or batch |
 
-## Batch Operations
+## Additional Resources
 
-```sql
--- Insert multiple rows
-INSERT INTO users (name, email) VALUES
-    ('Alice', 'a@x.com'),
-    ('Bob', 'b@x.com'),
-    ('Carol', 'c@x.com');
-
--- Update with limit (process in batches)
-UPDATE orders SET status = 'archived'
-WHERE status = 'completed' AND updated_at < '2023-01-01'
-LIMIT 1000;
-```
+For detailed patterns, load:
+- `./references/window-functions.md` - Complete window function patterns
+- `./references/indexing-strategies.md` - Index types, covering indexes, optimization

+ 297 - 0
skills/sql-patterns/references/indexing-strategies.md

@@ -0,0 +1,297 @@
+# SQL Indexing Strategies
+
+Comprehensive guide to database indexing for query optimization.
+
+## Index Types
+
+### B-Tree (Default)
+
+Best for: range queries, equality, ORDER BY, LIKE prefix
+
+```sql
+-- Standard index
+CREATE INDEX idx_users_email ON users(email);
+
+-- Unique index
+CREATE UNIQUE INDEX idx_users_email ON users(email);
+
+-- Works well for:
+WHERE email = 'x@y.com'           -- equality
+WHERE email LIKE 'john%'          -- prefix search
+WHERE created_at > '2024-01-01'   -- range
+ORDER BY created_at               -- sorting
+```
+
+### Hash Index
+
+Best for: exact equality only (PostgreSQL)
+
+```sql
+CREATE INDEX idx_users_email ON users USING hash(email);
+
+-- Only good for:
+WHERE email = 'x@y.com'
+
+-- NOT useful for:
+WHERE email LIKE '%@gmail.com'
+WHERE email > 'a'
+ORDER BY email
+```
+
+### GIN (Generalized Inverted Index)
+
+Best for: arrays, JSONB, full-text search
+
+```sql
+-- Array containment
+CREATE INDEX idx_posts_tags ON posts USING gin(tags);
+WHERE tags @> ARRAY['python', 'sql']
+
+-- JSONB queries
+CREATE INDEX idx_data_json ON events USING gin(payload jsonb_path_ops);
+WHERE payload @> '{"type": "click"}'
+
+-- Full-text search
+CREATE INDEX idx_posts_fts ON posts USING gin(to_tsvector('english', content));
+WHERE to_tsvector('english', content) @@ to_tsquery('database & optimization')
+```
+
+### GiST (Generalized Search Tree)
+
+Best for: geometric data, ranges, full-text
+
+```sql
+-- Range types
+CREATE INDEX idx_bookings_dates ON bookings USING gist(daterange(start_date, end_date));
+WHERE daterange(start_date, end_date) && '[2024-01-01, 2024-01-31]'
+
+-- Geometric
+CREATE INDEX idx_locations_point ON locations USING gist(coordinates);
+WHERE coordinates <-> point(40.7, -74.0) < 10
+```
+
+## Composite Indexes
+
+### Column Order Matters
+
+```sql
+-- Leftmost prefix rule
+CREATE INDEX idx_orders ON orders(user_id, status, created_at);
+
+-- This index supports:
+WHERE user_id = 123                              -- ✓
+WHERE user_id = 123 AND status = 'pending'       -- ✓
+WHERE user_id = 123 AND status = 'pending' AND created_at > '2024-01-01'  -- ✓
+WHERE user_id = 123 AND created_at > '2024-01-01'  -- Partial (user_id only)
+WHERE status = 'pending'                          -- ✗ (user_id not present)
+```
+
+### Optimal Column Order
+
+```sql
+-- Rule: Most selective first, then equality, then range
+-- If filtering by status (high cardinality) and date range:
+CREATE INDEX idx_orders_status_date ON orders(status, created_at);
+
+-- If status has few values, but user_id is selective:
+CREATE INDEX idx_orders_user_status_date ON orders(user_id, status, created_at);
+```
+
+## Covering Indexes
+
+Include columns to avoid table lookup:
+
+```sql
+-- Query needs name but filters by email
+SELECT name FROM users WHERE email = 'x@y.com';
+
+-- Covering index (PostgreSQL)
+CREATE INDEX idx_users_email_name ON users(email) INCLUDE (name);
+
+-- Now the query uses index-only scan
+-- (no need to read the actual table row)
+```
+
+### When to Use
+
+```sql
+-- Frequently accessed columns
+CREATE INDEX idx_orders_status ON orders(status)
+INCLUDE (total, created_at);
+
+-- Supports without table access:
+SELECT total, created_at FROM orders WHERE status = 'pending';
+```
+
+## Partial Indexes
+
+Index only rows matching a condition:
+
+```sql
+-- Only index active users (smaller, faster index)
+CREATE INDEX idx_users_active ON users(email)
+WHERE status = 'active';
+
+-- Only works for queries that include the condition:
+SELECT * FROM users WHERE email = 'x@y.com' AND status = 'active';  -- ✓
+SELECT * FROM users WHERE email = 'x@y.com';                        -- ✗
+
+-- Index only recent data
+CREATE INDEX idx_orders_recent ON orders(created_at)
+WHERE created_at > '2024-01-01';
+```
+
+## Expression Indexes
+
+Index computed values:
+
+```sql
+-- Case-insensitive search
+CREATE INDEX idx_users_email_lower ON users(LOWER(email));
+WHERE LOWER(email) = 'john@example.com'  -- ✓
+WHERE email = 'John@Example.com'          -- ✗
+
+-- Date extraction
+CREATE INDEX idx_orders_year ON orders(EXTRACT(YEAR FROM created_at));
+WHERE EXTRACT(YEAR FROM created_at) = 2024  -- ✓
+WHERE created_at >= '2024-01-01'            -- ✗ (use regular index)
+
+-- JSON field
+CREATE INDEX idx_events_type ON events((payload->>'type'));
+WHERE payload->>'type' = 'click'
+```
+
+## Query Analysis
+
+### EXPLAIN
+
+```sql
+EXPLAIN SELECT * FROM users WHERE email = 'x@y.com';
+
+-- Key things to look for:
+-- Seq Scan       - Full table scan (bad for large tables)
+-- Index Scan     - Using index, then fetching rows
+-- Index Only Scan - Using covering index (best)
+-- Bitmap Scan    - Multiple index conditions combined
+```
+
+### EXPLAIN ANALYZE
+
+```sql
+EXPLAIN ANALYZE SELECT * FROM orders WHERE status = 'pending';
+
+-- Shows actual execution:
+-- Planning Time: 0.5 ms
+-- Execution Time: 12.3 ms
+-- Rows: actual rows returned
+-- Loops: how many times operation ran
+```
+
+### Identifying Slow Queries
+
+```sql
+-- PostgreSQL: Enable slow query logging
+SET log_min_duration_statement = 1000;  -- Log queries > 1 second
+
+-- Find missing indexes (PostgreSQL)
+SELECT
+    schemaname || '.' || relname as table,
+    seq_scan,
+    seq_tup_read,
+    idx_scan,
+    seq_tup_read / NULLIF(seq_scan, 0) as avg_seq_rows
+FROM pg_stat_user_tables
+WHERE seq_scan > 0
+ORDER BY seq_tup_read DESC
+LIMIT 10;
+```
+
+## Anti-Patterns
+
+### Functions on Indexed Columns
+
+```sql
+-- BAD: Function prevents index use
+WHERE YEAR(created_at) = 2024
+
+-- GOOD: Rewrite as range
+WHERE created_at >= '2024-01-01' AND created_at < '2025-01-01'
+```
+
+### OR Conditions
+
+```sql
+-- BAD: May not use index efficiently
+WHERE status = 'pending' OR status = 'processing'
+
+-- GOOD: Use IN
+WHERE status IN ('pending', 'processing')
+
+-- Or use UNION for complex OR
+SELECT * FROM orders WHERE status = 'pending'
+UNION ALL
+SELECT * FROM orders WHERE user_id = 123 AND status != 'pending'
+```
+
+### Leading Wildcards
+
+```sql
+-- BAD: Can't use index
+WHERE email LIKE '%@gmail.com'
+
+-- GOOD: Use prefix
+WHERE email LIKE 'john%'
+
+-- Alternative: Full-text search or trigram index
+CREATE INDEX idx_email_trigram ON users USING gin(email gin_trgm_ops);
+```
+
+## Maintenance
+
+### Index Health
+
+```sql
+-- Check index usage (PostgreSQL)
+SELECT
+    indexrelname,
+    idx_scan,
+    idx_tup_read,
+    idx_tup_fetch
+FROM pg_stat_user_indexes
+WHERE idx_scan = 0  -- Unused indexes
+ORDER BY pg_relation_size(indexrelid) DESC;
+
+-- Index size
+SELECT
+    indexrelname,
+    pg_size_pretty(pg_relation_size(indexrelid)) as size
+FROM pg_stat_user_indexes
+ORDER BY pg_relation_size(indexrelid) DESC;
+```
+
+### Rebuild Indexes
+
+```sql
+-- Rebuild index (locks table)
+REINDEX INDEX idx_users_email;
+
+-- Concurrent rebuild (PostgreSQL 12+)
+REINDEX INDEX CONCURRENTLY idx_users_email;
+
+-- Rebuild all indexes on table
+REINDEX TABLE users;
+```
+
+## Quick Reference
+
+| Scenario | Index Strategy |
+|----------|---------------|
+| Equality lookup | B-tree on column |
+| Range queries | B-tree on column |
+| Multiple conditions | Composite index (selective first) |
+| Avoid table access | Covering index with INCLUDE |
+| Subset of rows | Partial index |
+| Case-insensitive | Expression index on LOWER() |
+| JSON/array queries | GIN index |
+| Full-text search | GIN with tsvector |
+| Geometric/range | GiST index |

+ 333 - 0
skills/sql-patterns/references/window-functions.md

@@ -0,0 +1,333 @@
+# SQL Window Functions
+
+Complete reference for window functions and analytical queries.
+
+## Core Window Functions
+
+### ROW_NUMBER
+
+Assigns unique sequential numbers within partition:
+
+```sql
+-- Rank employees by salary within department
+SELECT
+    name,
+    department,
+    salary,
+    ROW_NUMBER() OVER (PARTITION BY department ORDER BY salary DESC) as rank
+FROM employees;
+
+-- Get top N per group
+WITH ranked AS (
+    SELECT *,
+        ROW_NUMBER() OVER (PARTITION BY department ORDER BY salary DESC) as rn
+    FROM employees
+)
+SELECT * FROM ranked WHERE rn <= 3;
+```
+
+### RANK and DENSE_RANK
+
+Handle ties differently:
+
+```sql
+-- RANK: 1, 2, 2, 4 (skips after ties)
+-- DENSE_RANK: 1, 2, 2, 3 (no skip)
+SELECT
+    name,
+    score,
+    RANK() OVER (ORDER BY score DESC) as rank,
+    DENSE_RANK() OVER (ORDER BY score DESC) as dense_rank
+FROM contestants;
+
+-- Result for scores [100, 95, 95, 90]:
+-- name    score   rank   dense_rank
+-- Alice   100     1      1
+-- Bob     95      2      2
+-- Carol   95      2      2
+-- Dave    90      4      3
+```
+
+### NTILE
+
+Divide into N equal groups:
+
+```sql
+-- Divide into quartiles
+SELECT
+    name,
+    salary,
+    NTILE(4) OVER (ORDER BY salary) as quartile
+FROM employees;
+
+-- Percentile buckets
+SELECT
+    name,
+    score,
+    NTILE(100) OVER (ORDER BY score) as percentile
+FROM students;
+```
+
+## Navigation Functions
+
+### LAG and LEAD
+
+Access previous/next rows:
+
+```sql
+-- Previous and next day revenue
+SELECT
+    date,
+    revenue,
+    LAG(revenue, 1) OVER (ORDER BY date) as prev_day,
+    LEAD(revenue, 1) OVER (ORDER BY date) as next_day,
+    revenue - LAG(revenue, 1) OVER (ORDER BY date) as day_change
+FROM daily_sales;
+
+-- With default value for first/last
+SELECT
+    date,
+    revenue,
+    LAG(revenue, 1, 0) OVER (ORDER BY date) as prev_or_zero
+FROM daily_sales;
+
+-- Multiple periods back
+SELECT
+    date,
+    revenue,
+    LAG(revenue, 7) OVER (ORDER BY date) as same_day_last_week
+FROM daily_sales;
+```
+
+### FIRST_VALUE and LAST_VALUE
+
+Get first/last value in window:
+
+```sql
+-- Compare to first sale of month
+SELECT
+    date,
+    revenue,
+    FIRST_VALUE(revenue) OVER (
+        PARTITION BY DATE_TRUNC('month', date)
+        ORDER BY date
+    ) as first_day_revenue,
+    revenue - FIRST_VALUE(revenue) OVER (
+        PARTITION BY DATE_TRUNC('month', date)
+        ORDER BY date
+    ) as diff_from_first
+FROM daily_sales;
+
+-- Note: LAST_VALUE needs explicit frame
+SELECT
+    date,
+    revenue,
+    LAST_VALUE(revenue) OVER (
+        ORDER BY date
+        ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
+    ) as last_revenue
+FROM daily_sales;
+```
+
+### NTH_VALUE
+
+Get Nth value in window:
+
+```sql
+-- Get 2nd highest salary per department
+SELECT
+    department,
+    name,
+    salary,
+    NTH_VALUE(salary, 2) OVER (
+        PARTITION BY department
+        ORDER BY salary DESC
+        ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
+    ) as second_highest
+FROM employees;
+```
+
+## Aggregate Window Functions
+
+### Running Totals
+
+```sql
+-- Running total
+SELECT
+    date,
+    amount,
+    SUM(amount) OVER (ORDER BY date) as running_total
+FROM transactions;
+
+-- Running total by category
+SELECT
+    date,
+    category,
+    amount,
+    SUM(amount) OVER (
+        PARTITION BY category
+        ORDER BY date
+    ) as category_running_total
+FROM transactions;
+```
+
+### Moving Averages
+
+```sql
+-- 7-day moving average
+SELECT
+    date,
+    value,
+    AVG(value) OVER (
+        ORDER BY date
+        ROWS BETWEEN 6 PRECEDING AND CURRENT ROW
+    ) as moving_avg_7day
+FROM metrics;
+
+-- Centered moving average
+SELECT
+    date,
+    value,
+    AVG(value) OVER (
+        ORDER BY date
+        ROWS BETWEEN 3 PRECEDING AND 3 FOLLOWING
+    ) as centered_avg
+FROM metrics;
+```
+
+### Cumulative Statistics
+
+```sql
+-- Running count, sum, avg, min, max
+SELECT
+    date,
+    revenue,
+    COUNT(*) OVER (ORDER BY date) as cumulative_count,
+    SUM(revenue) OVER (ORDER BY date) as cumulative_sum,
+    AVG(revenue) OVER (ORDER BY date) as cumulative_avg,
+    MIN(revenue) OVER (ORDER BY date) as cumulative_min,
+    MAX(revenue) OVER (ORDER BY date) as cumulative_max
+FROM daily_sales;
+```
+
+## Window Frame Specification
+
+### ROWS vs RANGE
+
+```sql
+-- ROWS: Physical row count
+SELECT
+    date,
+    revenue,
+    SUM(revenue) OVER (
+        ORDER BY date
+        ROWS BETWEEN 2 PRECEDING AND CURRENT ROW
+    ) as sum_3_rows
+FROM sales;
+
+-- RANGE: Logical value range (careful with duplicates)
+SELECT
+    date,
+    revenue,
+    SUM(revenue) OVER (
+        ORDER BY date
+        RANGE BETWEEN INTERVAL '7 days' PRECEDING AND CURRENT ROW
+    ) as sum_7_days
+FROM sales;
+```
+
+### Frame Boundaries
+
+```sql
+-- All frames available
+ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING  -- Entire partition
+ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW          -- From start to here
+ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING          -- From here to end
+ROWS BETWEEN 3 PRECEDING AND 3 FOLLOWING                  -- 7 rows centered
+ROWS BETWEEN 6 PRECEDING AND CURRENT ROW                  -- 7 rows trailing
+```
+
+## Practical Examples
+
+### Year-over-Year Comparison
+
+```sql
+SELECT
+    date,
+    revenue,
+    LAG(revenue, 365) OVER (ORDER BY date) as revenue_year_ago,
+    revenue - LAG(revenue, 365) OVER (ORDER BY date) as yoy_change,
+    ROUND(100.0 * (revenue - LAG(revenue, 365) OVER (ORDER BY date))
+        / NULLIF(LAG(revenue, 365) OVER (ORDER BY date), 0), 2) as yoy_pct
+FROM daily_sales;
+```
+
+### Running Percentage of Total
+
+```sql
+SELECT
+    category,
+    sales,
+    SUM(sales) OVER () as total,
+    ROUND(100.0 * sales / SUM(sales) OVER (), 2) as pct_of_total,
+    ROUND(100.0 * SUM(sales) OVER (ORDER BY sales DESC)
+        / SUM(sales) OVER (), 2) as cumulative_pct
+FROM category_sales;
+```
+
+### Session/Gap Detection
+
+```sql
+-- Find sessions (gaps > 30 minutes = new session)
+WITH events_with_gaps AS (
+    SELECT
+        *,
+        EXTRACT(EPOCH FROM (timestamp - LAG(timestamp) OVER (
+            PARTITION BY user_id ORDER BY timestamp
+        ))) / 60 as minutes_since_last
+    FROM user_events
+)
+SELECT
+    *,
+    SUM(CASE WHEN minutes_since_last > 30 OR minutes_since_last IS NULL
+        THEN 1 ELSE 0 END) OVER (
+        PARTITION BY user_id ORDER BY timestamp
+    ) as session_id
+FROM events_with_gaps;
+```
+
+### Deduplication with Row Number
+
+```sql
+-- Keep only the latest record per user
+WITH ranked AS (
+    SELECT *,
+        ROW_NUMBER() OVER (
+            PARTITION BY user_id
+            ORDER BY updated_at DESC
+        ) as rn
+    FROM users
+)
+SELECT * FROM ranked WHERE rn = 1;
+```
+
+## Performance Tips
+
+1. **Index the ORDER BY column** - Window functions sort data
+2. **Limit partitions** - Large partitions = more memory
+3. **Named windows** - Reuse window definitions
+4. **Avoid nested windows** - Use CTEs instead
+
+### Named Windows
+
+```sql
+SELECT
+    name,
+    department,
+    salary,
+    ROW_NUMBER() OVER dept_salary as rank,
+    AVG(salary) OVER dept_salary as dept_avg,
+    salary - AVG(salary) OVER dept_salary as diff_from_avg
+FROM employees
+WINDOW dept_salary AS (PARTITION BY department ORDER BY salary DESC);
+```

+ 32 - 216
skills/sqlite-ops/SKILL.md

@@ -7,85 +7,28 @@ allowed-tools: "Read Write Bash"
 
 # SQLite Operations
 
-Patterns for SQLite databases in Python projects - state management, caching, and async operations.
+Patterns for SQLite databases in Python projects.
 
-## Schema Design Patterns
+## Quick Connection
 
-### State/Config Storage
-```sql
-CREATE TABLE IF NOT EXISTS app_state (
-    key TEXT PRIMARY KEY,
-    value TEXT NOT NULL,
-    updated_at TEXT DEFAULT (datetime('now'))
-);
-
--- Upsert pattern
-INSERT INTO app_state (key, value) VALUES ('last_sync', '2024-01-15')
-ON CONFLICT(key) DO UPDATE SET value = excluded.value, updated_at = datetime('now');
-```
-
-### Cache Table
-```sql
-CREATE TABLE IF NOT EXISTS cache (
-    key TEXT PRIMARY KEY,
-    value TEXT NOT NULL,
-    expires_at TEXT NOT NULL,
-    created_at TEXT DEFAULT (datetime('now'))
-);
-
--- Create index for expiry cleanup
-CREATE INDEX IF NOT EXISTS idx_cache_expires ON cache(expires_at);
-
--- Cleanup expired entries
-DELETE FROM cache WHERE expires_at < datetime('now');
-```
-
-### Event/Log Table
-```sql
-CREATE TABLE IF NOT EXISTS events (
-    id INTEGER PRIMARY KEY AUTOINCREMENT,
-    event_type TEXT NOT NULL,
-    payload TEXT,  -- JSON
-    created_at TEXT DEFAULT (datetime('now'))
-);
-
-CREATE INDEX IF NOT EXISTS idx_events_type_date ON events(event_type, created_at);
-```
-
-### Deduplication Table
-```sql
-CREATE TABLE IF NOT EXISTS seen_items (
-    hash TEXT PRIMARY KEY,
-    source TEXT NOT NULL,
-    first_seen TEXT DEFAULT (datetime('now'))
-);
-
--- Check if seen
-SELECT 1 FROM seen_items WHERE hash = ? LIMIT 1;
-```
-
-## Python sqlite3 Patterns
-
-### Connection with Best Practices
 ```python
 import sqlite3
-from pathlib import Path
 
-def get_connection(db_path: str | Path) -> sqlite3.Connection:
+def get_connection(db_path: str) -> sqlite3.Connection:
     conn = sqlite3.connect(db_path, check_same_thread=False)
     conn.row_factory = sqlite3.Row  # Dict-like access
     conn.execute("PRAGMA journal_mode=WAL")  # Better concurrency
-    conn.execute("PRAGMA foreign_keys=ON")   # Enforce FK constraints
+    conn.execute("PRAGMA foreign_keys=ON")
     return conn
 ```
 
-### Context Manager Pattern
+## Context Manager Pattern
+
 ```python
 from contextlib import contextmanager
 
 @contextmanager
 def db_transaction(conn: sqlite3.Connection):
-    """Auto-commit or rollback on error."""
     try:
         yield conn
         conn.commit()
@@ -94,57 +37,10 @@ def db_transaction(conn: sqlite3.Connection):
         raise
 ```
 
-### Batch Insert
-```python
-def batch_insert(conn, items: list[dict]):
-    """Efficient bulk insert."""
-    conn.executemany(
-        "INSERT OR IGNORE INTO items (id, name, data) VALUES (?, ?, ?)",
-        [(i["id"], i["name"], json.dumps(i["data"])) for i in items]
-    )
-    conn.commit()
-```
+## WAL Mode
 
-## Python aiosqlite Patterns
+Enable for concurrent read/write:
 
-### Async Connection
-```python
-import aiosqlite
-
-async def get_async_connection(db_path: str) -> aiosqlite.Connection:
-    conn = await aiosqlite.connect(db_path)
-    conn.row_factory = aiosqlite.Row
-    await conn.execute("PRAGMA journal_mode=WAL")
-    await conn.execute("PRAGMA foreign_keys=ON")
-    return conn
-```
-
-### Async Context Manager
-```python
-async def query_items(db_path: str, status: str) -> list[dict]:
-    async with aiosqlite.connect(db_path) as db:
-        db.row_factory = aiosqlite.Row
-        async with db.execute(
-            "SELECT * FROM items WHERE status = ?", (status,)
-        ) as cursor:
-            rows = await cursor.fetchall()
-            return [dict(row) for row in rows]
-```
-
-### Async Batch Operations
-```python
-async def batch_update_status(db_path: str, ids: list[int], status: str):
-    async with aiosqlite.connect(db_path) as db:
-        await db.executemany(
-            "UPDATE items SET status = ? WHERE id = ?",
-            [(status, id) for id in ids]
-        )
-        await db.commit()
-```
-
-## WAL Mode (Write-Ahead Logging)
-
-**Enable for concurrent read/write:**
 ```python
 conn.execute("PRAGMA journal_mode=WAL")
 ```
@@ -154,116 +50,36 @@ conn.execute("PRAGMA journal_mode=WAL")
 | DELETE (default) | Blocked during write | Single | Simple scripts |
 | WAL | Concurrent | Single | Web apps, MCP servers |
 
-**Checkpoint WAL periodically:**
-```python
-conn.execute("PRAGMA wal_checkpoint(TRUNCATE)")
-```
-
-## Migration Pattern
-
-```python
-MIGRATIONS = [
-    # Version 1
-    """
-    CREATE TABLE IF NOT EXISTS items (
-        id INTEGER PRIMARY KEY,
-        name TEXT NOT NULL,
-        created_at TEXT DEFAULT (datetime('now'))
-    );
-    """,
-    # Version 2 - add status column
-    """
-    ALTER TABLE items ADD COLUMN status TEXT DEFAULT 'active';
-    CREATE INDEX IF NOT EXISTS idx_items_status ON items(status);
-    """,
-]
-
-def migrate(conn: sqlite3.Connection):
-    """Apply pending migrations."""
-    conn.execute("CREATE TABLE IF NOT EXISTS schema_version (version INTEGER)")
-
-    result = conn.execute("SELECT version FROM schema_version").fetchone()
-    current = result[0] if result else 0
-
-    for i, migration in enumerate(MIGRATIONS[current:], start=current):
-        conn.executescript(migration)
-        conn.execute("DELETE FROM schema_version")
-        conn.execute("INSERT INTO schema_version VALUES (?)", (i + 1,))
-        conn.commit()
-```
-
-## Query Optimization
-
-### Use EXPLAIN QUERY PLAN
-```python
-plan = conn.execute("EXPLAIN QUERY PLAN SELECT * FROM items WHERE status = ?", ("active",)).fetchall()
-for row in plan:
-    print(row)
-# Look for "SCAN" (bad) vs "SEARCH" or "USING INDEX" (good)
-```
-
-### Common Index Patterns
-```sql
--- Single column (equality + range)
-CREATE INDEX idx_items_status ON items(status);
-
--- Composite (filter + sort)
-CREATE INDEX idx_items_status_date ON items(status, created_at);
-
--- Covering index (avoid table lookup)
-CREATE INDEX idx_items_status_covering ON items(status) INCLUDE (name, created_at);
-```
-
-## JSON in SQLite
-
-```sql
--- Store JSON
-INSERT INTO events (payload) VALUES ('{"type": "click", "x": 100}');
-
--- Query JSON (SQLite 3.38+)
-SELECT json_extract(payload, '$.type') as event_type FROM events;
+## Common Gotchas
 
--- Filter by JSON value
-SELECT * FROM events WHERE json_extract(payload, '$.type') = 'click';
-```
+| Issue | Solution |
+|-------|----------|
+| "database is locked" | Use WAL mode |
+| Slow queries | Add indexes, check EXPLAIN QUERY PLAN |
+| Thread safety | Use `check_same_thread=False` |
+| FK not enforced | Run `PRAGMA foreign_keys=ON` |
 
 ## CLI Quick Reference
 
 ```bash
-# Open database
-sqlite3 mydb.sqlite
-
-# Show tables
-.tables
-
-# Show schema
-.schema items
-
-# Export to CSV
-.headers on
-.mode csv
-.output items.csv
-SELECT * FROM items;
-.output stdout
-
-# Import CSV
-.mode csv
-.import items.csv items
+sqlite3 mydb.sqlite    # Open database
+.tables                # Show tables
+.schema items          # Show schema
+.headers on && .mode csv && .output data.csv  # Export CSV
+VACUUM;                # Reclaim space
+```
 
-# Run SQL file
-.read schema.sql
+## When to Use
 
-# Vacuum (reclaim space)
-VACUUM;
-```
+- Local state/config storage
+- Caching layer
+- Event logging
+- MCP server persistence
+- Small to medium datasets
 
-## Common Gotchas
+## Additional Resources
 
-| Issue | Solution |
-|-------|----------|
-| "database is locked" | Use WAL mode, or ensure single writer |
-| Slow queries | Add indexes, check EXPLAIN QUERY PLAN |
-| Memory issues with large results | Use `fetchmany(1000)` in batches |
-| Thread safety | Use `check_same_thread=False` + connection per thread |
-| Foreign key not enforced | Run `PRAGMA foreign_keys=ON` after connect |
-| datetime storage | Store as TEXT in ISO format, use `datetime()` function |
+For detailed patterns, load:
+- `./references/schema-patterns.md` - State, cache, event, queue table designs
+- `./references/async-patterns.md` - aiosqlite CRUD, batching, connection pools
+- `./references/migration-patterns.md` - Version migrations, JSON handling

+ 288 - 0
skills/sqlite-ops/references/async-patterns.md

@@ -0,0 +1,288 @@
+# SQLite Async Patterns
+
+Python aiosqlite patterns for async applications.
+
+## Async Connection
+
+```python
+import aiosqlite
+
+async def get_async_connection(db_path: str) -> aiosqlite.Connection:
+    """Create async connection with best practices."""
+    conn = await aiosqlite.connect(db_path)
+    conn.row_factory = aiosqlite.Row
+    await conn.execute("PRAGMA journal_mode=WAL")
+    await conn.execute("PRAGMA foreign_keys=ON")
+    return conn
+```
+
+## Context Manager Pattern
+
+```python
+async def query_items(db_path: str, status: str) -> list[dict]:
+    """Query with automatic connection cleanup."""
+    async with aiosqlite.connect(db_path) as db:
+        db.row_factory = aiosqlite.Row
+        async with db.execute(
+            "SELECT * FROM items WHERE status = ?", (status,)
+        ) as cursor:
+            rows = await cursor.fetchall()
+            return [dict(row) for row in rows]
+```
+
+## Async CRUD Operations
+
+### Create
+
+```python
+async def create_item(db_path: str, name: str, data: dict) -> int:
+    """Insert and return new ID."""
+    async with aiosqlite.connect(db_path) as db:
+        cursor = await db.execute(
+            "INSERT INTO items (name, data) VALUES (?, ?)",
+            (name, json.dumps(data))
+        )
+        await db.commit()
+        return cursor.lastrowid
+```
+
+### Read
+
+```python
+async def get_item(db_path: str, item_id: int) -> dict | None:
+    """Get single item by ID."""
+    async with aiosqlite.connect(db_path) as db:
+        db.row_factory = aiosqlite.Row
+        async with db.execute(
+            "SELECT * FROM items WHERE id = ?", (item_id,)
+        ) as cursor:
+            row = await cursor.fetchone()
+            return dict(row) if row else None
+```
+
+### Update
+
+```python
+async def update_item(db_path: str, item_id: int, **updates) -> bool:
+    """Update item fields."""
+    if not updates:
+        return False
+
+    set_clause = ", ".join(f"{k} = ?" for k in updates.keys())
+    values = list(updates.values()) + [item_id]
+
+    async with aiosqlite.connect(db_path) as db:
+        cursor = await db.execute(
+            f"UPDATE items SET {set_clause} WHERE id = ?",
+            values
+        )
+        await db.commit()
+        return cursor.rowcount > 0
+```
+
+### Delete
+
+```python
+async def delete_item(db_path: str, item_id: int) -> bool:
+    """Delete item by ID."""
+    async with aiosqlite.connect(db_path) as db:
+        cursor = await db.execute(
+            "DELETE FROM items WHERE id = ?", (item_id,)
+        )
+        await db.commit()
+        return cursor.rowcount > 0
+```
+
+## Batch Operations
+
+### Batch Insert
+
+```python
+async def batch_insert(db_path: str, items: list[dict]) -> int:
+    """Insert multiple items efficiently."""
+    async with aiosqlite.connect(db_path) as db:
+        await db.executemany(
+            "INSERT INTO items (name, data) VALUES (?, ?)",
+            [(i["name"], json.dumps(i.get("data", {}))) for i in items]
+        )
+        await db.commit()
+        return len(items)
+```
+
+### Batch Update
+
+```python
+async def batch_update_status(db_path: str, ids: list[int], status: str) -> int:
+    """Update status for multiple items."""
+    async with aiosqlite.connect(db_path) as db:
+        cursor = await db.executemany(
+            "UPDATE items SET status = ? WHERE id = ?",
+            [(status, id) for id in ids]
+        )
+        await db.commit()
+        return len(ids)
+```
+
+### Batch with Transaction
+
+```python
+async def batch_transfer(db_path: str, transfers: list[tuple[int, int, float]]) -> None:
+    """Transfer amounts between accounts atomically."""
+    async with aiosqlite.connect(db_path) as db:
+        try:
+            for from_id, to_id, amount in transfers:
+                await db.execute(
+                    "UPDATE accounts SET balance = balance - ? WHERE id = ?",
+                    (amount, from_id)
+                )
+                await db.execute(
+                    "UPDATE accounts SET balance = balance + ? WHERE id = ?",
+                    (amount, to_id)
+                )
+            await db.commit()
+        except Exception:
+            await db.rollback()
+            raise
+```
+
+## Connection Pool Pattern
+
+```python
+from contextlib import asynccontextmanager
+import asyncio
+
+class AsyncDBPool:
+    """Simple connection pool for aiosqlite."""
+
+    def __init__(self, db_path: str, max_connections: int = 5):
+        self.db_path = db_path
+        self.max_connections = max_connections
+        self._pool: asyncio.Queue[aiosqlite.Connection] = asyncio.Queue()
+        self._created = 0
+        self._lock = asyncio.Lock()
+
+    async def _create_connection(self) -> aiosqlite.Connection:
+        conn = await aiosqlite.connect(self.db_path)
+        conn.row_factory = aiosqlite.Row
+        await conn.execute("PRAGMA journal_mode=WAL")
+        return conn
+
+    @asynccontextmanager
+    async def acquire(self):
+        # Try to get from pool
+        try:
+            conn = self._pool.get_nowait()
+        except asyncio.QueueEmpty:
+            # Create new if under limit
+            async with self._lock:
+                if self._created < self.max_connections:
+                    conn = await self._create_connection()
+                    self._created += 1
+                else:
+                    # Wait for one to be returned
+                    conn = await self._pool.get()
+
+        try:
+            yield conn
+        finally:
+            # Return to pool
+            await self._pool.put(conn)
+
+    async def close_all(self):
+        while not self._pool.empty():
+            conn = await self._pool.get()
+            await conn.close()
+        self._created = 0
+
+# Usage
+pool = AsyncDBPool("mydb.sqlite")
+
+async def get_user(user_id: int):
+    async with pool.acquire() as db:
+        async with db.execute(
+            "SELECT * FROM users WHERE id = ?", (user_id,)
+        ) as cursor:
+            return await cursor.fetchone()
+```
+
+## Streaming Large Results
+
+```python
+async def stream_items(db_path: str, batch_size: int = 1000):
+    """Yield items in batches to avoid memory issues."""
+    async with aiosqlite.connect(db_path) as db:
+        db.row_factory = aiosqlite.Row
+        async with db.execute("SELECT * FROM items ORDER BY id") as cursor:
+            while True:
+                rows = await cursor.fetchmany(batch_size)
+                if not rows:
+                    break
+                for row in rows:
+                    yield dict(row)
+```
+
+## Concurrent Queries
+
+```python
+async def get_dashboard_data(db_path: str, user_id: int) -> dict:
+    """Run multiple queries concurrently."""
+    async with aiosqlite.connect(db_path) as db:
+        db.row_factory = aiosqlite.Row
+
+        # Execute queries concurrently
+        user_task = db.execute("SELECT * FROM users WHERE id = ?", (user_id,))
+        orders_task = db.execute(
+            "SELECT * FROM orders WHERE user_id = ? ORDER BY created_at DESC LIMIT 10",
+            (user_id,)
+        )
+        stats_task = db.execute(
+            "SELECT COUNT(*) as count, SUM(total) as total FROM orders WHERE user_id = ?",
+            (user_id,)
+        )
+
+        # Await all
+        user_cursor, orders_cursor, stats_cursor = await asyncio.gather(
+            user_task, orders_task, stats_task
+        )
+
+        return {
+            "user": dict(await user_cursor.fetchone()),
+            "recent_orders": [dict(r) for r in await orders_cursor.fetchall()],
+            "stats": dict(await stats_cursor.fetchone()),
+        }
+```
+
+## Error Handling
+
+```python
+import aiosqlite
+from sqlite3 import IntegrityError, OperationalError
+
+async def safe_insert(db_path: str, data: dict) -> tuple[bool, str]:
+    """Insert with comprehensive error handling."""
+    try:
+        async with aiosqlite.connect(db_path) as db:
+            await db.execute(
+                "INSERT INTO items (name, value) VALUES (?, ?)",
+                (data["name"], data["value"])
+            )
+            await db.commit()
+            return True, "Success"
+
+    except IntegrityError as e:
+        if "UNIQUE constraint" in str(e):
+            return False, "Duplicate entry"
+        elif "FOREIGN KEY constraint" in str(e):
+            return False, "Referenced record not found"
+        return False, f"Integrity error: {e}"
+
+    except OperationalError as e:
+        if "database is locked" in str(e):
+            return False, "Database busy, try again"
+        elif "no such table" in str(e):
+            return False, "Table not found"
+        return False, f"Database error: {e}"
+
+    except Exception as e:
+        return False, f"Unexpected error: {e}"
+```

+ 330 - 0
skills/sqlite-ops/references/migration-patterns.md

@@ -0,0 +1,330 @@
+# SQLite Migration Patterns
+
+Version-controlled schema migrations for SQLite databases.
+
+## Basic Migration Pattern
+
+```python
+import sqlite3
+
+MIGRATIONS = [
+    # Version 1: Initial schema
+    """
+    CREATE TABLE IF NOT EXISTS items (
+        id INTEGER PRIMARY KEY,
+        name TEXT NOT NULL,
+        created_at TEXT DEFAULT (datetime('now'))
+    );
+    """,
+    # Version 2: Add status column
+    """
+    ALTER TABLE items ADD COLUMN status TEXT DEFAULT 'active';
+    CREATE INDEX IF NOT EXISTS idx_items_status ON items(status);
+    """,
+    # Version 3: Add user reference
+    """
+    ALTER TABLE items ADD COLUMN user_id INTEGER;
+    CREATE INDEX IF NOT EXISTS idx_items_user ON items(user_id);
+    """,
+]
+
+def migrate(conn: sqlite3.Connection):
+    """Apply pending migrations."""
+    # Create version tracking table
+    conn.execute("""
+        CREATE TABLE IF NOT EXISTS schema_version (
+            version INTEGER PRIMARY KEY,
+            applied_at TEXT DEFAULT (datetime('now'))
+        )
+    """)
+
+    # Get current version
+    result = conn.execute(
+        "SELECT MAX(version) FROM schema_version"
+    ).fetchone()
+    current = result[0] if result[0] is not None else 0
+
+    # Apply pending migrations
+    for i, migration in enumerate(MIGRATIONS[current:], start=current + 1):
+        print(f"Applying migration {i}...")
+        conn.executescript(migration)
+        conn.execute(
+            "INSERT INTO schema_version (version) VALUES (?)",
+            (i,)
+        )
+        conn.commit()
+        print(f"Migration {i} complete")
+
+    print(f"Database at version {len(MIGRATIONS)}")
+```
+
+## Named Migrations
+
+```python
+from dataclasses import dataclass
+from datetime import datetime
+
+@dataclass
+class Migration:
+    name: str
+    up: str
+    down: str | None = None
+
+MIGRATIONS = [
+    Migration(
+        name="001_initial_schema",
+        up="""
+            CREATE TABLE users (
+                id INTEGER PRIMARY KEY,
+                email TEXT UNIQUE NOT NULL,
+                name TEXT,
+                created_at TEXT DEFAULT (datetime('now'))
+            );
+            CREATE INDEX idx_users_email ON users(email);
+        """,
+        down="""
+            DROP INDEX IF EXISTS idx_users_email;
+            DROP TABLE IF EXISTS users;
+        """
+    ),
+    Migration(
+        name="002_add_orders",
+        up="""
+            CREATE TABLE orders (
+                id INTEGER PRIMARY KEY,
+                user_id INTEGER NOT NULL REFERENCES users(id),
+                total REAL NOT NULL,
+                status TEXT DEFAULT 'pending',
+                created_at TEXT DEFAULT (datetime('now'))
+            );
+            CREATE INDEX idx_orders_user ON orders(user_id);
+            CREATE INDEX idx_orders_status ON orders(status);
+        """,
+        down="""
+            DROP TABLE IF EXISTS orders;
+        """
+    ),
+]
+
+def migrate_up(conn: sqlite3.Connection, target: int | None = None):
+    """Apply migrations up to target version."""
+    conn.execute("""
+        CREATE TABLE IF NOT EXISTS migrations (
+            id INTEGER PRIMARY KEY,
+            name TEXT NOT NULL,
+            applied_at TEXT DEFAULT (datetime('now'))
+        )
+    """)
+
+    applied = {
+        row[0] for row in
+        conn.execute("SELECT name FROM migrations").fetchall()
+    }
+
+    target = target or len(MIGRATIONS)
+
+    for i, migration in enumerate(MIGRATIONS[:target]):
+        if migration.name not in applied:
+            print(f"Applying: {migration.name}")
+            conn.executescript(migration.up)
+            conn.execute(
+                "INSERT INTO migrations (name) VALUES (?)",
+                (migration.name,)
+            )
+            conn.commit()
+
+def migrate_down(conn: sqlite3.Connection, steps: int = 1):
+    """Rollback migrations."""
+    applied = conn.execute(
+        "SELECT name FROM migrations ORDER BY id DESC LIMIT ?",
+        (steps,)
+    ).fetchall()
+
+    for (name,) in applied:
+        migration = next(m for m in MIGRATIONS if m.name == name)
+        if migration.down:
+            print(f"Rolling back: {name}")
+            conn.executescript(migration.down)
+            conn.execute("DELETE FROM migrations WHERE name = ?", (name,))
+            conn.commit()
+        else:
+            print(f"Cannot rollback {name}: no down migration")
+            break
+```
+
+## Async Migrations
+
+```python
+import aiosqlite
+
+async def async_migrate(db_path: str, migrations: list[str]):
+    """Apply migrations asynchronously."""
+    async with aiosqlite.connect(db_path) as db:
+        await db.execute("""
+            CREATE TABLE IF NOT EXISTS schema_version (
+                version INTEGER PRIMARY KEY
+            )
+        """)
+
+        result = await db.execute("SELECT MAX(version) FROM schema_version")
+        row = await result.fetchone()
+        current = row[0] if row[0] is not None else 0
+
+        for i, migration in enumerate(migrations[current:], start=current + 1):
+            await db.executescript(migration)
+            await db.execute(
+                "INSERT INTO schema_version (version) VALUES (?)",
+                (i,)
+            )
+            await db.commit()
+```
+
+## Safe Column Operations
+
+SQLite has limited ALTER TABLE support. Here are safe patterns:
+
+### Adding Columns
+
+```sql
+-- Safe: Add column with default
+ALTER TABLE items ADD COLUMN status TEXT DEFAULT 'active';
+
+-- Safe: Add nullable column
+ALTER TABLE items ADD COLUMN notes TEXT;
+```
+
+### Renaming Columns (SQLite 3.25+)
+
+```sql
+-- Safe in SQLite 3.25+
+ALTER TABLE items RENAME COLUMN old_name TO new_name;
+```
+
+### Recreate Table Pattern
+
+For complex changes (dropping columns, changing types):
+
+```python
+def recreate_table(conn: sqlite3.Connection):
+    """Safely modify table structure by recreating."""
+    conn.executescript("""
+        -- 1. Rename old table
+        ALTER TABLE items RENAME TO items_old;
+
+        -- 2. Create new table with desired schema
+        CREATE TABLE items (
+            id INTEGER PRIMARY KEY,
+            name TEXT NOT NULL,
+            status TEXT DEFAULT 'active',
+            -- dropped: old_column
+            -- changed: type of some_column
+            created_at TEXT DEFAULT (datetime('now'))
+        );
+
+        -- 3. Copy data (mapping columns as needed)
+        INSERT INTO items (id, name, status, created_at)
+        SELECT id, name, COALESCE(status, 'active'), created_at
+        FROM items_old;
+
+        -- 4. Drop old table
+        DROP TABLE items_old;
+
+        -- 5. Recreate indexes
+        CREATE INDEX idx_items_status ON items(status);
+    """)
+    conn.commit()
+```
+
+## JSON in SQLite
+
+### Storing JSON
+
+```python
+import json
+
+def store_json(conn: sqlite3.Connection, key: str, data: dict):
+    """Store JSON data."""
+    conn.execute(
+        "INSERT OR REPLACE INTO json_store (key, data) VALUES (?, ?)",
+        (key, json.dumps(data))
+    )
+    conn.commit()
+
+def get_json(conn: sqlite3.Connection, key: str) -> dict | None:
+    """Retrieve JSON data."""
+    result = conn.execute(
+        "SELECT data FROM json_store WHERE key = ?", (key,)
+    ).fetchone()
+    return json.loads(result[0]) if result else None
+```
+
+### Querying JSON (SQLite 3.38+)
+
+```sql
+-- Create table with JSON column
+CREATE TABLE events (
+    id INTEGER PRIMARY KEY,
+    payload TEXT NOT NULL  -- JSON
+);
+
+-- Extract JSON field
+SELECT json_extract(payload, '$.type') as event_type FROM events;
+
+-- Filter by JSON value
+SELECT * FROM events
+WHERE json_extract(payload, '$.user_id') = 123;
+
+-- Get nested value
+SELECT json_extract(payload, '$.metadata.source') FROM events;
+
+-- Check if key exists
+SELECT * FROM events
+WHERE json_type(payload, '$.optional_field') IS NOT NULL;
+
+-- Array operations
+SELECT json_extract(payload, '$.tags[0]') FROM events;
+SELECT json_array_length(json_extract(payload, '$.tags')) FROM events;
+```
+
+### JSON with Python
+
+```python
+def query_json_field(conn: sqlite3.Connection, field: str, value: any) -> list:
+    """Query by JSON field value."""
+    conn.row_factory = sqlite3.Row
+    cursor = conn.execute(
+        f"SELECT * FROM events WHERE json_extract(payload, '$.{field}') = ?",
+        (value,)
+    )
+    return [dict(row) for row in cursor.fetchall()]
+
+def update_json_field(conn: sqlite3.Connection, event_id: int, field: str, value: any):
+    """Update specific JSON field."""
+    conn.execute(
+        f"UPDATE events SET payload = json_set(payload, '$.{field}', ?) WHERE id = ?",
+        (json.dumps(value) if isinstance(value, (dict, list)) else value, event_id)
+    )
+    conn.commit()
+```
+
+## CLI Quick Reference
+
+```bash
+# Run migration from file
+sqlite3 mydb.sqlite < migrations/001_initial.sql
+
+# Check schema version
+sqlite3 mydb.sqlite "SELECT * FROM schema_version"
+
+# Export schema
+sqlite3 mydb.sqlite ".schema" > schema.sql
+
+# Dump with data
+sqlite3 mydb.sqlite ".dump" > backup.sql
+
+# Restore from dump
+sqlite3 newdb.sqlite < backup.sql
+
+# Compare schemas
+diff <(sqlite3 db1.sqlite ".schema") <(sqlite3 db2.sqlite ".schema")
+```

+ 229 - 0
skills/sqlite-ops/references/schema-patterns.md

@@ -0,0 +1,229 @@
+# SQLite Schema Patterns
+
+Common schema designs for state management, caching, logging, and deduplication.
+
+## State/Config Storage
+
+Key-value store with automatic timestamps:
+
+```sql
+CREATE TABLE IF NOT EXISTS app_state (
+    key TEXT PRIMARY KEY,
+    value TEXT NOT NULL,
+    updated_at TEXT DEFAULT (datetime('now'))
+);
+
+-- Upsert pattern (insert or update)
+INSERT INTO app_state (key, value) VALUES ('last_sync', '2024-01-15')
+ON CONFLICT(key) DO UPDATE SET value = excluded.value, updated_at = datetime('now');
+
+-- Get value
+SELECT value FROM app_state WHERE key = 'last_sync';
+
+-- Get all state
+SELECT * FROM app_state ORDER BY updated_at DESC;
+```
+
+## Cache Table
+
+Time-based cache with expiry cleanup:
+
+```sql
+CREATE TABLE IF NOT EXISTS cache (
+    key TEXT PRIMARY KEY,
+    value TEXT NOT NULL,
+    expires_at TEXT NOT NULL,
+    created_at TEXT DEFAULT (datetime('now'))
+);
+
+-- Create index for expiry cleanup
+CREATE INDEX IF NOT EXISTS idx_cache_expires ON cache(expires_at);
+
+-- Insert with 1 hour TTL
+INSERT INTO cache (key, value, expires_at)
+VALUES ('user:123', '{"name": "Alice"}', datetime('now', '+1 hour'))
+ON CONFLICT(key) DO UPDATE SET
+    value = excluded.value,
+    expires_at = excluded.expires_at;
+
+-- Get non-expired value
+SELECT value FROM cache
+WHERE key = 'user:123' AND expires_at > datetime('now');
+
+-- Cleanup expired entries
+DELETE FROM cache WHERE expires_at < datetime('now');
+```
+
+## Event/Log Table
+
+Append-only event log with type indexing:
+
+```sql
+CREATE TABLE IF NOT EXISTS events (
+    id INTEGER PRIMARY KEY AUTOINCREMENT,
+    event_type TEXT NOT NULL,
+    payload TEXT,  -- JSON
+    created_at TEXT DEFAULT (datetime('now'))
+);
+
+-- Index for type + date queries
+CREATE INDEX IF NOT EXISTS idx_events_type_date ON events(event_type, created_at);
+
+-- Insert event
+INSERT INTO events (event_type, payload)
+VALUES ('user_login', '{"user_id": 123, "ip": "10.0.0.1"}');
+
+-- Get recent events by type
+SELECT * FROM events
+WHERE event_type = 'user_login'
+AND created_at > datetime('now', '-1 day')
+ORDER BY created_at DESC;
+
+-- Count by type
+SELECT event_type, COUNT(*) as count
+FROM events
+GROUP BY event_type;
+```
+
+## Deduplication Table
+
+Track seen items to avoid reprocessing:
+
+```sql
+CREATE TABLE IF NOT EXISTS seen_items (
+    hash TEXT PRIMARY KEY,
+    source TEXT NOT NULL,
+    first_seen TEXT DEFAULT (datetime('now'))
+);
+
+-- Check if seen
+SELECT 1 FROM seen_items WHERE hash = ? LIMIT 1;
+
+-- Mark as seen
+INSERT OR IGNORE INTO seen_items (hash, source) VALUES (?, ?);
+
+-- Get sources for hash
+SELECT source, first_seen FROM seen_items WHERE hash = ?;
+
+-- Cleanup old entries
+DELETE FROM seen_items WHERE first_seen < datetime('now', '-30 days');
+```
+
+## Queue Table
+
+Simple job queue with status tracking:
+
+```sql
+CREATE TABLE IF NOT EXISTS job_queue (
+    id INTEGER PRIMARY KEY AUTOINCREMENT,
+    job_type TEXT NOT NULL,
+    payload TEXT NOT NULL,  -- JSON
+    status TEXT DEFAULT 'pending',  -- pending, processing, completed, failed
+    priority INTEGER DEFAULT 0,
+    created_at TEXT DEFAULT (datetime('now')),
+    started_at TEXT,
+    completed_at TEXT,
+    error TEXT
+);
+
+-- Index for fetching next job
+CREATE INDEX IF NOT EXISTS idx_jobs_status_priority
+ON job_queue(status, priority DESC, created_at);
+
+-- Claim next job (atomic with transaction)
+UPDATE job_queue
+SET status = 'processing', started_at = datetime('now')
+WHERE id = (
+    SELECT id FROM job_queue
+    WHERE status = 'pending'
+    ORDER BY priority DESC, created_at
+    LIMIT 1
+)
+RETURNING *;
+
+-- Complete job
+UPDATE job_queue
+SET status = 'completed', completed_at = datetime('now')
+WHERE id = ?;
+
+-- Fail job
+UPDATE job_queue
+SET status = 'failed', completed_at = datetime('now'), error = ?
+WHERE id = ?;
+```
+
+## Session Table
+
+User sessions with expiry:
+
+```sql
+CREATE TABLE IF NOT EXISTS sessions (
+    token TEXT PRIMARY KEY,
+    user_id INTEGER NOT NULL,
+    data TEXT,  -- JSON
+    created_at TEXT DEFAULT (datetime('now')),
+    expires_at TEXT NOT NULL
+);
+
+CREATE INDEX IF NOT EXISTS idx_sessions_user ON sessions(user_id);
+CREATE INDEX IF NOT EXISTS idx_sessions_expires ON sessions(expires_at);
+
+-- Create session (1 week expiry)
+INSERT INTO sessions (token, user_id, data, expires_at)
+VALUES (?, ?, '{}', datetime('now', '+7 days'));
+
+-- Get valid session
+SELECT * FROM sessions
+WHERE token = ? AND expires_at > datetime('now');
+
+-- Extend session
+UPDATE sessions
+SET expires_at = datetime('now', '+7 days')
+WHERE token = ?;
+
+-- Delete session
+DELETE FROM sessions WHERE token = ?;
+
+-- Cleanup expired
+DELETE FROM sessions WHERE expires_at < datetime('now');
+```
+
+## Full-Text Search Table
+
+Using SQLite FTS5:
+
+```sql
+-- Create FTS table
+CREATE VIRTUAL TABLE IF NOT EXISTS documents_fts USING fts5(
+    title,
+    content,
+    content='documents',
+    content_rowid='id'
+);
+
+-- Trigger to keep FTS in sync
+CREATE TRIGGER documents_ai AFTER INSERT ON documents BEGIN
+    INSERT INTO documents_fts(rowid, title, content)
+    VALUES (new.id, new.title, new.content);
+END;
+
+CREATE TRIGGER documents_ad AFTER DELETE ON documents BEGIN
+    INSERT INTO documents_fts(documents_fts, rowid, title, content)
+    VALUES('delete', old.id, old.title, old.content);
+END;
+
+CREATE TRIGGER documents_au AFTER UPDATE ON documents BEGIN
+    INSERT INTO documents_fts(documents_fts, rowid, title, content)
+    VALUES('delete', old.id, old.title, old.content);
+    INSERT INTO documents_fts(rowid, title, content)
+    VALUES (new.id, new.title, new.content);
+END;
+
+-- Search
+SELECT * FROM documents_fts WHERE documents_fts MATCH 'search query';
+
+-- Ranked search
+SELECT *, rank FROM documents_fts
+WHERE documents_fts MATCH 'query'
+ORDER BY rank;
+```

+ 38 - 294
skills/structural-search/SKILL.md

@@ -1,333 +1,67 @@
 ---
 name: structural-search
-description: "Search code by AST structure using ast-grep. Find semantic patterns like function calls, imports, class definitions instead of text patterns. Triggers on: find all calls to X, search for pattern, refactor usages, find where function is used, structural search."
+description: "Search code by AST structure using ast-grep. Find semantic patterns like function calls, imports, class definitions instead of text patterns. Triggers on: find all calls to X, search for pattern, refactor usages, find where function is used, structural search, ast-grep, sg."
 compatibility: "Requires ast-grep (sg) CLI tool. Install: brew install ast-grep (macOS) or cargo install ast-grep (cross-platform)."
 allowed-tools: "Bash"
 ---
 
 # Structural Search
 
-## Purpose
-Search code by its abstract syntax tree (AST) structure rather than plain text. Finds semantic patterns that regex cannot match reliably.
+Search code by its abstract syntax tree (AST) structure. Finds semantic patterns that regex cannot match reliably.
 
 ## Tools
 
 | Tool | Command | Use For |
 |------|---------|---------|
-| ast-grep | `ast-grep -p 'pattern'` | AST-aware code search |
-| sg | `sg -p 'pattern'` | Short alias for ast-grep |
+| ast-grep | `sg -p 'pattern'` | AST-aware code search |
 
 ## Pattern Syntax
 
 | Pattern | Matches | Example |
 |---------|---------|---------|
-| `$NAME` | Single identifier | `function $NAME() {}` |
-| `$_` | Any single node (wildcard) | `console.log($_)` |
-| `$$$` | Zero or more nodes | `function $_($$$) { $$$ }` |
-| `$$_` | One or more nodes | `[$_, $$_]` (non-empty array) |
+| `$NAME` | Named identifier | `function $NAME() {}` |
+| `$_` | Any single node | `console.log($_)` |
+| `$$$` | Zero or more nodes | `function $_($$$) {}` |
 
-## JavaScript/TypeScript Patterns
-
-### Function Calls
+## Top 10 Essential Patterns
 
 ```bash
-# Find all console.log calls
+# 1. Find console.log calls
 sg -p 'console.log($_)'
 
-# Find all console methods
-sg -p 'console.$_($_)'
-
-# Find fetch calls
-sg -p 'fetch($_)'
-
-# Find await fetch
-sg -p 'await fetch($_)'
-
-# Find specific function calls
-sg -p 'getUserById($_)'
-
-# Find method chaining
-sg -p '$_.then($_).catch($_)'
-```
-
-### React Patterns
-
-```bash
-# Find useState hooks
+# 2. Find React hooks
 sg -p 'const [$_, $_] = useState($_)'
-
-# Find useEffect with dependencies
 sg -p 'useEffect($_, [$$$])'
 
-# Find useEffect without dependencies (runs every render)
-sg -p 'useEffect($_, [])'
-
-# Find component definitions
-sg -p 'function $NAME($$$) { return <$$$> }'
-
-# Find specific prop usage
-sg -p '<Button onClick={$_}>'
-
-# Find useState without destructuring
-sg -p 'useState($_)'
-```
-
-### Imports
-
-```bash
-# Find all imports from a module
-sg -p 'import $_ from "react"'
-
-# Find named imports
-sg -p 'import { $_ } from "lodash"'
-
-# Find default and named imports
-sg -p 'import $_, { $$$ } from $_'
-
-# Find dynamic imports
-sg -p 'import($_)'
-
-# Find require calls
-sg -p 'require($_)'
-```
-
-### Async Patterns
-
-```bash
-# Find async functions
-sg -p 'async function $NAME($$$) { $$$ }'
-
-# Find async arrow functions
-sg -p 'async ($$$) => { $$$ }'
-
-# Find try-catch blocks
-sg -p 'try { $$$ } catch ($_) { $$$ }'
-
-# Find Promise.all
-sg -p 'Promise.all([$$$])'
-
-# Find unhandled promises (no await)
-sg -p '$_.then($_)'
-```
-
-### Error Prone Patterns
-
-```bash
-# Find == instead of ===
-sg -p '$_ == $_'
-
-# Find assignments in conditions
-sg -p 'if ($_ = $_)'
-
-# Find empty catch blocks
-sg -p 'catch ($_) {}'
-
-# Find console.log (for cleanup)
-sg -p 'console.log($$$)'
-
-# Find TODO comments
-sg -p '// TODO$$$'
-
-# Find debugger statements
-sg -p 'debugger'
-```
-
-## Python Patterns
-
-```bash
-# Find function definitions
+# 3. Find function definitions
+sg -p 'function $NAME($$$) { $$$ }'
 sg -p 'def $NAME($$$): $$$' --lang python
 
-# Find class definitions
-sg -p 'class $NAME: $$$' --lang python
-
-# Find decorated functions
-sg -p '@$_
-def $NAME($$$): $$$' --lang python
-
-# Find specific decorator
-sg -p '@pytest.fixture
-def $NAME($$$): $$$' --lang python
-
-# Find imports
-sg -p 'import $_' --lang python
+# 4. Find imports
+sg -p 'import $_ from "$_"'
 sg -p 'from $_ import $_' --lang python
 
-# Find f-strings
-sg -p 'f"$$$"' --lang python
-
-# Find list comprehensions
-sg -p '[$_ for $_ in $_]' --lang python
-
-# Find with statements
-sg -p 'with $_ as $_: $$$' --lang python
-
-# Find async definitions
-sg -p 'async def $NAME($$$): $$$' --lang python
-```
-
-## Go Patterns
-
-```bash
-# Find function declarations
-sg -p 'func $NAME($$$) $_ { $$$ }' --lang go
-
-# Find method declarations
-sg -p 'func ($_ $_) $NAME($$$) $_ { $$$ }' --lang go
-
-# Find interface definitions
-sg -p 'type $NAME interface { $$$ }' --lang go
-
-# Find struct definitions
-sg -p 'type $NAME struct { $$$ }' --lang go
+# 5. Find async patterns
+sg -p 'await $_'
+sg -p 'async function $NAME($$$) { $$$ }'
 
-# Find error handling
+# 6. Find error handling
+sg -p 'try { $$$ } catch ($_) { $$$ }'
 sg -p 'if err != nil { $$$ }' --lang go
 
-# Find defer statements
-sg -p 'defer $_' --lang go
+# 7. Find potential issues
+sg -p '$_ == $_'           # == instead of ===
+sg -p 'eval($_)'           # Security risk
+sg -p '$_.innerHTML = $_'  # XSS vector
 
-# Find goroutines
-sg -p 'go $_' --lang go
-```
-
-## Rust Patterns
-
-```bash
-# Find function definitions
-sg -p 'fn $NAME($$$) -> $_ { $$$ }' --lang rust
-
-# Find impl blocks
-sg -p 'impl $_ for $_ { $$$ }' --lang rust
-
-# Find match expressions
-sg -p 'match $_ { $$$ }' --lang rust
-
-# Find unwrap calls (potential panics)
-sg -p '$_.unwrap()' --lang rust
-
-# Find Result/Option handling
-sg -p '$_?' --lang rust
-```
-
-## Refactoring Patterns
-
-### Find and Replace
-
-```bash
-# Preview replacement
+# 8. Preview refactoring
 sg -p 'console.log($_)' -r 'logger.info($_)'
 
-# Replace in place
-sg -p 'console.log($_)' -r 'logger.info($_)' --rewrite
-
-# Replace with context
-sg -p 'var $NAME = $_' -r 'const $NAME = $_'
-```
-
-### Common Refactors
+# 9. Apply refactoring
+sg -p 'var $NAME = $_' -r 'const $NAME = $_' --rewrite
 
-```bash
-# Convert function to arrow
-sg -p 'function $NAME($ARGS) { return $BODY }' \
-   -r 'const $NAME = ($ARGS) => $BODY'
-
-# Convert require to import
-sg -p 'const $NAME = require("$MOD")' \
-   -r 'import $NAME from "$MOD"'
-
-# Add optional chaining
-sg -p '$OBJ.$PROP' -r '$OBJ?.$PROP'
-```
-
-## Security Patterns
-
-### SQL Injection
-
-```bash
-# Find string concatenation in queries
-sg -p 'query($_ + $_)'
-sg -p 'execute("$$$" + $_)'
-
-# Find template literals in queries
-sg -p 'query(`$$$${$_}$$$`)'
-```
-
-### XSS Vectors
-
-```bash
-# Find innerHTML assignments
-sg -p '$_.innerHTML = $_'
-
-# Find dangerouslySetInnerHTML
-sg -p 'dangerouslySetInnerHTML={{ __html: $_ }}'
-
-# Find eval calls
-sg -p 'eval($_)'
-
-# Find document.write
-sg -p 'document.write($_)'
-```
-
-### Secrets/Credentials
-
-```bash
-# Find hardcoded passwords
-sg -p 'password = "$_"'
-sg -p 'password: "$_"'
-
-# Find API keys
-sg -p 'apiKey = "$_"'
-sg -p 'API_KEY = "$_"'
-```
-
-## Advanced Usage
-
-### Context and Output
-
-```bash
-# Show surrounding lines
-sg -p 'console.log($_)' -A 3
-
-# JSON output
-sg -p 'console.log($_)' --json
-
-# File names only
-sg -p 'TODO' -l
-
-# Count matches
-sg -p 'console.log($_)' --count
-```
-
-### Combining with Other Tools
-
-```bash
-# Find and process with jq
-sg -p 'fetch($_)' --json | jq '.matches[].file'
-
-# Find in specific files
-fd -e ts | xargs sg -p 'useState($_)'
-
-# Interactive selection
-sg -p 'console.log($_)' -l | fzf | xargs code
-```
-
-### YAML Rules (Reusable Patterns)
-
-Create `.ast-grep.yml` for complex patterns:
-
-```yaml
-id: no-console-log
-language: typescript
-rule:
-  pattern: console.log($$$)
-message: Remove console.log before committing
-severity: warning
-```
-
-Run with:
-```bash
-sg scan
+# 10. Search specific language
+sg -p 'pattern' --lang typescript
 ```
 
 ## Quick Reference
@@ -342,13 +76,23 @@ sg scan
 | JSON output | `sg -p 'pattern' --json` |
 | File list only | `sg -p 'pattern' -l` |
 | Count matches | `sg -p 'pattern' --count` |
+| Run YAML rules | `sg scan` |
 
 ## When to Use
 
 - Finding all usages of a function/method
 - Locating specific code patterns (hooks, API calls)
 - Preparing for large-scale refactoring
-- Understanding code structure
 - When regex would match false positives
 - Detecting anti-patterns and security issues
 - Creating custom linting rules
+
+## Additional Resources
+
+For complete patterns, load:
+- `./references/js-ts-patterns.md` - JavaScript/TypeScript patterns
+- `./references/python-patterns.md` - Python patterns
+- `./references/go-rust-patterns.md` - Go and Rust patterns
+- `./references/security-patterns.md` - Security vulnerability detection
+- `./references/advanced-usage.md` - YAML rules and tool integration
+- `./assets/rule-template.yaml` - Starter template for custom rules

+ 36 - 0
skills/structural-search/assets/rule-template.yaml

@@ -0,0 +1,36 @@
+# ast-grep Rule Template
+# Place in project root or rules/ directory
+# Run with: sg scan
+
+id: rule-id-here
+language: typescript  # js, python, go, rust, etc.
+
+rule:
+  # Basic pattern match
+  pattern: console.log($$$)
+
+  # Or use conditions:
+  # any:
+  #   - pattern: console.log($$$)
+  #   - pattern: console.warn($$$)
+  #
+  # not:
+  #   pattern: console.error($$$)
+  #
+  # inside:
+  #   pattern: function $_ { $$$ }
+
+message: "Description of the issue"
+severity: warning  # error | warning | info | hint
+
+# Optional auto-fix
+# fix: "replacement using $METAVARS"
+
+# Optional additional context
+# note: "Explanation for developers"
+
+# Optional metadata
+# metadata:
+#   category: security
+#   references:
+#     - https://example.com/docs

+ 240 - 0
skills/structural-search/references/advanced-usage.md

@@ -0,0 +1,240 @@
+# Advanced Usage
+
+Advanced ast-grep features including YAML rules, output formatting, and tool integration.
+
+## Context and Output Options
+
+```bash
+# Show surrounding lines (context)
+sg -p 'console.log($_)' -A 3    # 3 lines after
+sg -p 'console.log($_)' -B 3    # 3 lines before
+sg -p 'console.log($_)' -C 3    # 3 lines both
+
+# JSON output (for scripting)
+sg -p 'console.log($_)' --json
+
+# File names only
+sg -p 'TODO' -l
+sg -p 'TODO' --files-with-matches
+
+# Count matches
+sg -p 'console.log($_)' --count
+
+# Report format
+sg -p 'console.log($_)' --report
+```
+
+## Combining with Other Tools
+
+```bash
+# Find and process with jq
+sg -p 'fetch($_)' --json | jq '.matches[].file'
+
+# Find in specific files
+fd -e ts | xargs sg -p 'useState($_)'
+
+# Interactive selection with fzf
+sg -p 'console.log($_)' -l | fzf | xargs code
+
+# Parallel search in large codebases
+fd -e ts -e tsx | xargs -P 4 sg -p 'useEffect($_)'
+
+# Combine with ripgrep for pre-filtering
+rg -l 'useState' | xargs sg -p 'const [$_, $_] = useState($_)'
+```
+
+## YAML Rules (Reusable Patterns)
+
+Create `.ast-grep.yml` or `sgconfig.yml` in project root:
+
+```yaml
+# Single rule file
+id: no-console-log
+language: typescript
+rule:
+  pattern: console.log($$$)
+message: Remove console.log before committing
+severity: warning
+```
+
+### Multiple Rules
+
+Create `rules/` directory with individual files:
+
+```yaml
+# rules/no-console.yml
+id: no-console-log
+language: typescript
+rule:
+  pattern: console.log($$$)
+message: Remove console.log statements
+severity: warning
+fix: "// removed: console.log"
+
+---
+# rules/prefer-const.yml
+id: prefer-const
+language: typescript
+rule:
+  pattern: var $NAME = $_
+message: Use const instead of var
+severity: error
+fix: const $NAME = $_
+```
+
+### Rule Configuration
+
+```yaml
+id: rule-identifier
+language: typescript  # js, python, go, rust, etc.
+
+rule:
+  # Match a pattern
+  pattern: console.log($$$)
+
+  # Or use multiple conditions
+  any:
+    - pattern: console.log($$$)
+    - pattern: console.warn($$$)
+
+  # Negative patterns
+  not:
+    pattern: console.error($$$)
+
+  # Inside specific context
+  inside:
+    pattern: function $_ { $$$ }
+
+message: "Human-readable warning message"
+severity: error | warning | info | hint
+note: "Additional context for the developer"
+
+# Optional auto-fix
+fix: "replacement code using $METAVARS"
+
+# Optional metadata
+metadata:
+  category: best-practice
+  references:
+    - https://example.com/rule-explanation
+```
+
+### Running Rules
+
+```bash
+# Scan with all rules
+sg scan
+
+# Scan specific directory
+sg scan src/
+
+# Scan with specific config
+sg scan --config sgconfig.yml
+
+# Test rules
+sg test
+
+# Auto-fix issues
+sg scan --fix
+```
+
+## Project Configuration
+
+Create `sgconfig.yml` in project root:
+
+```yaml
+# sgconfig.yml
+ruleDirs:
+  - rules/         # Directory containing rule files
+  - .ast-grep/     # Alternative rules location
+
+testConfigs:
+  - testDir: rules/tests/
+
+# Ignore patterns
+ignores:
+  - "**/node_modules/**"
+  - "**/dist/**"
+  - "**/*.min.js"
+
+# Language-specific settings
+languageGlobs:
+  typescript:
+    - "**/*.ts"
+    - "**/*.tsx"
+  python:
+    - "**/*.py"
+```
+
+## Rule Testing
+
+Create test files for rules:
+
+```yaml
+# rules/tests/no-console-test.yml
+id: no-console-log
+valid:
+  - const x = 1;
+  - logger.info("message");
+invalid:
+  - console.log("test");
+  - console.log(variable);
+```
+
+Run tests:
+```bash
+sg test
+```
+
+## Integration Patterns
+
+### Pre-commit Hook
+
+```yaml
+# .pre-commit-config.yaml
+repos:
+  - repo: local
+    hooks:
+      - id: ast-grep
+        name: ast-grep security
+        entry: sg scan --fail-on warning
+        language: system
+        types: [file]
+```
+
+### CI/CD Pipeline
+
+```yaml
+# GitHub Actions
+- name: AST Security Scan
+  run: |
+    sg scan --json > ast-grep-results.json
+    if [ $(jq '.diagnostics | length' ast-grep-results.json) -gt 0 ]; then
+      echo "Security issues found"
+      jq '.diagnostics[]' ast-grep-results.json
+      exit 1
+    fi
+```
+
+### VS Code Integration
+
+Install `ast-grep.ast-grep-vscode` extension for:
+- Real-time pattern matching
+- Inline warnings from rules
+- Quick fixes
+
+## Performance Tips
+
+```bash
+# Limit to specific directories
+sg -p 'pattern' src/ lib/
+
+# Use file type filters
+sg -p 'pattern' --lang typescript
+
+# Combine with fd for speed
+fd -e ts -x sg -p 'pattern' {}
+
+# Parallel processing
+find . -name "*.ts" -print0 | xargs -0 -P 4 sg -p 'pattern'
+```

+ 191 - 0
skills/structural-search/references/go-rust-patterns.md

@@ -0,0 +1,191 @@
+# Go and Rust Patterns
+
+Complete pattern library for ast-grep in Go and Rust.
+
+## Go Patterns
+
+### Function Declarations
+
+```bash
+# Find function declarations
+sg -p 'func $NAME($$$) $_ { $$$ }' --lang go
+
+# Find functions without return type
+sg -p 'func $NAME($$$) { $$$ }' --lang go
+
+# Find method declarations
+sg -p 'func ($_ $_) $NAME($$$) $_ { $$$ }' --lang go
+
+# Find pointer receiver methods
+sg -p 'func ($_ *$_) $NAME($$$) $_ { $$$ }' --lang go
+```
+
+### Type Definitions
+
+```bash
+# Find interface definitions
+sg -p 'type $NAME interface { $$$ }' --lang go
+
+# Find struct definitions
+sg -p 'type $NAME struct { $$$ }' --lang go
+
+# Find type aliases
+sg -p 'type $NAME = $_' --lang go
+```
+
+### Error Handling
+
+```bash
+# Find error checks
+sg -p 'if err != nil { $$$ }' --lang go
+
+# Find error returns
+sg -p 'return $_, err' --lang go
+
+# Find error wrapping
+sg -p 'fmt.Errorf($$$)' --lang go
+```
+
+### Concurrency
+
+```bash
+# Find goroutines
+sg -p 'go $_' --lang go
+
+# Find defer statements
+sg -p 'defer $_' --lang go
+
+# Find channel operations
+sg -p '$_ <- $_' --lang go
+
+# Find select statements
+sg -p 'select { $$$ }' --lang go
+
+# Find mutex locks
+sg -p '$_.Lock()' --lang go
+sg -p '$_.Unlock()' --lang go
+```
+
+### Common Patterns
+
+```bash
+# Find make calls
+sg -p 'make($_)' --lang go
+
+# Find new calls
+sg -p 'new($_)' --lang go
+
+# Find range loops
+sg -p 'for $_, $_ := range $_ { $$$ }' --lang go
+
+# Find init functions
+sg -p 'func init() { $$$ }' --lang go
+```
+
+---
+
+## Rust Patterns
+
+### Function Definitions
+
+```bash
+# Find function definitions with return type
+sg -p 'fn $NAME($$$) -> $_ { $$$ }' --lang rust
+
+# Find function definitions without return
+sg -p 'fn $NAME($$$) { $$$ }' --lang rust
+
+# Find async functions
+sg -p 'async fn $NAME($$$) -> $_ { $$$ }' --lang rust
+
+# Find public functions
+sg -p 'pub fn $NAME($$$) -> $_ { $$$ }' --lang rust
+```
+
+### Impl Blocks
+
+```bash
+# Find impl blocks
+sg -p 'impl $_ { $$$ }' --lang rust
+
+# Find trait implementations
+sg -p 'impl $_ for $_ { $$$ }' --lang rust
+
+# Find generic impl
+sg -p 'impl<$_> $_ { $$$ }' --lang rust
+```
+
+### Error Handling
+
+```bash
+# Find unwrap calls (potential panics)
+sg -p '$_.unwrap()' --lang rust
+
+# Find expect calls
+sg -p '$_.expect($_)' --lang rust
+
+# Find ? operator
+sg -p '$_?' --lang rust
+
+# Find Result types
+sg -p 'Result<$_, $_>' --lang rust
+
+# Find Option types
+sg -p 'Option<$_>' --lang rust
+```
+
+### Match Expressions
+
+```bash
+# Find match expressions
+sg -p 'match $_ { $$$ }' --lang rust
+
+# Find if let patterns
+sg -p 'if let $_ = $_ { $$$ }' --lang rust
+
+# Find while let patterns
+sg -p 'while let $_ = $_ { $$$ }' --lang rust
+```
+
+### Macros and Attributes
+
+```bash
+# Find derive attributes
+sg -p '#[derive($$$)]' --lang rust
+
+# Find macro invocations
+sg -p '$_!($$$)' --lang rust
+
+# Find specific macros
+sg -p 'println!($$$)' --lang rust
+sg -p 'vec![$$$]' --lang rust
+```
+
+### Async/Await
+
+```bash
+# Find .await calls
+sg -p '$_.await' --lang rust
+
+# Find tokio::spawn
+sg -p 'tokio::spawn($_)' --lang rust
+
+# Find async blocks
+sg -p 'async { $$$ }' --lang rust
+```
+
+### Smart Pointers
+
+```bash
+# Find Box usage
+sg -p 'Box::new($_)' --lang rust
+
+# Find Rc usage
+sg -p 'Rc::new($_)' --lang rust
+
+# Find Arc usage
+sg -p 'Arc::new($_)' --lang rust
+
+# Find RefCell
+sg -p 'RefCell::new($_)' --lang rust
+```

+ 137 - 0
skills/structural-search/references/js-ts-patterns.md

@@ -0,0 +1,137 @@
+# JavaScript/TypeScript Patterns
+
+Complete pattern library for ast-grep in JavaScript and TypeScript.
+
+## Function Calls
+
+```bash
+# Find all console.log calls
+sg -p 'console.log($_)'
+
+# Find all console methods
+sg -p 'console.$_($_)'
+
+# Find fetch calls
+sg -p 'fetch($_)'
+
+# Find await fetch
+sg -p 'await fetch($_)'
+
+# Find specific function calls
+sg -p 'getUserById($_)'
+
+# Find method chaining
+sg -p '$_.then($_).catch($_)'
+```
+
+## React Patterns
+
+```bash
+# Find useState hooks
+sg -p 'const [$_, $_] = useState($_)'
+
+# Find useEffect with dependencies
+sg -p 'useEffect($_, [$$$])'
+
+# Find useEffect without dependencies (runs every render)
+sg -p 'useEffect($_, [])'
+
+# Find component definitions
+sg -p 'function $NAME($$$) { return <$$$> }'
+
+# Find specific prop usage
+sg -p '<Button onClick={$_}>'
+
+# Find useState without destructuring
+sg -p 'useState($_)'
+```
+
+## Imports
+
+```bash
+# Find all imports from a module
+sg -p 'import $_ from "react"'
+
+# Find named imports
+sg -p 'import { $_ } from "lodash"'
+
+# Find default and named imports
+sg -p 'import $_, { $$$ } from $_'
+
+# Find dynamic imports
+sg -p 'import($_)'
+
+# Find require calls
+sg -p 'require($_)'
+```
+
+## Async Patterns
+
+```bash
+# Find async functions
+sg -p 'async function $NAME($$$) { $$$ }'
+
+# Find async arrow functions
+sg -p 'async ($$$) => { $$$ }'
+
+# Find try-catch blocks
+sg -p 'try { $$$ } catch ($_) { $$$ }'
+
+# Find Promise.all
+sg -p 'Promise.all([$$$])'
+
+# Find unhandled promises (no await)
+sg -p '$_.then($_)'
+```
+
+## Error Prone Patterns
+
+```bash
+# Find == instead of ===
+sg -p '$_ == $_'
+
+# Find assignments in conditions
+sg -p 'if ($_ = $_)'
+
+# Find empty catch blocks
+sg -p 'catch ($_) {}'
+
+# Find console.log (for cleanup)
+sg -p 'console.log($$$)'
+
+# Find TODO comments
+sg -p '// TODO$$$'
+
+# Find debugger statements
+sg -p 'debugger'
+```
+
+## Refactoring Patterns
+
+### Find and Replace
+
+```bash
+# Preview replacement
+sg -p 'console.log($_)' -r 'logger.info($_)'
+
+# Replace in place
+sg -p 'console.log($_)' -r 'logger.info($_)' --rewrite
+
+# Replace with context
+sg -p 'var $NAME = $_' -r 'const $NAME = $_'
+```
+
+### Common Refactors
+
+```bash
+# Convert function to arrow
+sg -p 'function $NAME($ARGS) { return $BODY }' \
+   -r 'const $NAME = ($ARGS) => $BODY'
+
+# Convert require to import
+sg -p 'const $NAME = require("$MOD")' \
+   -r 'import $NAME from "$MOD"'
+
+# Add optional chaining
+sg -p '$OBJ.$PROP' -r '$OBJ?.$PROP'
+```

+ 131 - 0
skills/structural-search/references/python-patterns.md

@@ -0,0 +1,131 @@
+# Python Patterns
+
+Complete pattern library for ast-grep in Python.
+
+## Function Definitions
+
+```bash
+# Find function definitions
+sg -p 'def $NAME($$$): $$$' --lang python
+
+# Find async function definitions
+sg -p 'async def $NAME($$$): $$$' --lang python
+
+# Find class definitions
+sg -p 'class $NAME: $$$' --lang python
+
+# Find class with inheritance
+sg -p 'class $NAME($_): $$$' --lang python
+```
+
+## Decorators
+
+```bash
+# Find any decorated functions
+sg -p '@$_
+def $NAME($$$): $$$' --lang python
+
+# Find pytest fixtures
+sg -p '@pytest.fixture
+def $NAME($$$): $$$' --lang python
+
+# Find Flask routes
+sg -p '@app.route($_)
+def $NAME($$$): $$$' --lang python
+
+# Find property decorators
+sg -p '@property
+def $NAME($$$): $$$' --lang python
+
+# Find classmethod/staticmethod
+sg -p '@classmethod
+def $NAME($$$): $$$' --lang python
+```
+
+## Imports
+
+```bash
+# Find standard imports
+sg -p 'import $_' --lang python
+
+# Find from imports
+sg -p 'from $_ import $_' --lang python
+
+# Find aliased imports
+sg -p 'import $_ as $_' --lang python
+
+# Find wildcard imports (anti-pattern)
+sg -p 'from $_ import *' --lang python
+```
+
+## Control Flow
+
+```bash
+# Find try-except blocks
+sg -p 'try:
+    $$$
+except $_:
+    $$$' --lang python
+
+# Find with statements (context managers)
+sg -p 'with $_ as $_: $$$' --lang python
+
+# Find list comprehensions
+sg -p '[$_ for $_ in $_]' --lang python
+
+# Find dict comprehensions
+sg -p '{$_: $_ for $_ in $_}' --lang python
+
+# Find generator expressions
+sg -p '($_ for $_ in $_)' --lang python
+```
+
+## String Formatting
+
+```bash
+# Find f-strings
+sg -p 'f"$$$"' --lang python
+
+# Find .format() calls
+sg -p '"$$$".format($$$)' --lang python
+
+# Find % formatting (old style)
+sg -p '"$$$" % $_' --lang python
+```
+
+## Common Patterns
+
+```bash
+# Find main block
+sg -p 'if __name__ == "__main__":
+    $$$' --lang python
+
+# Find dataclass definitions
+sg -p '@dataclass
+class $NAME:
+    $$$' --lang python
+
+# Find type hints
+sg -p 'def $NAME($$$) -> $_: $$$' --lang python
+
+# Find assert statements
+sg -p 'assert $_' --lang python
+
+# Find raise statements
+sg -p 'raise $_' --lang python
+```
+
+## Testing Patterns
+
+```bash
+# Find test functions
+sg -p 'def test_$NAME($$$): $$$' --lang python
+
+# Find pytest parametrize
+sg -p '@pytest.mark.parametrize($_)
+def $NAME($$$): $$$' --lang python
+
+# Find mock patches
+sg -p '@patch($_)
+def $NAME($$$): $$$' --lang python
+```

+ 163 - 0
skills/structural-search/references/security-patterns.md

@@ -0,0 +1,163 @@
+# Security Patterns
+
+AST patterns for detecting security vulnerabilities and anti-patterns.
+
+## SQL Injection
+
+```bash
+# Find string concatenation in queries
+sg -p 'query($_ + $_)'
+sg -p 'execute("$$$" + $_)'
+
+# Find template literals in queries
+sg -p 'query(`$$$${$_}$$$`)'
+
+# Find raw SQL with variables
+sg -p 'raw("$$$" + $_)'
+sg -p 'execute($_)' # Then inspect for string interpolation
+```
+
+## XSS Vectors
+
+```bash
+# Find innerHTML assignments
+sg -p '$_.innerHTML = $_'
+
+# Find dangerouslySetInnerHTML (React)
+sg -p 'dangerouslySetInnerHTML={{ __html: $_ }}'
+
+# Find eval calls
+sg -p 'eval($_)'
+
+# Find document.write
+sg -p 'document.write($_)'
+
+# Find outerHTML
+sg -p '$_.outerHTML = $_'
+
+# Find insertAdjacentHTML
+sg -p '$_.insertAdjacentHTML($_, $_)'
+```
+
+## Secrets/Credentials
+
+```bash
+# Find hardcoded passwords
+sg -p 'password = "$_"'
+sg -p 'password: "$_"'
+sg -p 'PASSWORD = "$_"'
+
+# Find API keys
+sg -p 'apiKey = "$_"'
+sg -p 'API_KEY = "$_"'
+sg -p 'api_key: "$_"'
+
+# Find tokens
+sg -p 'token = "$_"'
+sg -p 'TOKEN = "$_"'
+sg -p 'secret = "$_"'
+
+# Find AWS credentials
+sg -p 'aws_access_key_id = "$_"'
+sg -p 'aws_secret_access_key = "$_"'
+```
+
+## Command Injection
+
+```bash
+# Find exec calls with variables
+sg -p 'exec($_)' --lang python
+sg -p 'system($_)' --lang python
+sg -p 'subprocess.call($_)' --lang python
+
+# Find shell=True (dangerous)
+sg -p 'subprocess.run($$$, shell=True)' --lang python
+
+# Find child_process in Node.js
+sg -p 'exec($_)'
+sg -p 'execSync($_)'
+sg -p 'spawn($_)'
+```
+
+## Path Traversal
+
+```bash
+# Find path joins with user input
+sg -p 'path.join($_, req.$_)'
+sg -p 'os.path.join($_, $_)' --lang python
+
+# Find file operations with variables
+sg -p 'readFile($_)'
+sg -p 'writeFile($_)'
+sg -p 'open($_)' --lang python
+```
+
+## Cryptographic Issues
+
+```bash
+# Find weak hashing algorithms
+sg -p 'md5($_)'
+sg -p 'sha1($_)'
+sg -p 'createHash("md5")'
+sg -p 'createHash("sha1")'
+
+# Find Math.random for crypto (insecure)
+sg -p 'Math.random()'
+```
+
+## Authentication Issues
+
+```bash
+# Find JWT without verification
+sg -p 'jwt.decode($_)'  # vs jwt.verify
+
+# Find session without secure flag
+sg -p 'session: { secure: false }'
+
+# Find password comparison (timing attack)
+sg -p 'password === $_'
+sg -p 'password == $_'
+```
+
+## Python-Specific Security
+
+```bash
+# Find pickle (arbitrary code execution)
+sg -p 'pickle.load($_)' --lang python
+sg -p 'pickle.loads($_)' --lang python
+
+# Find yaml.load without Loader (unsafe)
+sg -p 'yaml.load($_)' --lang python
+
+# Find assert for security checks (removed in -O)
+sg -p 'assert $_' --lang python
+```
+
+## React/Frontend Security
+
+```bash
+# Find target="_blank" without rel (tabnabbing)
+sg -p '<$_ target="_blank">'
+
+# Find window.location assignment
+sg -p 'window.location = $_'
+sg -p 'window.location.href = $_'
+
+# Find postMessage without origin check
+sg -p 'postMessage($_)'
+```
+
+## Detection Workflow
+
+1. Run security patterns on codebase:
+```bash
+# Create a security scan script
+for pattern in 'eval($_)' '$_.innerHTML = $_' 'password = "$_"'; do
+  echo "=== $pattern ==="
+  sg -p "$pattern" -l
+done
+```
+
+2. Review matches for false positives
+3. Remediate confirmed issues
+4. Add patterns to CI/CD pipeline

+ 38 - 149
skills/tailwind-patterns/SKILL.md

@@ -7,63 +7,42 @@ allowed-tools: "Read Write"
 
 # Tailwind Patterns
 
-Quick reference for Tailwind CSS utility patterns, responsive design, and configuration.
+Quick reference for Tailwind CSS utility patterns.
 
 ## Responsive Breakpoints
 
-| Prefix | Min Width | CSS |
-|--------|-----------|-----|
-| `sm:` | 640px | `@media (min-width: 640px)` |
-| `md:` | 768px | `@media (min-width: 768px)` |
-| `lg:` | 1024px | `@media (min-width: 1024px)` |
-| `xl:` | 1280px | `@media (min-width: 1280px)` |
-| `2xl:` | 1536px | `@media (min-width: 1536px)` |
-
-**Mobile-first:** No prefix = mobile, add prefix for larger screens.
+| Prefix | Min Width |
+|--------|-----------|
+| `sm:` | 640px |
+| `md:` | 768px |
+| `lg:` | 1024px |
+| `xl:` | 1280px |
+| `2xl:` | 1536px |
 
 ```html
 <div class="w-full md:w-1/2 lg:w-1/3">
-  <!-- Full width on mobile, half on tablet, third on desktop -->
+  <!-- Full on mobile, half on tablet, third on desktop -->
 </div>
 ```
 
 ## Common Layout Patterns
 
-### Centered Container
 ```html
+<!-- Centered container -->
 <div class="container mx-auto px-4">
-  <!-- Centered with padding -->
-</div>
-```
 
-### Flexbox Row
-```html
+<!-- Flexbox row -->
 <div class="flex items-center justify-between gap-4">
-  <div>Left</div>
-  <div>Right</div>
-</div>
-```
 
-### Grid Layout
-```html
+<!-- Grid -->
 <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
-  <div>Card 1</div>
-  <div>Card 2</div>
-  <div>Card 3</div>
-</div>
-```
 
-### Stack (Vertical)
-```html
+<!-- Stack -->
 <div class="flex flex-col gap-4">
-  <div>Item 1</div>
-  <div>Item 2</div>
-</div>
 ```
 
-## Common Component Patterns
+## Card
 
-### Card
 ```html
 <div class="bg-white rounded-lg shadow-md p-6">
   <h3 class="text-lg font-semibold mb-2">Title</h3>
@@ -71,110 +50,31 @@ Quick reference for Tailwind CSS utility patterns, responsive design, and config
 </div>
 ```
 
-### Button Variants
+## Button
+
 ```html
-<!-- Primary -->
 <button class="bg-blue-600 text-white px-4 py-2 rounded-lg hover:bg-blue-700 transition-colors">
-  Primary
-</button>
-
-<!-- Secondary -->
-<button class="bg-gray-200 text-gray-800 px-4 py-2 rounded-lg hover:bg-gray-300 transition-colors">
-  Secondary
-</button>
-
-<!-- Outline -->
-<button class="border border-blue-600 text-blue-600 px-4 py-2 rounded-lg hover:bg-blue-50 transition-colors">
-  Outline
+  Button
 </button>
 ```
 
-### Form Input
+## Form Input
+
 ```html
-<input
-  type="text"
-  class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent"
-  placeholder="Enter text"
-/>
+<input type="text"
+  class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent"
+  placeholder="Enter text">
 ```
 
 ## Dark Mode
 
-### Class Strategy (Recommended)
-```js
-// tailwind.config.js
-module.exports = {
-  darkMode: 'class',
-  // ...
-}
-```
-
 ```html
-<!-- Add 'dark' class to html or parent -->
 <div class="bg-white dark:bg-gray-900 text-gray-900 dark:text-white">
-  Content adapts to dark mode
-</div>
-```
-
-### Media Strategy
-```js
-// tailwind.config.js
-module.exports = {
-  darkMode: 'media', // Uses prefers-color-scheme
-  // ...
-}
 ```
 
-## Minimal Config Template
-
 ```js
 // tailwind.config.js
-module.exports = {
-  content: [
-    './src/**/*.{js,ts,jsx,tsx,html}',
-  ],
-  darkMode: 'class',
-  theme: {
-    extend: {
-      colors: {
-        brand: {
-          50: '#f0f9ff',
-          500: '#3b82f6',
-          900: '#1e3a8a',
-        },
-      },
-      fontFamily: {
-        sans: ['Inter', 'sans-serif'],
-      },
-    },
-  },
-  plugins: [],
-}
-```
-
-## Spacing Scale Reference
-
-| Class | Size |
-|-------|------|
-| `p-0` | 0px |
-| `p-1` | 4px (0.25rem) |
-| `p-2` | 8px (0.5rem) |
-| `p-4` | 16px (1rem) |
-| `p-6` | 24px (1.5rem) |
-| `p-8` | 32px (2rem) |
-| `p-12` | 48px (3rem) |
-| `p-16` | 64px (4rem) |
-
-Same scale applies to: `m-`, `gap-`, `w-`, `h-`, `space-x-`, `space-y-`
-
-## Arbitrary Values
-
-When the scale doesn't have what you need:
-
-```html
-<div class="w-[137px] h-[calc(100vh-64px)] top-[17px]">
-  <!-- Exact values when needed -->
-</div>
+module.exports = { darkMode: 'class' }
 ```
 
 ## State Modifiers
@@ -186,35 +86,24 @@ When the scale doesn't have what you need:
 | `active:` | Being clicked |
 | `disabled:` | Disabled state |
 | `group-hover:` | Parent hovered |
-| `first:` | First child |
-| `last:` | Last child |
-| `odd:` | Odd children |
-| `even:` | Even children |
-
-```html
-<button class="bg-blue-500 hover:bg-blue-600 active:bg-blue-700 disabled:opacity-50">
-  Button
-</button>
-```
-
-## Performance Tips
 
-1. **Content configuration** - Ensure all template paths are in `content` array
-2. **Avoid @apply overuse** - Prefer utility classes directly
-3. **Use CSS variables** for dynamic values that change at runtime
-4. **Purge in production** - Tailwind does this automatically via `content`
+## Spacing Scale
 
-## Class Organization
+| Class | Size |
+|-------|------|
+| `p-1` | 4px |
+| `p-2` | 8px |
+| `p-4` | 16px |
+| `p-6` | 24px |
+| `p-8` | 32px |
 
-Recommended order for readability:
-1. Layout (flex, grid, position)
-2. Box model (w, h, p, m)
-3. Typography (text, font)
-4. Visual (bg, border, shadow)
-5. Interactive (hover, focus)
+## Arbitrary Values
 
 ```html
-<div class="flex items-center | w-full p-4 | text-lg font-medium | bg-white border rounded-lg | hover:shadow-md">
-  <!-- Pipes are comments for organization -->
-</div>
+<div class="w-[137px] h-[calc(100vh-64px)]">
 ```
+
+## Additional Resources
+
+For detailed patterns, load:
+- `./references/component-patterns.md` - Navbar, cards, forms, alerts, loading states

+ 317 - 0
skills/tailwind-patterns/references/component-patterns.md

@@ -0,0 +1,317 @@
+# Tailwind Component Patterns
+
+Ready-to-use component patterns with Tailwind CSS.
+
+## Navigation
+
+### Navbar
+
+```html
+<nav class="bg-white shadow">
+  <div class="container mx-auto px-4">
+    <div class="flex items-center justify-between h-16">
+      <!-- Logo -->
+      <a href="/" class="text-xl font-bold text-gray-900">Logo</a>
+
+      <!-- Desktop Menu -->
+      <div class="hidden md:flex items-center space-x-8">
+        <a href="#" class="text-gray-600 hover:text-gray-900">Home</a>
+        <a href="#" class="text-gray-600 hover:text-gray-900">Features</a>
+        <a href="#" class="text-gray-600 hover:text-gray-900">Pricing</a>
+        <a href="#" class="bg-blue-600 text-white px-4 py-2 rounded-lg hover:bg-blue-700">
+          Get Started
+        </a>
+      </div>
+
+      <!-- Mobile Menu Button -->
+      <button class="md:hidden p-2">
+        <svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
+          <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
+                d="M4 6h16M4 12h16M4 18h16"/>
+        </svg>
+      </button>
+    </div>
+  </div>
+</nav>
+```
+
+### Sidebar
+
+```html
+<aside class="w-64 bg-gray-900 text-white min-h-screen">
+  <div class="p-4">
+    <h2 class="text-lg font-semibold mb-4">Dashboard</h2>
+    <nav class="space-y-2">
+      <a href="#" class="flex items-center px-4 py-2 bg-gray-800 rounded-lg">
+        <svg class="w-5 h-5 mr-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
+          <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
+                d="M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6"/>
+        </svg>
+        Home
+      </a>
+      <a href="#" class="flex items-center px-4 py-2 text-gray-400 hover:bg-gray-800 hover:text-white rounded-lg transition-colors">
+        <svg class="w-5 h-5 mr-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
+          <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
+                d="M12 4.354a4 4 0 110 5.292M15 21H3v-1a6 6 0 0112 0v1zm0 0h6v-1a6 6 0 00-9-5.197M13 7a4 4 0 11-8 0 4 4 0 018 0z"/>
+        </svg>
+        Users
+      </a>
+    </nav>
+  </div>
+</aside>
+```
+
+## Cards
+
+### Feature Card
+
+```html
+<div class="bg-white rounded-xl shadow-lg p-6 hover:shadow-xl transition-shadow">
+  <div class="w-12 h-12 bg-blue-100 rounded-lg flex items-center justify-center mb-4">
+    <svg class="w-6 h-6 text-blue-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
+      <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
+            d="M13 10V3L4 14h7v7l9-11h-7z"/>
+    </svg>
+  </div>
+  <h3 class="text-lg font-semibold text-gray-900 mb-2">Lightning Fast</h3>
+  <p class="text-gray-600">Optimized for speed with edge computing and CDN distribution.</p>
+</div>
+```
+
+### Profile Card
+
+```html
+<div class="bg-white rounded-xl shadow-lg overflow-hidden max-w-sm">
+  <div class="h-32 bg-gradient-to-r from-blue-500 to-purple-600"></div>
+  <div class="relative px-6 pb-6">
+    <img src="avatar.jpg" alt="Profile"
+         class="w-24 h-24 rounded-full border-4 border-white absolute -top-12">
+    <div class="pt-16">
+      <h3 class="text-xl font-bold text-gray-900">Jane Doe</h3>
+      <p class="text-gray-500">Senior Developer</p>
+      <div class="flex gap-4 mt-4">
+        <div class="text-center">
+          <div class="text-xl font-bold text-gray-900">142</div>
+          <div class="text-sm text-gray-500">Posts</div>
+        </div>
+        <div class="text-center">
+          <div class="text-xl font-bold text-gray-900">4.2k</div>
+          <div class="text-sm text-gray-500">Followers</div>
+        </div>
+      </div>
+    </div>
+  </div>
+</div>
+```
+
+### Pricing Card
+
+```html
+<div class="bg-white rounded-2xl shadow-xl p-8 border-2 border-blue-500 relative">
+  <div class="absolute -top-4 left-1/2 -translate-x-1/2 bg-blue-500 text-white px-4 py-1 rounded-full text-sm font-medium">
+    Popular
+  </div>
+  <h3 class="text-xl font-bold text-gray-900">Pro</h3>
+  <div class="mt-4">
+    <span class="text-4xl font-bold">$29</span>
+    <span class="text-gray-500">/month</span>
+  </div>
+  <ul class="mt-6 space-y-3">
+    <li class="flex items-center text-gray-600">
+      <svg class="w-5 h-5 text-green-500 mr-2" fill="currentColor" viewBox="0 0 20 20">
+        <path fill-rule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clip-rule="evenodd"/>
+      </svg>
+      Unlimited projects
+    </li>
+    <li class="flex items-center text-gray-600">
+      <svg class="w-5 h-5 text-green-500 mr-2" fill="currentColor" viewBox="0 0 20 20">
+        <path fill-rule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clip-rule="evenodd"/>
+      </svg>
+      Advanced analytics
+    </li>
+    <li class="flex items-center text-gray-600">
+      <svg class="w-5 h-5 text-green-500 mr-2" fill="currentColor" viewBox="0 0 20 20">
+        <path fill-rule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clip-rule="evenodd"/>
+      </svg>
+      Priority support
+    </li>
+  </ul>
+  <button class="w-full mt-8 bg-blue-600 text-white py-3 rounded-lg font-medium hover:bg-blue-700 transition-colors">
+    Get Started
+  </button>
+</div>
+```
+
+## Forms
+
+### Login Form
+
+```html
+<form class="bg-white rounded-xl shadow-lg p-8 max-w-md mx-auto">
+  <h2 class="text-2xl font-bold text-gray-900 mb-6">Welcome back</h2>
+
+  <div class="space-y-4">
+    <div>
+      <label for="email" class="block text-sm font-medium text-gray-700 mb-1">Email</label>
+      <input type="email" id="email"
+             class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent"
+             placeholder="you@example.com">
+    </div>
+
+    <div>
+      <label for="password" class="block text-sm font-medium text-gray-700 mb-1">Password</label>
+      <input type="password" id="password"
+             class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent"
+             placeholder="••••••••">
+    </div>
+
+    <div class="flex items-center justify-between">
+      <label class="flex items-center">
+        <input type="checkbox" class="rounded border-gray-300 text-blue-600 focus:ring-blue-500">
+        <span class="ml-2 text-sm text-gray-600">Remember me</span>
+      </label>
+      <a href="#" class="text-sm text-blue-600 hover:underline">Forgot password?</a>
+    </div>
+
+    <button type="submit"
+            class="w-full bg-blue-600 text-white py-2 rounded-lg font-medium hover:bg-blue-700 transition-colors">
+      Sign in
+    </button>
+  </div>
+</form>
+```
+
+### Search Input with Button
+
+```html
+<div class="flex max-w-lg">
+  <input type="text"
+         class="flex-1 px-4 py-2 border border-gray-300 rounded-l-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent"
+         placeholder="Search...">
+  <button class="px-6 py-2 bg-blue-600 text-white rounded-r-lg hover:bg-blue-700 transition-colors">
+    Search
+  </button>
+</div>
+```
+
+## Lists
+
+### Task List
+
+```html
+<ul class="bg-white rounded-xl shadow divide-y">
+  <li class="flex items-center px-6 py-4 hover:bg-gray-50">
+    <input type="checkbox" class="rounded border-gray-300 text-blue-600 focus:ring-blue-500">
+    <span class="ml-4 flex-1">Complete project documentation</span>
+    <span class="text-sm text-gray-500">Due tomorrow</span>
+  </li>
+  <li class="flex items-center px-6 py-4 hover:bg-gray-50">
+    <input type="checkbox" checked class="rounded border-gray-300 text-blue-600 focus:ring-blue-500">
+    <span class="ml-4 flex-1 line-through text-gray-400">Review pull requests</span>
+    <span class="text-sm text-gray-500">Completed</span>
+  </li>
+</ul>
+```
+
+### User List
+
+```html
+<div class="bg-white rounded-xl shadow divide-y">
+  <div class="flex items-center px-6 py-4">
+    <img src="avatar1.jpg" class="w-10 h-10 rounded-full" alt="User">
+    <div class="ml-4 flex-1">
+      <h4 class="font-medium text-gray-900">John Smith</h4>
+      <p class="text-sm text-gray-500">john@example.com</p>
+    </div>
+    <span class="px-3 py-1 text-xs font-medium bg-green-100 text-green-800 rounded-full">Active</span>
+  </div>
+</div>
+```
+
+## Alerts/Badges
+
+### Alert Types
+
+```html
+<!-- Success -->
+<div class="bg-green-50 border-l-4 border-green-500 p-4 rounded-r-lg">
+  <div class="flex items-center">
+    <svg class="w-5 h-5 text-green-500" fill="currentColor" viewBox="0 0 20 20">
+      <path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clip-rule="evenodd"/>
+    </svg>
+    <span class="ml-3 text-green-800">Changes saved successfully!</span>
+  </div>
+</div>
+
+<!-- Error -->
+<div class="bg-red-50 border-l-4 border-red-500 p-4 rounded-r-lg">
+  <div class="flex items-center">
+    <svg class="w-5 h-5 text-red-500" fill="currentColor" viewBox="0 0 20 20">
+      <path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z" clip-rule="evenodd"/>
+    </svg>
+    <span class="ml-3 text-red-800">Error processing your request.</span>
+  </div>
+</div>
+
+<!-- Warning -->
+<div class="bg-yellow-50 border-l-4 border-yellow-500 p-4 rounded-r-lg">
+  <span class="text-yellow-800">Please review before submitting.</span>
+</div>
+
+<!-- Info -->
+<div class="bg-blue-50 border-l-4 border-blue-500 p-4 rounded-r-lg">
+  <span class="text-blue-800">New features are now available.</span>
+</div>
+```
+
+### Badges
+
+```html
+<!-- Status badges -->
+<span class="px-2 py-1 text-xs font-medium bg-green-100 text-green-800 rounded-full">Active</span>
+<span class="px-2 py-1 text-xs font-medium bg-yellow-100 text-yellow-800 rounded-full">Pending</span>
+<span class="px-2 py-1 text-xs font-medium bg-red-100 text-red-800 rounded-full">Inactive</span>
+<span class="px-2 py-1 text-xs font-medium bg-gray-100 text-gray-800 rounded-full">Draft</span>
+
+<!-- Notification badge -->
+<div class="relative inline-block">
+  <button class="p-2">
+    <svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
+      <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 17h5l-1.405-1.405A2.032 2.032 0 0118 14.158V11a6.002 6.002 0 00-4-5.659V5a2 2 0 10-4 0v.341C7.67 6.165 6 8.388 6 11v3.159c0 .538-.214 1.055-.595 1.436L4 17h5m6 0v1a3 3 0 11-6 0v-1m6 0H9"/>
+    </svg>
+  </button>
+  <span class="absolute -top-1 -right-1 w-5 h-5 bg-red-500 text-white text-xs rounded-full flex items-center justify-center">3</span>
+</div>
+```
+
+## Loading States
+
+### Spinner
+
+```html
+<div class="flex items-center justify-center">
+  <div class="animate-spin rounded-full h-8 w-8 border-b-2 border-blue-600"></div>
+</div>
+```
+
+### Skeleton
+
+```html
+<div class="animate-pulse space-y-4">
+  <div class="h-4 bg-gray-200 rounded w-3/4"></div>
+  <div class="h-4 bg-gray-200 rounded w-1/2"></div>
+  <div class="h-4 bg-gray-200 rounded w-5/6"></div>
+</div>
+```
+
+### Button Loading
+
+```html
+<button class="flex items-center px-4 py-2 bg-blue-600 text-white rounded-lg" disabled>
+  <svg class="animate-spin -ml-1 mr-2 h-4 w-4" fill="none" viewBox="0 0 24 24">
+    <circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"/>
+    <path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"/>
+  </svg>
+  Processing...
+</button>
+```

+ 160 - 0
skills/testing-patterns/SKILL.md

@@ -0,0 +1,160 @@
+---
+name: testing-patterns
+description: "Cross-language testing strategies and patterns. Triggers on: test pyramid, unit test, integration test, e2e test, TDD, BDD, test coverage, mocking strategy, test doubles, test isolation."
+compatibility: "Language-agnostic patterns. Framework-specific details in references."
+allowed-tools: "Read Write Bash"
+---
+
+# Testing Patterns
+
+Universal testing strategies and patterns applicable across languages.
+
+## The Test Pyramid
+
+```
+        /\
+       /  \     E2E Tests (few, slow, expensive)
+      /    \    - Full system tests
+     /------\   - Real browser/API calls
+    /        \
+   /  Integ   \ Integration Tests (some)
+  /   Tests    \ - Service boundaries
+ /--------------\ - Database, APIs
+/                \
+/   Unit Tests    \ Unit Tests (many, fast, cheap)
+------------------  - Single function/class
+                    - Mocked dependencies
+```
+
+## Test Types
+
+### Unit Tests
+```
+Scope:      Single function/method/class
+Speed:      Milliseconds
+Dependencies: All mocked
+When:       Every code change
+Coverage:   80%+ of codebase
+```
+
+### Integration Tests
+```
+Scope:      Multiple components together
+Speed:      Seconds
+Dependencies: Real databases, mocked external APIs
+When:       PR/merge, critical paths
+Coverage:   Key integration points
+```
+
+### End-to-End Tests
+```
+Scope:      Full user journey
+Speed:      Minutes
+Dependencies: Real system (or staging)
+When:       Pre-deploy, nightly
+Coverage:   Critical user flows only
+```
+
+## Test Naming Convention
+
+```
+test_<unit>_<scenario>_<expected>
+
+Examples:
+- test_calculate_total_with_discount_returns_reduced_price
+- test_user_login_with_invalid_password_returns_401
+- test_order_submit_when_out_of_stock_raises_error
+```
+
+## Arrange-Act-Assert (AAA)
+
+```python
+def test_calculate_discount():
+    # Arrange - Set up test data and dependencies
+    cart = Cart()
+    cart.add_item(Item(price=100))
+    discount = Discount(percent=10)
+
+    # Act - Execute the code under test
+    total = cart.calculate_total(discount)
+
+    # Assert - Verify the results
+    assert total == 90
+```
+
+## Test Doubles
+
+| Type | Purpose | Example |
+|------|---------|---------|
+| **Stub** | Returns canned data | `stub.get_user.returns(fake_user)` |
+| **Mock** | Verifies interactions | `mock.send_email.assert_called_once()` |
+| **Spy** | Records calls, uses real impl | `spy.on(service, 'save')` |
+| **Fake** | Working simplified impl | `FakeDatabase()` instead of real DB |
+| **Dummy** | Placeholder, never used | `null` object for required param |
+
+## Test Isolation Strategies
+
+### Database Isolation
+```
+Option 1: Transaction rollback (fast)
+- Start transaction before test
+- Rollback after test
+
+Option 2: Truncate tables (medium)
+- Clear all data between tests
+
+Option 3: Separate database (slow)
+- Each test gets fresh database
+```
+
+### External Service Isolation
+```
+Option 1: Mock at boundary
+- Replace HTTP client with mock
+
+Option 2: Fake server
+- WireMock, MSW, VCR cassettes
+
+Option 3: Contract testing
+- Pact, consumer-driven contracts
+```
+
+## What to Test
+
+### MUST Test
+- Business logic and calculations
+- Input validation and error handling
+- Security-sensitive code (auth, permissions)
+- Edge cases and boundary conditions
+
+### SHOULD Test
+- Integration points (DB, APIs)
+- State transitions
+- Configuration handling
+
+### AVOID Testing
+- Framework internals
+- Third-party library behavior
+- Simple getters/setters
+- Private implementation details
+
+## Test Quality Checklist
+
+- [ ] Tests are independent (no order dependency)
+- [ ] Tests are deterministic (no flaky tests)
+- [ ] Tests are fast (unit < 100ms, integration < 5s)
+- [ ] Tests have clear names describing behavior
+- [ ] Tests cover happy path AND error cases
+- [ ] Tests don't repeat production logic
+- [ ] Mocks are minimal (only external boundaries)
+
+## Additional Resources
+
+- `./references/tdd-workflow.md` - Test-Driven Development cycle
+- `./references/mocking-strategies.md` - When and how to mock
+- `./references/test-data-patterns.md` - Fixtures, factories, builders
+- `./references/ci-testing.md` - Testing in CI/CD pipelines
+
+## Scripts
+
+- `./scripts/coverage-check.sh` - Run coverage and fail if below threshold

+ 293 - 0
skills/testing-patterns/references/ci-testing.md

@@ -0,0 +1,293 @@
+# CI/CD Testing Patterns
+
+Testing strategies for continuous integration pipelines.
+
+## Test Pipeline Stages
+
+```
+┌─────────────────────────────────────────────────────────────────┐
+│                        CI Pipeline                               │
+│                                                                  │
+│  ┌──────┐   ┌──────┐   ┌───────┐   ┌─────┐   ┌──────┐   ┌────┐│
+│  │ Lint │ → │ Unit │ → │ Build │ → │Integ│ → │  E2E │ → │Dep.││
+│  │      │   │Tests │   │       │   │Tests│   │Tests │   │    ││
+│  └──────┘   └──────┘   └───────┘   └─────┘   └──────┘   └────┘│
+│     1m        2-5m       1-3m       5-10m     10-30m      -   │
+│                                                                  │
+│  ◄─────── Fast Feedback ───────►  ◄─── Comprehensive ──────►   │
+└─────────────────────────────────────────────────────────────────┘
+```
+
+## GitHub Actions Example
+
+```yaml
+name: CI
+
+on:
+  push:
+    branches: [main]
+  pull_request:
+    branches: [main]
+
+jobs:
+  lint:
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@v4
+      - uses: actions/setup-python@v5
+        with:
+          python-version: '3.11'
+      - name: Lint
+        run: |
+          pip install ruff
+          ruff check .
+
+  unit-tests:
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@v4
+      - uses: actions/setup-python@v5
+        with:
+          python-version: '3.11'
+      - name: Install dependencies
+        run: pip install -e .[test]
+      - name: Run unit tests
+        run: pytest tests/unit -v --cov=src --cov-report=xml
+      - name: Upload coverage
+        uses: codecov/codecov-action@v4
+
+  integration-tests:
+    needs: unit-tests
+    runs-on: ubuntu-latest
+    services:
+      postgres:
+        image: postgres:15
+        env:
+          POSTGRES_PASSWORD: postgres
+        ports:
+          - 5432:5432
+        options: >-
+          --health-cmd pg_isready
+          --health-interval 10s
+          --health-timeout 5s
+          --health-retries 5
+    steps:
+      - uses: actions/checkout@v4
+      - uses: actions/setup-python@v5
+        with:
+          python-version: '3.11'
+      - name: Run integration tests
+        env:
+          DATABASE_URL: postgres://postgres:postgres@localhost:5432/test
+        run: pytest tests/integration -v
+
+  e2e-tests:
+    needs: integration-tests
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@v4
+      - name: Run E2E tests
+        run: |
+          docker-compose up -d
+          pytest tests/e2e -v
+          docker-compose down
+```
+
+## Test Parallelization
+
+### pytest-xdist
+
+```yaml
+- name: Run tests in parallel
+  run: pytest -n auto  # Use all available CPUs
+
+- name: Run with specific workers
+  run: pytest -n 4  # 4 parallel workers
+```
+
+### Matrix Testing
+
+```yaml
+jobs:
+  test:
+    strategy:
+      matrix:
+        python-version: ['3.9', '3.10', '3.11']
+        os: [ubuntu-latest, macos-latest]
+    runs-on: ${{ matrix.os }}
+    steps:
+      - uses: actions/setup-python@v5
+        with:
+          python-version: ${{ matrix.python-version }}
+      - run: pytest
+```
+
+### Sharded Tests
+
+```yaml
+jobs:
+  test:
+    strategy:
+      matrix:
+        shard: [1, 2, 3, 4]
+    steps:
+      - name: Run test shard
+        run: pytest --shard-id=${{ matrix.shard }} --num-shards=4
+```
+
+## Caching for Speed
+
+```yaml
+- name: Cache pip packages
+  uses: actions/cache@v4
+  with:
+    path: ~/.cache/pip
+    key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements*.txt') }}
+    restore-keys: |
+      ${{ runner.os }}-pip-
+
+- name: Cache pytest
+  uses: actions/cache@v4
+  with:
+    path: .pytest_cache
+    key: pytest-${{ github.sha }}
+    restore-keys: pytest-
+```
+
+## Flaky Test Handling
+
+### Retry Mechanism
+
+```yaml
+- name: Run tests with retry
+  uses: nick-fields/retry@v3
+  with:
+    timeout_minutes: 10
+    max_attempts: 3
+    command: pytest tests/e2e
+```
+
+### pytest-rerunfailures
+
+```bash
+# Rerun failed tests up to 3 times
+pytest --reruns 3 --reruns-delay 1
+```
+
+### Quarantine Flaky Tests
+
+```python
+@pytest.mark.flaky(reruns=3, reruns_delay=2)
+def test_sometimes_fails():
+    # This test is known to be flaky
+    pass
+
+@pytest.mark.skip(reason="Flaky - investigating")
+def test_quarantined():
+    pass
+```
+
+## Test Reports
+
+### JUnit XML
+
+```yaml
+- name: Run tests
+  run: pytest --junitxml=results.xml
+
+- name: Publish Test Results
+  uses: dorny/test-reporter@v1
+  if: always()
+  with:
+    name: Test Results
+    path: results.xml
+    reporter: java-junit
+```
+
+### Coverage Reports
+
+```yaml
+- name: Run with coverage
+  run: pytest --cov=src --cov-report=xml --cov-report=html
+
+- name: Upload coverage to Codecov
+  uses: codecov/codecov-action@v4
+  with:
+    files: ./coverage.xml
+    fail_ci_if_error: true
+
+- name: Coverage comment on PR
+  uses: py-cov-action/python-coverage-comment-action@v3
+```
+
+## Branch Protection Rules
+
+```yaml
+# Require tests to pass before merge
+# Settings → Branches → Branch protection rules
+
+Required status checks:
+  - lint
+  - unit-tests
+  - integration-tests
+
+Require branches to be up to date: Yes
+```
+
+## Test Selection
+
+### Changed Files Only
+
+```yaml
+- name: Get changed files
+  id: changed
+  uses: tj-actions/changed-files@v41
+  with:
+    files: |
+      src/**
+      tests/**
+
+- name: Run affected tests
+  if: steps.changed.outputs.any_changed == 'true'
+  run: pytest tests/ -v
+```
+
+### Skip Expensive Tests
+
+```yaml
+- name: Quick tests on PR
+  if: github.event_name == 'pull_request'
+  run: pytest -m "not slow and not e2e"
+
+- name: Full tests on main
+  if: github.ref == 'refs/heads/main'
+  run: pytest
+```
+
+## Secrets in Tests
+
+```yaml
+- name: Run tests with secrets
+  env:
+    API_KEY: ${{ secrets.TEST_API_KEY }}
+    DATABASE_URL: ${{ secrets.TEST_DATABASE_URL }}
+  run: pytest tests/integration
+
+# Use environment for sensitive tests
+jobs:
+  integration:
+    environment: testing  # Requires approval
+    steps:
+      - run: pytest tests/integration
+```
+
+## Best Practices
+
+1. **Fast feedback first** - Run linting and unit tests before slow tests
+2. **Fail fast** - Stop pipeline on first failure (`pytest -x`)
+3. **Parallel when possible** - Use matrix builds and xdist
+4. **Cache aggressively** - Pip, node_modules, docker layers
+5. **Keep tests deterministic** - No reliance on external state
+6. **Isolate flaky tests** - Quarantine or fix, don't ignore
+7. **Report clearly** - Use test reporters and coverage comments
+8. **Secure secrets** - Never log, use GitHub secrets

+ 239 - 0
skills/testing-patterns/references/mocking-strategies.md

@@ -0,0 +1,239 @@
+# Mocking Strategies
+
+When, what, and how to mock effectively.
+
+## When to Mock
+
+### ALWAYS Mock
+- External HTTP APIs
+- Databases in unit tests
+- File system in unit tests
+- Time-dependent operations
+- Random number generators
+- Email/SMS services
+
+### SOMETIMES Mock
+- Internal services (depends on test type)
+- Caches
+- Message queues
+
+### NEVER Mock
+- The code under test itself
+- Simple value objects
+- Pure functions without side effects
+
+## The Testing Boundary
+
+```
+┌─────────────────────────────────────────────────────┐
+│                  Your Application                    │
+│                                                      │
+│  ┌──────────┐    ┌──────────┐    ┌──────────┐      │
+│  │ Business │ -> │ Service  │ -> │Repository│      │
+│  │  Logic   │    │  Layer   │    │  Layer   │      │
+│  └──────────┘    └──────────┘    └──────────┘      │
+│                                        │            │
+│                                        ▼            │
+│                              ┌─────────────────┐   │
+│                              │   BOUNDARY      │   │
+│                              │ (Mock Here!)    │   │
+│                              └─────────────────┘   │
+│                                        │            │
+└────────────────────────────────────────│────────────┘
+                                         ▼
+                              ┌─────────────────┐
+                              │External Services│
+                              │ - Database      │
+                              │ - APIs          │
+                              │ - File System   │
+                              └─────────────────┘
+```
+
+## Mock Patterns
+
+### Stub Pattern (Canned Responses)
+
+```python
+# Use when you need predictable return values
+def test_get_user_returns_user_data(mocker):
+    mock_db = mocker.patch("app.database.get_user")
+    mock_db.return_value = {"id": 1, "name": "Alice"}
+
+    result = user_service.get_user(1)
+
+    assert result["name"] == "Alice"
+```
+
+### Mock Pattern (Verify Interactions)
+
+```python
+# Use when you need to verify calls were made
+def test_order_sends_confirmation_email(mocker):
+    mock_email = mocker.patch("app.email.send")
+
+    order_service.place_order(user_id=1, items=[...])
+
+    mock_email.assert_called_once_with(
+        to="user@example.com",
+        subject="Order Confirmation",
+        body=mocker.ANY
+    )
+```
+
+### Spy Pattern (Record + Real Implementation)
+
+```python
+# Use when you want real behavior but need to track calls
+def test_caching_reduces_db_calls(mocker):
+    spy = mocker.spy(database, "query")
+
+    # First call hits database
+    result1 = cached_service.get_data("key")
+    # Second call should use cache
+    result2 = cached_service.get_data("key")
+
+    assert spy.call_count == 1  # Only called once
+    assert result1 == result2
+```
+
+### Fake Pattern (Simplified Implementation)
+
+```python
+# Use for complex dependencies that need real behavior
+class FakeEmailService:
+    def __init__(self):
+        self.sent_emails = []
+
+    def send(self, to, subject, body):
+        self.sent_emails.append({
+            "to": to,
+            "subject": subject,
+            "body": body
+        })
+
+def test_order_workflow(fake_email):
+    order_service = OrderService(email_service=fake_email)
+    order_service.place_order(user_id=1, items=[...])
+
+    assert len(fake_email.sent_emails) == 1
+    assert "Order Confirmation" in fake_email.sent_emails[0]["subject"]
+```
+
+## Mock Anti-Patterns
+
+### Over-Mocking
+
+```python
+# BAD - Mocking everything
+def test_order_total(mocker):
+    mock_cart = mocker.Mock()
+    mock_item = mocker.Mock()
+    mock_item.price = 100
+    mock_cart.items = [mock_item]
+    mock_cart.calculate_total.return_value = 100  # ?!
+
+    # This tests nothing - we mocked the thing we're testing!
+    assert mock_cart.calculate_total() == 100
+
+# GOOD - Only mock boundaries
+def test_order_total():
+    cart = Cart()
+    cart.add_item(Item(price=100))
+
+    assert cart.calculate_total() == 100
+```
+
+### Mocking Too Deep
+
+```python
+# BAD - Mocking internal implementation
+def test_process_order(mocker):
+    mocker.patch("app.order.Order._validate_inventory")
+    mocker.patch("app.order.Order._calculate_tax")
+    mocker.patch("app.order.Order._apply_discount")
+    # Now coupled to internal implementation!
+
+# GOOD - Mock at the boundary
+def test_process_order(mocker):
+    mocker.patch("app.inventory_service.check_availability")
+    mocker.patch("app.tax_service.calculate")
+    # External services, not internal methods
+```
+
+### Mock Setup Longer Than Test
+
+```python
+# BAD - Test is mostly setup
+def test_user_registration(mocker):
+    mock_db = mocker.patch("app.db")
+    mock_email = mocker.patch("app.email")
+    mock_validator = mocker.patch("app.validator")
+    mock_logger = mocker.patch("app.logger")
+    mock_db.create_user.return_value = {"id": 1}
+    mock_email.send.return_value = True
+    mock_validator.validate.return_value = []
+    # ... 20 more lines of setup
+
+    # The actual test is tiny
+    result = register_user("test@example.com")
+    assert result.success
+
+# GOOD - Use fixtures and factories
+@pytest.fixture
+def registration_mocks(mocker):
+    return RegistrationMocks(mocker)  # Encapsulate setup
+
+def test_user_registration(registration_mocks):
+    result = register_user("test@example.com")
+    assert result.success
+```
+
+## Dependency Injection for Testability
+
+```python
+# Hard to test - creates own dependencies
+class OrderService:
+    def __init__(self):
+        self.db = Database()  # Can't mock!
+        self.email = EmailService()
+
+# Easy to test - dependencies injected
+class OrderService:
+    def __init__(self, db: Database, email: EmailService):
+        self.db = db
+        self.email = email
+
+# Test with mocks
+def test_order_service(mocker):
+    mock_db = mocker.Mock()
+    mock_email = mocker.Mock()
+    service = OrderService(db=mock_db, email=mock_email)
+```
+
+## Contract Testing
+
+When mocking external services, verify your mocks match reality:
+
+```python
+# Record real responses
+@pytest.fixture(scope="session")
+def vcr_config():
+    return {"record_mode": "once"}
+
+@pytest.mark.vcr()
+def test_github_api():
+    response = github_client.get_user("octocat")
+    assert response["login"] == "octocat"
+
+# Or use contract testing (Pact)
+def test_user_service_contract():
+    pact.given("user exists").upon_receiving(
+        "a request for user"
+    ).with_request(
+        method="GET",
+        path="/users/1"
+    ).will_respond_with(
+        status=200,
+        body={"id": 1, "name": Like("string")}
+    )
+```

+ 214 - 0
skills/testing-patterns/references/tdd-workflow.md

@@ -0,0 +1,214 @@
+# Test-Driven Development (TDD)
+
+Red-Green-Refactor cycle for quality code.
+
+## The TDD Cycle
+
+```
+┌─────────────────────────────────────────┐
+│                                         │
+│   ┌─────┐    ┌─────┐    ┌─────────┐    │
+│   │ RED │ -> │GREEN│ -> │REFACTOR │ ──┐│
+│   └─────┘    └─────┘    └─────────┘   ││
+│       ^                               │ │
+│       └───────────────────────────────┘ │
+│                                         │
+└─────────────────────────────────────────┘
+```
+
+### 1. RED: Write a Failing Test
+
+```python
+# Start with the test
+def test_calculate_discount_applies_percentage():
+    cart = Cart()
+    cart.add_item(Item(price=100))
+
+    total = cart.calculate_total(discount_percent=10)
+
+    assert total == 90  # Fails - function doesn't exist yet
+```
+
+### 2. GREEN: Make It Pass (Minimal Code)
+
+```python
+# Write minimal code to pass
+class Cart:
+    def __init__(self):
+        self.items = []
+
+    def add_item(self, item):
+        self.items.append(item)
+
+    def calculate_total(self, discount_percent=0):
+        total = sum(item.price for item in self.items)
+        return total * (1 - discount_percent / 100)
+```
+
+### 3. REFACTOR: Improve the Code
+
+```python
+# Clean up while tests pass
+class Cart:
+    def __init__(self):
+        self._items: list[Item] = []
+
+    def add_item(self, item: Item) -> None:
+        self._items.append(item)
+
+    @property
+    def subtotal(self) -> Decimal:
+        return sum(item.price for item in self._items)
+
+    def calculate_total(self, discount_percent: int = 0) -> Decimal:
+        discount_multiplier = Decimal(100 - discount_percent) / 100
+        return self.subtotal * discount_multiplier
+```
+
+## TDD Rules
+
+### Three Laws of TDD
+
+1. **Don't write production code** until you have a failing test
+2. **Write only enough test** to fail (compilation counts)
+3. **Write only enough production code** to pass the test
+
+### Test Size Rules
+
+```
+Tests should be:
+- Fast (< 100ms each)
+- Isolated (no shared state)
+- Repeatable (same result every time)
+- Self-validating (pass/fail, no manual inspection)
+- Timely (written before production code)
+```
+
+## TDD Workflow Example
+
+### Step 1: List Test Cases
+
+```
+Feature: Shopping Cart Discount
+
+Test cases:
+[ ] Empty cart returns 0
+[ ] Single item returns item price
+[ ] Multiple items returns sum
+[ ] Percentage discount applied correctly
+[ ] Maximum discount capped at 50%
+[ ] Negative discount treated as 0
+```
+
+### Step 2: Start with Simplest Test
+
+```python
+def test_empty_cart_returns_zero():
+    cart = Cart()
+    assert cart.calculate_total() == 0
+```
+
+### Step 3: Implement and Move to Next
+
+```python
+# After passing, add next test
+def test_single_item_returns_price():
+    cart = Cart()
+    cart.add_item(Item(price=50))
+    assert cart.calculate_total() == 50
+```
+
+### Step 4: Build Up Complexity
+
+```python
+def test_discount_capped_at_50_percent():
+    cart = Cart()
+    cart.add_item(Item(price=100))
+
+    total = cart.calculate_total(discount_percent=75)
+
+    assert total == 50  # Capped at 50% max discount
+```
+
+## When to Use TDD
+
+### Good For:
+- Business logic
+- Algorithms
+- Data transformations
+- API contracts
+- Complex conditionals
+
+### Less Suitable For:
+- UI/visual elements
+- Exploratory prototyping
+- One-off scripts
+- Integration with external systems
+
+## TDD Anti-Patterns
+
+### Testing Implementation Details
+
+```python
+# BAD - Tests internal state
+def test_cart_has_items_list():
+    cart = Cart()
+    cart.add_item(Item(price=10))
+    assert len(cart._items) == 1  # Tests implementation!
+
+# GOOD - Tests behavior
+def test_cart_counts_items():
+    cart = Cart()
+    cart.add_item(Item(price=10))
+    assert cart.item_count == 1  # Tests public interface
+```
+
+### Tests That Mirror Code
+
+```python
+# BAD - Test duplicates implementation
+def test_calculate_total():
+    cart = Cart()
+    cart.add_item(Item(price=10))
+    cart.add_item(Item(price=20))
+
+    # This is just reimplementing the function
+    expected = 10 + 20
+    assert cart.calculate_total() == expected
+
+# GOOD - Tests expected outcome
+def test_calculate_total():
+    cart = Cart()
+    cart.add_item(Item(price=10))
+    cart.add_item(Item(price=20))
+
+    assert cart.calculate_total() == 30
+```
+
+## Kata Practice
+
+### String Calculator
+
+```
+Create a calculator that takes a string of numbers and returns their sum.
+
+Step 1: "" returns 0
+Step 2: "1" returns 1
+Step 3: "1,2" returns 3
+Step 4: Handle unknown number of numbers
+Step 5: Handle newlines as delimiters: "1\n2,3" returns 6
+Step 6: Support custom delimiters: "//;\n1;2" returns 3
+Step 7: Throw on negative numbers with message including all negatives
+```
+
+### FizzBuzz
+
+```
+Step 1: Return "1" for 1
+Step 2: Return "2" for 2
+Step 3: Return "Fizz" for 3
+Step 4: Return "Buzz" for 5
+Step 5: Return "Fizz" for 6 (multiple of 3)
+Step 6: Return "Buzz" for 10 (multiple of 5)
+Step 7: Return "FizzBuzz" for 15 (multiple of both)
+```

+ 332 - 0
skills/testing-patterns/references/test-data-patterns.md

@@ -0,0 +1,332 @@
+# Test Data Patterns
+
+Strategies for managing test data effectively.
+
+## Fixtures
+
+### Basic Fixture
+
+```python
+import pytest
+
+@pytest.fixture
+def user():
+    return User(id=1, name="Test User", email="test@example.com")
+
+def test_user_greeting(user):
+    assert user.greeting() == "Hello, Test User!"
+```
+
+### Fixture with Cleanup
+
+```python
+@pytest.fixture
+def temp_database():
+    db = create_test_database()
+    yield db
+    db.drop()  # Cleanup after test
+```
+
+### Shared Fixtures (conftest.py)
+
+```python
+# tests/conftest.py
+@pytest.fixture(scope="session")
+def app():
+    """Application shared across all tests."""
+    return create_app(testing=True)
+
+@pytest.fixture(scope="function")
+def client(app):
+    """Fresh client for each test."""
+    return app.test_client()
+```
+
+## Factory Pattern
+
+### Simple Factory
+
+```python
+def make_user(**overrides):
+    """Factory function for creating test users."""
+    defaults = {
+        "id": 1,
+        "name": "Test User",
+        "email": "test@example.com",
+        "active": True,
+    }
+    return User(**{**defaults, **overrides})
+
+def test_inactive_user():
+    user = make_user(active=False)
+    assert not user.can_login()
+```
+
+### Factory Fixture
+
+```python
+@pytest.fixture
+def user_factory():
+    """Factory fixture for creating multiple users."""
+    created = []
+
+    def _create(**overrides):
+        user = make_user(**overrides)
+        created.append(user)
+        return user
+
+    yield _create
+
+    # Cleanup
+    for user in created:
+        user.delete()
+
+def test_user_comparison(user_factory):
+    user1 = user_factory(name="Alice")
+    user2 = user_factory(name="Bob")
+    assert user1 != user2
+```
+
+### Factory Boy (Python)
+
+```python
+import factory
+from factory import Faker
+
+class UserFactory(factory.Factory):
+    class Meta:
+        model = User
+
+    id = factory.Sequence(lambda n: n + 1)
+    name = Faker("name")
+    email = Faker("email")
+    created_at = Faker("date_time_this_year")
+
+# Usage
+def test_users():
+    user = UserFactory()
+    admin = UserFactory(role="admin")
+    users = UserFactory.create_batch(10)
+```
+
+## Builder Pattern
+
+```python
+class UserBuilder:
+    """Fluent builder for test users."""
+
+    def __init__(self):
+        self._data = {
+            "id": 1,
+            "name": "Test User",
+            "email": "test@example.com",
+            "role": "user",
+            "active": True,
+        }
+
+    def with_name(self, name: str) -> "UserBuilder":
+        self._data["name"] = name
+        return self
+
+    def as_admin(self) -> "UserBuilder":
+        self._data["role"] = "admin"
+        return self
+
+    def inactive(self) -> "UserBuilder":
+        self._data["active"] = False
+        return self
+
+    def build(self) -> User:
+        return User(**self._data)
+
+# Usage
+def test_admin_access():
+    admin = UserBuilder().as_admin().build()
+    assert admin.can_access_admin_panel()
+
+def test_inactive_user():
+    user = UserBuilder().inactive().build()
+    assert not user.can_login()
+```
+
+## Mother Pattern
+
+```python
+class ObjectMother:
+    """Pre-configured test objects for common scenarios."""
+
+    @staticmethod
+    def valid_user() -> User:
+        return User(
+            id=1,
+            name="Valid User",
+            email="valid@example.com",
+            active=True
+        )
+
+    @staticmethod
+    def admin_user() -> User:
+        return User(
+            id=2,
+            name="Admin User",
+            email="admin@example.com",
+            role="admin",
+            active=True
+        )
+
+    @staticmethod
+    def expired_subscription() -> Subscription:
+        return Subscription(
+            user_id=1,
+            expires_at=datetime.now() - timedelta(days=30),
+            plan="basic"
+        )
+
+# Usage
+def test_admin_permissions():
+    admin = ObjectMother.admin_user()
+    assert admin.can_delete_users()
+```
+
+## Fixture Composition
+
+```python
+@pytest.fixture
+def address():
+    return Address(street="123 Main St", city="Test City")
+
+@pytest.fixture
+def user(address):
+    return User(name="Test User", address=address)
+
+@pytest.fixture
+def order(user):
+    return Order(user=user, items=[])
+
+def test_order_address(order):
+    assert order.shipping_address.city == "Test City"
+```
+
+## Data Files
+
+### JSON Fixtures
+
+```python
+# tests/fixtures/users.json
+[
+    {"id": 1, "name": "Alice", "role": "admin"},
+    {"id": 2, "name": "Bob", "role": "user"}
+]
+
+# tests/conftest.py
+@pytest.fixture
+def sample_users():
+    with open("tests/fixtures/users.json") as f:
+        return json.load(f)
+```
+
+### YAML Fixtures
+
+```yaml
+# tests/fixtures/config.yaml
+database:
+  host: localhost
+  port: 5432
+  name: test_db
+
+users:
+  - id: 1
+    name: Alice
+  - id: 2
+    name: Bob
+```
+
+```python
+@pytest.fixture
+def config():
+    with open("tests/fixtures/config.yaml") as f:
+        return yaml.safe_load(f)
+```
+
+## Randomized Data
+
+```python
+from faker import Faker
+
+fake = Faker()
+
+def test_user_email_validation():
+    # Random but valid email
+    email = fake.email()
+    user = User(email=email)
+    assert user.is_valid_email()
+
+def test_with_seed():
+    # Reproducible random data
+    Faker.seed(12345)
+    user = make_user(name=fake.name())
+    # Same name every time with seed 12345
+```
+
+## Best Practices
+
+### 1. Keep Fixtures Close to Tests
+
+```
+tests/
+├── conftest.py          # Shared fixtures
+├── unit/
+│   ├── conftest.py      # Unit test fixtures
+│   └── test_user.py
+└── integration/
+    ├── conftest.py      # Integration fixtures
+    └── test_api.py
+```
+
+### 2. Use Descriptive Names
+
+```python
+# BAD
+@pytest.fixture
+def data():
+    return {...}
+
+# GOOD
+@pytest.fixture
+def user_with_expired_subscription():
+    return {...}
+```
+
+### 3. Minimize Fixture Scope
+
+```python
+# Use function scope (default) unless you have a reason
+@pytest.fixture(scope="function")  # Default
+def user(): ...
+
+# Session scope only for expensive, read-only fixtures
+@pytest.fixture(scope="session")
+def database_schema(): ...
+```
+
+### 4. Avoid Test Data Dependencies
+
+```python
+# BAD - Tests depend on each other
+def test_create_user():
+    user = create_user("test@example.com")
+    # User exists in DB after this test
+
+def test_get_user():
+    user = get_user("test@example.com")  # Depends on previous test!
+
+# GOOD - Each test is independent
+def test_create_user(db):
+    user = create_user("test@example.com")
+    assert user.email == "test@example.com"
+
+def test_get_user(db, user_factory):
+    user_factory(email="test@example.com")  # Create own data
+    found = get_user("test@example.com")
+    assert found is not None
+```

+ 38 - 0
skills/testing-patterns/scripts/coverage-check.sh

@@ -0,0 +1,38 @@
+#!/bin/bash
+# Run tests with coverage and fail if below threshold
+# Usage: ./coverage-check.sh [--threshold 80] [pytest-args...]
+
+set -e
+
+THRESHOLD=80
+PYTEST_ARGS=""
+
+# Parse arguments
+while [[ $# -gt 0 ]]; do
+    case $1 in
+        --threshold)
+            THRESHOLD="$2"
+            shift 2
+            ;;
+        *)
+            PYTEST_ARGS="$PYTEST_ARGS $1"
+            shift
+            ;;
+    esac
+done
+
+echo "=== Running tests with coverage ==="
+echo "Minimum coverage threshold: ${THRESHOLD}%"
+echo ""
+
+# Run pytest with coverage
+pytest \
+    --cov=src \
+    --cov-report=term-missing \
+    --cov-report=html \
+    --cov-fail-under=${THRESHOLD} \
+    ${PYTEST_ARGS}
+
+echo ""
+echo "=== Coverage report generated ==="
+echo "HTML report: htmlcov/index.html"

+ 49 - 168
skills/tool-discovery/SKILL.md

@@ -2,205 +2,86 @@
 name: tool-discovery
 description: "Recommend the right agents and skills for any task. Covers both heavyweight agents (Task tool) and lightweight skills (Skill tool). Triggers on: which agent, which skill, what tool should I use, help me choose, recommend agent, find the right tool."
 allowed-tools: "Read Glob"
+depends-on: []
+related-skills: [claude-code-templates, claude-code-debug]
 ---
 
 # Tool Discovery
 
-Recommend the right agents and skills for any task. Covers both heavyweight agents (Task tool) and lightweight skills (Skill tool).
+Recommend the right agents and skills for any task.
 
 ## Decision Flowchart
 
 ```
 Is this a reference/lookup task?
 ├── YES → Use a SKILL (lightweight, auto-injects)
-│         Examples: patterns, syntax, CLI commands
-│
 └── NO → Does it require reasoning/decisions?
          ├── YES → Use an AGENT (heavyweight, spawns subagent)
-         │         Examples: architecture, optimization, debugging
-         │
-         └── MAYBE → Check both lists below
+         └── MAYBE → Check catalogs below
 ```
 
-**Rule of thumb:**
-- **Skills** = Quick reference, patterns, commands (50-200 lines)
-- **Agents** = Deep expertise, autonomous decisions (200-1600 lines)
+**Rule:** Skills = patterns/reference. Agents = decisions/expertise.
 
----
-
-## Skills Reference
-
-### Pattern Skills (Reference Tables)
-
-| Skill | Triggers | Use When |
-|-------|----------|----------|
-| **rest-patterns** | rest api, http methods, status codes | HTTP method semantics, status code lookup |
-| **tailwind-patterns** | tailwind, utility classes, tw | Tailwind classes, responsive breakpoints |
-| **sql-patterns** | sql patterns, cte, window functions | CTE examples, JOIN reference, window functions |
-| **sqlite-ops** | sqlite, aiosqlite, local database | SQLite schema patterns, Python sqlite3/aiosqlite |
-| **mcp-patterns** | mcp server, model context protocol | MCP server structure, tool handlers |
-
-### CLI Tool Skills
-
-| Skill | Triggers | Use When |
-|-------|----------|----------|
-| **file-search** | fd, ripgrep, rg, fzf | Finding files, searching code, interactive selection |
-| **find-replace** | sd, batch replace | Modern find-and-replace (sd over sed) |
-| **code-stats** | tokei, difft, line counts | Codebase statistics, semantic diffs |
-| **data-processing** | jq, yq, json, yaml | JSON/YAML processing and transformation |
-| **structural-search** | ast-grep, sg, ast pattern | Search by AST structure, not text |
-
-### Workflow Skills
+## Quick Skill Reference
 
-| Skill | Triggers | Use When |
-|-------|----------|----------|
-| **git-workflow** | lazygit, gh, delta, pr, rebase, stash, bisect | Git operations, GitHub PRs, staging, rebase, bisect |
-| **python-env** | uv, venv, pip, pyproject | Python environment setup with uv |
-| **task-runner** | just, justfile, run tests | Running project tasks via justfile |
-| **doc-scanner** | AGENTS.md, conventions, scan docs | Finding and reading project documentation |
-| **project-planner** | plan, sync plan, track | Project planning with /plan command |
-
----
-
-## Agents Reference
-
-### Language Experts
-
-| Agent | Use When |
+| Skill | Triggers |
 |-------|----------|
-| **python-expert** | Advanced Python, async, testing, optimization |
-| **javascript-expert** | Modern JS, async patterns, V8 optimization |
-| **typescript-expert** | Type system, generics, complex types |
-| **bash-expert** | Shell scripting, defensive programming |
-
-### Framework Experts
-
-| Agent | Use When |
+| **file-search** | fd, rg, fzf, find files |
+| **find-replace** | sd, batch replace |
+| **code-stats** | tokei, difft, line counts |
+| **data-processing** | jq, yq, json, yaml |
+| **structural-search** | ast-grep, sg, ast pattern |
+| **git-workflow** | lazygit, gh, delta, rebase |
+| **python-env** | uv, venv, pyproject |
+| **rest-patterns** | http methods, status codes |
+| **sql-patterns** | cte, window functions |
+| **sqlite-ops** | sqlite, aiosqlite |
+| **tailwind-patterns** | tailwind, tw classes |
+| **mcp-patterns** | mcp server, protocol |
+
+## Quick Agent Reference
+
+| Agent | Triggers |
 |-------|----------|
-| **react-expert** | React hooks, Server Components, state management |
-| **vue-expert** | Vue 3, Composition API, Pinia |
-| **laravel-expert** | Laravel, Eloquent, PHP testing |
-| **astro-expert** | Astro SSR/SSG, Cloudflare deployment |
-
-### Infrastructure Experts
-
-| Agent | Use When |
-|-------|----------|
-| **postgres-expert** | PostgreSQL optimization, execution plans |
-| **sql-expert** | Complex queries, query optimization |
-| **wrangler-expert** | Cloudflare Workers deployment |
-| **aws-fargate-ecs-expert** | ECS/Fargate container orchestration |
-| **cloudflare-expert** | Workers, Pages, DNS configuration |
-
-### Specialized
-
-| Agent | Use When |
-|-------|----------|
-| **firecrawl-expert** | Web scraping, crawling, anti-bot bypass |
-| **payloadcms-expert** | Payload CMS architecture, configuration |
-| **craftcms-expert** | Craft CMS, Twig templates |
-| **cypress-expert** | E2E testing, component tests |
-| **project-organizer** | Restructuring project directories |
-
-### Built-in Agents (Task tool)
-
-| Agent | Use When |
-|-------|----------|
-| **Explore** | Quick codebase exploration, "where is X" |
-| **Plan** | Design implementation strategy |
-| **general-purpose** | Multi-step tasks when unsure |
-| **claude-code-guide** | Questions about Claude Code features |
-
----
-
-## Matching By Context
-
-### By File Extension
-
-| Files | Skill | Agent |
-|-------|-------|-------|
-| `.py` | python-env | python-expert |
-| `.ts`, `.js` | — | typescript-expert, javascript-expert |
-| `.sql` | sql-patterns | postgres-expert, sql-expert |
-| `.sh` | — | bash-expert |
-| `.astro` | tailwind-patterns | astro-expert |
-| `.json` | data-processing | — |
-| `.yaml` | data-processing | — |
-
-### By Task Type
-
-| Task | Try Skill First | Then Agent |
-|------|-----------------|------------|
-| "How do I write a CTE?" | sql-patterns | sql-expert |
-| "Optimize this query" | — | postgres-expert |
-| "Find files named X" | file-search | Explore |
-| "Restructure this project" | — | project-organizer |
-| "Scrape this website" | — | firecrawl-expert |
-| "What HTTP status for X?" | rest-patterns | — |
-| "Set up Python project" | python-env | python-expert |
-| "Build MCP server" | mcp-patterns | — |
-
-### By Keywords
-
-| Keywords | Likely Skill | Likely Agent |
-|----------|--------------|--------------|
-| "pattern", "example", "syntax" | Check skills first | — |
-| "optimize", "debug", "fix" | — | Check agents |
-| "reference", "lookup", "how to" | Check skills first | — |
-| "architecture", "design", "plan" | — | Check agents or Plan |
-
----
+| **python-expert** | Python, async, pytest |
+| **typescript-expert** | TypeScript, types, generics |
+| **react-expert** | React, hooks, state |
+| **postgres-expert** | PostgreSQL, query optimization |
+| **cloudflare-expert** | Workers, KV, D1, R2 |
+| **Explore** | "where is", "find" |
+| **Plan** | design, architect |
 
 ## How to Launch
 
-### Skills (via Skill tool)
+**Skills:**
 ```
 Skill tool → skill: "file-search"
 ```
-Skills auto-inject into current context. No subagent spawned.
 
-### Agents (via Task tool)
+**Agents:**
 ```
 Task tool → subagent_type: "python-expert"
-         → prompt: "Your task description"
-```
-Agents spawn a subagent session with their full context.
-
----
-
-## Recommendations Workflow
-
+         → prompt: "Your task"
 ```
-User: "Which tool should I use for X?"
-
-1. Parse the request:
-   - Is it reference/lookup? → Skill
-   - Does it need reasoning? → Agent
-   - Unclear? → Check both lists
 
-2. Match to available tools:
-   - Check file types in project
-   - Check config files (package.json, pyproject.toml, etc.)
-   - Consider task complexity
+## Match by Task Type
 
-3. Output format:
-   RECOMMENDED: [skill/agent-name]
-   TYPE: Skill | Agent
-   WHY: [1 sentence rationale]
-
-   LAUNCH: Skill tool with "name" | Task tool with subagent_type="name"
+| Task | Skill First | Agent If Needed |
+|------|-------------|-----------------|
+| "How to write a CTE?" | sql-patterns | sql-expert |
+| "Optimize this query" | — | postgres-expert |
+| "Find files named X" | file-search | Explore |
+| "Set up Python project" | python-env | python-expert |
+| "What HTTP status for X?" | rest-patterns | — |
 
-4. If multiple apply:
-   PRIMARY: [name] - [reason]
-   SECONDARY: [name] - [reason]
-```
+## Tips
 
----
+- **Skills are cheaper** - Use for lookups, patterns
+- **Agents are powerful** - Use for decisions, optimization
+- **Don't over-recommend** - Max 2-3 tools per task
 
-## Tips
+## Additional Resources
 
-- **Skills are cheaper** - Use for reference lookups, patterns, CLI commands
-- **Agents are powerful** - Use for decisions, optimization, debugging
-- **Don't over-recommend** - Maximum 2-3 tools per task
-- **Parallel execution** - Launch independent agents in parallel via Task tool
-- **Check availability** - Run `/agents` or check this skill for current list
+For complete catalogs, load:
+- `./references/agents-catalog.md` - All agents with capabilities
+- `./references/skills-catalog.md` - All skills with details

+ 458 - 0
skills/tool-discovery/references/agents-catalog.md

@@ -0,0 +1,458 @@
+# Agents Catalog
+
+Complete reference for all available agents in the Task tool.
+
+## Language Experts
+
+### python-expert
+
+**Triggers:** python, py, pythonic, PEP, async, pytest, django, flask
+
+**Capabilities:**
+- Advanced Python features (decorators, metaclasses, descriptors)
+- Async programming (asyncio, aiohttp, async generators)
+- Testing strategies (pytest, mocking, fixtures)
+- Performance optimization and profiling
+- Clean, idiomatic Python code
+
+**Best For:**
+- Complex Python architecture decisions
+- Performance optimization
+- Testing strategy design
+- Debugging difficult Python issues
+
+---
+
+### javascript-expert
+
+**Triggers:** javascript, js, node, es6, esm, commonjs, npm
+
+**Capabilities:**
+- Modern JavaScript (ES2015+)
+- Async patterns (Promises, async/await)
+- Module systems (ESM, CommonJS)
+- Event loop and concurrency
+- V8 optimization patterns
+
+**Best For:**
+- JavaScript modernization
+- Async code architecture
+- Performance optimization
+- Node.js development
+
+---
+
+### typescript-expert
+
+**Triggers:** typescript, ts, types, generics, interface, type guard
+
+**Capabilities:**
+- Advanced type system (generics, conditional types)
+- Utility types and type manipulation
+- Declaration files (.d.ts)
+- Strict mode and type safety
+- Type-level programming
+
+**Best For:**
+- Complex type definitions
+- Type-safe API design
+- Generic library development
+- Migration from JavaScript
+
+---
+
+### bash-expert
+
+**Triggers:** bash, shell, script, zsh, cli
+
+**Capabilities:**
+- Defensive bash scripting
+- Error handling and traps
+- CI/CD pipeline scripts
+- System utilities
+- Cross-platform considerations
+
+**Best For:**
+- Production automation scripts
+- CI/CD pipelines
+- System administration
+- Build scripts
+
+---
+
+## Framework Experts
+
+### react-expert
+
+**Triggers:** react, hooks, useState, useEffect, jsx, tsx
+
+**Capabilities:**
+- React hooks (built-in and custom)
+- State management patterns
+- Server Components and RSC
+- Performance optimization
+- Component architecture
+
+**Best For:**
+- React application architecture
+- Performance bottlenecks
+- State management design
+- Migration to modern React
+
+---
+
+### vue-expert
+
+**Triggers:** vue, vuejs, composition api, pinia, vue router
+
+**Capabilities:**
+- Vue 3 Composition API
+- Pinia state management
+- Vue Router patterns
+- Reactivity system internals
+- Component design
+
+**Best For:**
+- Vue 3 migration
+- State management setup
+- Complex component patterns
+- SSR with Nuxt
+
+---
+
+### laravel-expert
+
+**Triggers:** laravel, eloquent, php, artisan
+
+**Capabilities:**
+- Laravel framework patterns
+- Eloquent ORM
+- Testing with PHPUnit
+- Queue and job handling
+- API development
+
+**Best For:**
+- Laravel application design
+- Database optimization
+- Testing strategy
+- API architecture
+
+---
+
+### astro-expert
+
+**Triggers:** astro, islands, content collections, cloudflare workers
+
+**Capabilities:**
+- Astro architecture (SSR/SSG/hybrid)
+- Islands architecture
+- Content Collections
+- Cloudflare Workers deployment
+- Performance optimization
+
+**Best For:**
+- Astro project setup
+- Deployment to Cloudflare
+- Content management
+- Performance tuning
+
+---
+
+## Infrastructure Experts
+
+### postgres-expert
+
+**Triggers:** postgres, postgresql, pg, sql optimization
+
+**Capabilities:**
+- Query optimization
+- Index strategies
+- Execution plan analysis
+- Connection pooling
+- Replication setup
+
+**Best For:**
+- Slow query optimization
+- Index design
+- Database architecture
+- Performance tuning
+
+---
+
+### sql-expert
+
+**Triggers:** sql, query, database, join, subquery
+
+**Capabilities:**
+- Complex query writing
+- Query optimization
+- Index strategies
+- Data modeling
+- Cross-database patterns
+
+**Best For:**
+- Complex query construction
+- Query debugging
+- Data modeling
+- Performance analysis
+
+---
+
+### cloudflare-expert
+
+**Triggers:** cloudflare, workers, pages, kv, d1, r2
+
+**Capabilities:**
+- Workers development
+- KV/D1/R2 storage
+- Edge computing patterns
+- Security configuration
+- DNS and CDN setup
+
+**Best For:**
+- Cloudflare Workers apps
+- Edge optimization
+- Storage architecture
+- Security hardening
+
+---
+
+### wrangler-expert
+
+**Triggers:** wrangler, deploy, cloudflare cli
+
+**Capabilities:**
+- Wrangler CLI configuration
+- Multi-environment deployment
+- Binding configuration
+- Troubleshooting deployments
+- CI/CD integration
+
+**Best For:**
+- Deployment issues
+- Wrangler configuration
+- Environment setup
+- CI/CD pipelines
+
+---
+
+### aws-fargate-ecs-expert
+
+**Triggers:** ecs, fargate, aws containers, task definition
+
+**Capabilities:**
+- ECS/Fargate deployment
+- Task definitions
+- Service Auto Scaling
+- Networking (awsvpc)
+- Logging (FireLens)
+
+**Best For:**
+- Container deployment on AWS
+- ECS architecture
+- Scaling strategy
+- Cost optimization
+
+---
+
+## Specialized Experts
+
+### firecrawl-expert
+
+**Triggers:** firecrawl, web scraping, crawl, anti-bot
+
+**Capabilities:**
+- Web scraping strategies
+- Anti-bot bypass
+- Dynamic content handling
+- Structured data extraction
+- API integration
+
+**Best For:**
+- Complex scraping tasks
+- Blocked site access
+- Data extraction pipelines
+- Crawl architecture
+
+---
+
+### payloadcms-expert
+
+**Triggers:** payload, payload cms, headless cms
+
+**Capabilities:**
+- Payload CMS architecture
+- Collection configuration
+- Access control design
+- Media handling
+- Multi-tenant setup
+
+**Best For:**
+- Payload project setup
+- Access control design
+- Schema planning
+- Integration patterns
+
+---
+
+### craftcms-expert
+
+**Triggers:** craft, craftcms, twig
+
+**Capabilities:**
+- Craft CMS development
+- Twig templates
+- Plugin development
+- Matrix fields
+- GraphQL API
+
+**Best For:**
+- Craft CMS projects
+- Template development
+- Custom field types
+- Content modeling
+
+---
+
+### cypress-expert
+
+**Triggers:** cypress, e2e, component testing, test runner
+
+**Capabilities:**
+- E2E test architecture
+- Component testing
+- Custom commands
+- Network stubbing
+- CI integration
+
+**Best For:**
+- E2E test suite setup
+- Test architecture
+- Flaky test debugging
+- CI optimization
+
+---
+
+### playwright-roulette-expert
+
+**Triggers:** playwright, browser automation, casino, roulette
+
+**Capabilities:**
+- Playwright automation
+- DOM manipulation
+- Coordinate-based clicking
+- Browser process management
+- Viewport configuration
+
+**Best For:**
+- Browser automation
+- Game automation
+- Complex DOM interactions
+- Process management
+
+---
+
+### project-organizer
+
+**Triggers:** restructure, organize, cleanup, directory
+
+**Capabilities:**
+- Project structure analysis
+- Directory reorganization
+- Old file cleanup
+- Git-aware operations
+- Best practice structure
+
+**Best For:**
+- Project restructuring
+- Codebase cleanup
+- Structure standardization
+- Tech debt reduction
+
+---
+
+## Built-in Agents
+
+### Explore
+
+**Triggers:** where is, find, locate, codebase search
+
+**Capabilities:**
+- Fast codebase exploration
+- Pattern matching
+- File discovery
+- Quick answers
+
+**Best For:**
+- "Where is X defined?"
+- "Find files matching Y"
+- Quick codebase questions
+
+---
+
+### Plan
+
+**Triggers:** plan, design, architect, strategy
+
+**Capabilities:**
+- Implementation planning
+- Architecture design
+- File identification
+- Trade-off analysis
+
+**Best For:**
+- Feature planning
+- Architectural decisions
+- Implementation strategy
+
+---
+
+### general-purpose
+
+**Triggers:** multi-step, complex, research
+
+**Capabilities:**
+- Autonomous research
+- Multi-step tasks
+- Code search
+- Tool coordination
+
+**Best For:**
+- Complex investigations
+- Open-ended research
+- Multi-step operations
+
+---
+
+### claude-code-guide
+
+**Triggers:** how to use claude code, can claude code, does claude code
+
+**Capabilities:**
+- Claude Code documentation
+- Feature explanations
+- Hook configuration
+- MCP server setup
+- Agent SDK guidance
+
+**Best For:**
+- Claude Code questions
+- Configuration help
+- Feature discovery
+- SDK usage
+
+---
+
+## Selection Guide
+
+| Need | First Try | Then Try |
+|------|-----------|----------|
+| "How to write X in Python" | python-expert | - |
+| "Optimize this query" | postgres-expert | sql-expert |
+| "Find where X is defined" | Explore | general-purpose |
+| "Plan feature implementation" | Plan | general-purpose |
+| "Scrape this website" | firecrawl-expert | - |
+| "Deploy to Cloudflare" | wrangler-expert | cloudflare-expert |
+| "Fix React performance" | react-expert | - |
+| "Write E2E tests" | cypress-expert | - |
+| "Restructure project" | project-organizer | - |

+ 292 - 0
skills/tool-discovery/references/skills-catalog.md

@@ -0,0 +1,292 @@
+# Skills Catalog
+
+Complete reference for all available skills.
+
+## Pattern Skills
+
+Quick reference for common patterns and syntax.
+
+### rest-patterns
+
+**Triggers:** rest api, http methods, status codes, api design, endpoint design
+
+**Use For:**
+- HTTP method semantics (GET, POST, PUT, PATCH, DELETE)
+- Status code selection
+- API versioning strategies
+- Caching and rate limiting
+- Error response formats
+
+**References:** status-codes.md, caching-patterns.md, rate-limiting.md, response-formats.md
+
+---
+
+### sql-patterns
+
+**Triggers:** sql patterns, cte example, window functions, sql join, index strategy
+
+**Use For:**
+- CTE (Common Table Expressions)
+- Window functions (ROW_NUMBER, LAG, running totals)
+- JOIN reference
+- Pagination patterns
+- Index strategies
+
+**References:** window-functions.md, indexing-strategies.md
+
+---
+
+### tailwind-patterns
+
+**Triggers:** tailwind, utility classes, responsive design, tailwind config, dark mode
+
+**Use For:**
+- Responsive breakpoints
+- Layout patterns (flex, grid)
+- Component patterns (cards, forms, navbars)
+- Dark mode configuration
+- State modifiers
+
+**References:** component-patterns.md
+
+---
+
+### sqlite-ops
+
+**Triggers:** sqlite, sqlite3, aiosqlite, local database, database schema
+
+**Use For:**
+- Schema design patterns (state, cache, events)
+- Python sqlite3 usage
+- Async operations with aiosqlite
+- WAL mode configuration
+- Migration patterns
+
+**References:** schema-patterns.md, async-patterns.md, migration-patterns.md
+
+---
+
+### mcp-patterns
+
+**Triggers:** mcp server, model context protocol, tool handlers
+
+**Use For:**
+- MCP server structure
+- Tool handler patterns
+- Resource configuration
+- Protocol implementation
+
+**References:** server-patterns.md, tool-handlers.md, resources.md
+
+---
+
+## CLI Tool Skills
+
+Modern command-line tools for development workflows.
+
+### file-search
+
+**Triggers:** fd, ripgrep, rg, find files, search code, fzf, fuzzy find
+
+**Use For:**
+- Finding files by name (fd)
+- Searching file contents (rg)
+- Interactive selection (fzf)
+- Combined workflows
+
+**References:** advanced-workflows.md
+
+---
+
+### find-replace
+
+**Triggers:** sd, find replace, batch replace, string replacement
+
+**Use For:**
+- Modern find-and-replace with sd
+- Regex patterns
+- Batch operations
+- Preview before applying
+
+**References:** advanced-patterns.md
+
+---
+
+### code-stats
+
+**Triggers:** tokei, difft, line counts, code statistics, semantic diff
+
+**Use For:**
+- Codebase statistics (tokei)
+- Semantic diffs (difft)
+- Language breakdown
+- Before/after comparisons
+
+**References:** tokei-advanced.md, difft-advanced.md
+
+---
+
+### data-processing
+
+**Triggers:** jq, yq, json, yaml, toml
+
+**Use For:**
+- JSON processing and transformation
+- YAML/TOML operations
+- Structured data queries
+- Config file manipulation
+
+**References:** jq-patterns.md, yq-patterns.md, shell-integration.md
+
+---
+
+### structural-search
+
+**Triggers:** ast-grep, sg, ast pattern, find function calls, semantic search
+
+**Use For:**
+- Search by AST structure
+- Pattern matching in code
+- Refactoring operations
+- Security scans
+
+**References:** js-ts-patterns.md, python-patterns.md, go-rust-patterns.md, security-patterns.md, advanced-usage.md
+
+---
+
+## Workflow Skills
+
+Project and development workflow automation.
+
+### git-workflow
+
+**Triggers:** lazygit, gh, delta, pr, rebase, stash, bisect
+
+**Use For:**
+- Interactive git operations (lazygit)
+- GitHub CLI (gh) commands
+- Syntax-highlighted diffs (delta)
+- Rebase and stash patterns
+- Bug hunting with bisect
+
+**References:** rebase-patterns.md, stash-patterns.md, advanced-git.md
+
+---
+
+### python-env
+
+**Triggers:** uv, venv, pip, pyproject, python environment
+
+**Use For:**
+- Fast environment setup with uv
+- Virtual environment creation
+- Dependency management
+- pyproject.toml configuration
+
+**References:** pyproject-patterns.md, dependency-management.md
+
+---
+
+### task-runner
+
+**Triggers:** just, justfile, run tests, build project, list tasks
+
+**Use For:**
+- Project task execution
+- Justfile configuration
+- Common development commands
+
+---
+
+### doc-scanner
+
+**Triggers:** AGENTS.md, conventions, scan docs, project documentation
+
+**Use For:**
+- Finding project documentation
+- Synthesizing AI agent instructions
+- Consolidating multiple doc files
+- Creating AGENTS.md
+
+**References:** file-patterns.md, templates.md
+
+---
+
+### project-planner
+
+**Triggers:** plan, sync plan, track, project planning
+
+**Use For:**
+- Project planning with /plan
+- Session state management
+- Progress tracking
+- Context preservation
+
+---
+
+## Selection Guide
+
+### By File Type
+
+| Working With | Skill |
+|--------------|-------|
+| JSON files | data-processing |
+| YAML/TOML | data-processing |
+| SQL databases | sql-patterns, sqlite-ops |
+| TypeScript/JS | file-search, structural-search |
+| Python | python-env, structural-search |
+| API endpoints | rest-patterns |
+| CSS/Tailwind | tailwind-patterns |
+
+### By Task
+
+| Task | Skill |
+|------|-------|
+| Find files by name | file-search |
+| Search code content | file-search |
+| Replace across files | find-replace |
+| Count lines of code | code-stats |
+| Compare code changes | code-stats |
+| Process JSON/YAML | data-processing |
+| Git operations | git-workflow |
+| Set up Python project | python-env |
+| Run project tasks | task-runner |
+| Find project docs | doc-scanner |
+| Plan implementation | project-planner |
+
+### By Complexity
+
+**Quick Lookups (< 1 min):**
+- rest-patterns: Status code lookup
+- sql-patterns: CTE syntax
+- tailwind-patterns: Breakpoint reference
+- file-search: Basic fd/rg commands
+
+**Medium Tasks (1-5 min):**
+- find-replace: Batch replacements
+- data-processing: JSON transformations
+- git-workflow: Rebase operations
+- python-env: Project setup
+
+**Complex Workflows (5+ min):**
+- structural-search: Security scans
+- doc-scanner: Documentation consolidation
+- project-planner: Session planning
+
+## When to Use Skills vs Agents
+
+**Use a Skill when:**
+- You need quick reference (syntax, patterns)
+- Task is well-defined (replace X with Y)
+- Looking up how to do something
+- Executing a known workflow
+
+**Use an Agent when:**
+- Requires reasoning or decisions
+- Complex problem-solving needed
+- Multiple approaches to evaluate
+- Architecture or optimization
+
+**Example:**
+- "What's the HTTP status for unauthorized?" → rest-patterns (skill)
+- "Design authentication for my API" → python-expert or relevant framework agent

Algúns arquivos non se mostraron porque demasiados arquivos cambiaron neste cambio