From f53d08098e26a31e926488a6fd7fe3f7ecf5c236 Mon Sep 17 00:00:00 2001 From: qk Date: Tue, 7 Apr 2026 13:07:20 +0700 Subject: [PATCH] Add performance-optimizer subagent and dependency-check hook (#36) * feat: add performance-optimizer subagent and dependency-check hook Agent-Logs-Url: https://github.com/khanhnkq/claude-howto/sessions/ef3fb01c-a9c0-466e-9ad2-f255f306add2 Co-authored-by: khanhnkq <180888435+khanhnkq@users.noreply.github.com> * fix(hooks): use basename for manifest matching in dependency-check.sh FILE=$1 receives an absolute path (e.g. /home/user/project/package.json). The case statement and all [[ "$FILE" == ... ]] guards matched bare filenames, so every invocation would hit the *) exit 0 branch and skip all vuln scans. Extract BASENAME=$(basename "$FILE") and use it for all pattern matching. --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: Luong NGUYEN --- 04-subagents/performance-optimizer.md | 126 +++++++++++++++++++++ 06-hooks/dependency-check.sh | 156 ++++++++++++++++++++++++++ CATALOG.md | 8 +- 3 files changed, 287 insertions(+), 3 deletions(-) create mode 100644 04-subagents/performance-optimizer.md create mode 100755 06-hooks/dependency-check.sh diff --git a/04-subagents/performance-optimizer.md b/04-subagents/performance-optimizer.md new file mode 100644 index 0000000..0033802 --- /dev/null +++ b/04-subagents/performance-optimizer.md @@ -0,0 +1,126 @@ +--- +name: performance-optimizer +description: Performance analysis and optimization specialist. Use PROACTIVELY after writing or modifying code to identify bottlenecks, improve throughput, and reduce latency. +tools: Read, Edit, Bash, Grep, Glob +model: inherit +--- + +# Performance Optimizer Agent + +You are an expert performance engineer specializing in identifying and resolving bottlenecks across the full stack. + +When invoked: +1. Profile the target code or system +2. Identify the most impactful bottlenecks +3. Propose and implement optimizations +4. Measure and verify improvements + +## Analysis Process + +1. **Identify the scope** + - Ask what area to optimize (API, database, frontend, algorithm) + - Determine performance goals (latency, throughput, memory) + - Clarify acceptable trade-offs (readability vs speed) + +2. **Profile and measure** + - Run profiling tools relevant to the stack + - Capture baseline metrics before any changes + - Identify hotspots using call graphs and flame charts + +3. **Analyze bottlenecks** + - Algorithmic complexity (Big O) + - I/O-bound vs CPU-bound issues + - Memory allocation and GC pressure + - Database queries and N+1 problems + - Network round-trips and payload size + +4. **Implement optimizations** + - Apply the highest-impact fix first + - Make one change at a time and re-measure + - Preserve correctness (run tests after each change) + +5. **Document results** + - Show before/after metrics + - Explain the trade-offs made + - Recommend monitoring strategies + +## Optimization Checklist + +### Algorithms & Data Structures +- [ ] Replace O(n²) with O(n log n) or O(n) where possible +- [ ] Use appropriate data structures (hash maps for O(1) lookup) +- [ ] Eliminate redundant iterations and recomputation +- [ ] Apply memoization / caching for repeated expensive calls + +### Database +- [ ] Detect and fix N+1 query problems (use JOIN or batch fetch) +- [ ] Add indexes for frequently filtered/sorted columns +- [ ] Use pagination to avoid loading unbounded result sets +- [ ] Prefer projections (select only needed columns) +- [ ] Use connection pooling + +### Backend / API +- [ ] Move heavy work off the request path (async jobs / queues) +- [ ] Cache computed results with appropriate TTLs +- [ ] Enable HTTP compression (gzip / brotli) +- [ ] Use streaming for large responses +- [ ] Pool and reuse expensive resources (DB connections, HTTP clients) + +### Frontend +- [ ] Reduce JavaScript bundle size (tree-shaking, code splitting) +- [ ] Lazy-load images and non-critical assets +- [ ] Minimize layout thrashing (batch DOM reads/writes) +- [ ] Debounce/throttle expensive event handlers +- [ ] Use Web Workers for CPU-intensive tasks + +### Memory +- [ ] Avoid memory leaks (clear timers, remove event listeners) +- [ ] Prefer streaming over loading entire files into memory +- [ ] Reduce object allocation in hot paths + +## Common Profiling Commands + +```bash +# Node.js — CPU profile +node --prof app.js +node --prof-process isolate-*.log > profile.txt + +# Python — function-level profiling +python -m cProfile -s cumulative script.py + +# Go — pprof CPU profile +go test -cpuprofile=cpu.out ./... +go tool pprof cpu.out + +# Database query analysis (PostgreSQL) +EXPLAIN ANALYZE SELECT ...; + +# Find slow endpoints (if using structured logs) +grep '"status":5' access.log | jq '.duration' | sort -n | tail -20 + +# Benchmark a function (Go) +go test -bench=. -benchmem ./... + +# Run k6 load test +k6 run --vus 50 --duration 30s load-test.js +``` + +## Output Format + +For each optimization delivered: +- **Bottleneck**: What was slow and why +- **Root Cause**: Algorithmic / I/O / memory / network issue +- **Before**: Baseline metric (ms, MB, RPS, query count) +- **Change**: Code or config change made +- **After**: Measured improvement +- **Trade-offs**: Any downsides or caveats + +## Investigation Checklist + +- [ ] Baseline metrics captured +- [ ] Hotspots identified via profiling +- [ ] Root cause confirmed (not guessed) +- [ ] Optimization implemented +- [ ] Tests still pass +- [ ] Improvement measured and documented +- [ ] Monitoring / alerting recommended diff --git a/06-hooks/dependency-check.sh b/06-hooks/dependency-check.sh new file mode 100755 index 0000000..c659b9f --- /dev/null +++ b/06-hooks/dependency-check.sh @@ -0,0 +1,156 @@ +#!/bin/bash +# Check for known vulnerabilities in dependencies after manifest files are modified. +# Hook: PostToolUse:Write + +FILE=$1 + +if [ -z "$FILE" ]; then + echo "Usage: $0 " + exit 0 +fi + +# Use basename for matching — $1 may be an absolute path +BASENAME=$(basename "$FILE") + +# Only run when a dependency manifest is written +case "$BASENAME" in + package.json|package-lock.json|yarn.lock|pnpm-lock.yaml| \ + requirements.txt|Pipfile|Pipfile.lock|pyproject.toml| \ + go.mod|go.sum| \ + Cargo.toml|Cargo.lock| \ + Gemfile|Gemfile.lock| \ + composer.json|composer.lock| \ + pom.xml|build.gradle|build.gradle.kts) + echo "📦 Dependency manifest updated: $FILE — scanning for vulnerabilities..." + ;; + *) + exit 0 + ;; +esac + +ISSUES_FOUND=0 + +# ── npm / yarn / pnpm ──────────────────────────────────────────────────────── +if [[ "$BASENAME" == package*.json || "$BASENAME" == yarn.lock || "$BASENAME" == pnpm-lock.yaml ]]; then + if command -v npm &>/dev/null; then + echo "🔍 Running npm audit..." + if ! npm audit --audit-level=high --json 2>/dev/null | \ + python3 -c " +import sys, json +data = json.load(sys.stdin) +vulns = data.get('metadata', {}).get('vulnerabilities', {}) +high = vulns.get('high', 0) + vulns.get('critical', 0) +if high: + print(f' ⚠️ {high} high/critical npm vulnerabilities found. Run: npm audit fix') + sys.exit(1) +" 2>/dev/null; then + ISSUES_FOUND=1 + else + echo " ✅ No high/critical npm vulnerabilities" + fi + fi + + if command -v yarn &>/dev/null && [[ "$BASENAME" == yarn.lock ]]; then + echo "🔍 Running yarn audit..." + if ! yarn audit --level high --json 2>/dev/null | \ + grep -q '"type":"auditAdvisory"' 2>/dev/null; then + echo " ✅ No high yarn vulnerabilities" + else + echo " ⚠️ yarn audit found vulnerabilities. Run: yarn audit --level high" + ISSUES_FOUND=1 + fi + fi +fi + +# ── Python ─────────────────────────────────────────────────────────────────── +if [[ "$BASENAME" == requirements.txt || "$BASENAME" == Pipfile* || "$BASENAME" == pyproject.toml ]]; then + if command -v pip-audit &>/dev/null; then + echo "🔍 Running pip-audit..." + if pip-audit --format=json 2>/dev/null | \ + python3 -c " +import sys, json +data = json.load(sys.stdin) +vulns = [d for d in data.get('dependencies', []) if d.get('vulns')] +if vulns: + for dep in vulns: + for v in dep['vulns']: + print(f' ⚠️ {dep[\"name\"]} {dep[\"version\"]}: {v[\"id\"]} — {v[\"fix_versions\"]}') + sys.exit(1) +" 2>/dev/null; then + echo " ✅ No Python vulnerabilities found" + else + ISSUES_FOUND=1 + echo " Run: pip-audit for details" + fi + elif command -v safety &>/dev/null; then + echo "🔍 Running safety check..." + OUTPUT=$(safety check --short-report 2>&1) + EXIT_CODE=$? + if [ $EXIT_CODE -eq 0 ]; then + echo " ✅ No Python vulnerabilities found" + elif echo "$OUTPUT" | grep -qiE "vulnerability|CVE|insecure"; then + echo "$OUTPUT" + ISSUES_FOUND=1 + else + echo " ⚠️ safety check could not complete (network or config error)" >&2 + fi + fi +fi + +# ── Go ─────────────────────────────────────────────────────────────────────── +if [[ "$BASENAME" == go.mod || "$BASENAME" == go.sum ]]; then + if command -v govulncheck &>/dev/null; then + echo "🔍 Running govulncheck..." + OUTPUT=$(govulncheck ./... 2>&1) + EXIT_CODE=$? + if [ $EXIT_CODE -eq 0 ]; then + echo " ✅ No Go vulnerabilities found" + elif echo "$OUTPUT" | grep -q "Vulnerability #"; then + echo "$OUTPUT" + ISSUES_FOUND=1 + else + echo " ⚠️ govulncheck could not complete: $OUTPUT" >&2 + fi + fi +fi + +# ── Rust ───────────────────────────────────────────────────────────────────── +if [[ "$BASENAME" == Cargo.toml || "$BASENAME" == Cargo.lock ]]; then + if command -v cargo-audit &>/dev/null; then + echo "🔍 Running cargo audit..." + if ! cargo audit 2>/dev/null; then + ISSUES_FOUND=1 + else + echo " ✅ No Rust vulnerabilities found" + fi + fi +fi + +# ── Ruby ───────────────────────────────────────────────────────────────────── +if [[ "$BASENAME" == Gemfile || "$BASENAME" == Gemfile.lock ]]; then + if command -v bundler-audit &>/dev/null; then + echo "🔍 Running bundler-audit..." + bundler-audit check --update 2>/dev/null || ISSUES_FOUND=1 + fi +fi + +# ── Generic fallback: trivy ────────────────────────────────────────────────── +if command -v trivy &>/dev/null; then + echo "🔍 Running trivy fs scan..." + if ! trivy fs --exit-code 1 --severity HIGH,CRITICAL --quiet . 2>/dev/null; then + ISSUES_FOUND=1 + else + echo " ✅ trivy found no HIGH/CRITICAL issues" + fi +fi + +if [ "$ISSUES_FOUND" -eq 0 ]; then + echo "✅ Dependency check passed — no vulnerabilities detected" +else + echo "" + echo "⚠️ Vulnerabilities detected. Review and update dependencies before committing." + echo " This hook is advisory only and will not block your workflow." +fi + +# Always exit 0 — this hook warns but does not block +exit 0 diff --git a/CATALOG.md b/CATALOG.md index f1410b5..9350b98 100644 --- a/CATALOG.md +++ b/CATALOG.md @@ -16,13 +16,13 @@ | Feature | Built-in | Examples | Total | Reference | |---------|----------|----------|-------|-----------| | **Slash Commands** | 55+ | 8 | 63+ | [01-slash-commands/](01-slash-commands/) | -| **Subagents** | 6 | 10 | 16 | [04-subagents/](04-subagents/) | +| **Subagents** | 6 | 11 | 17 | [04-subagents/](04-subagents/) | | **Skills** | 5 bundled | 4 | 9 | [03-skills/](03-skills/) | | **Plugins** | - | 3 | 3 | [07-plugins/](07-plugins/) | | **MCP Servers** | 1 | 8 | 9 | [05-mcp/](05-mcp/) | -| **Hooks** | 25 events | 7 | 7 | [06-hooks/](06-hooks/) | +| **Hooks** | 25 events | 8 | 8 | [06-hooks/](06-hooks/) | | **Memory** | 7 types | 3 | 3 | [02-memory/](02-memory/) | -| **Total** | **99** | **43** | **117** | | +| **Total** | **99** | **45** | **119** | | --- @@ -171,6 +171,7 @@ Specialized AI assistants with isolated contexts for specific tasks. | `implementation-agent` | Full feature implementation | Feature development | Project | `cp 04-subagents/implementation-agent.md .claude/agents/` | | `debugger` | Root cause analysis | Bug investigation | User | `cp 04-subagents/debugger.md .claude/agents/` | | `data-scientist` | SQL queries, data analysis | Data tasks | User | `cp 04-subagents/data-scientist.md .claude/agents/` | +| `performance-optimizer` | Profiling & performance tuning | Bottleneck investigation | Project | `cp 04-subagents/performance-optimizer.md .claude/agents/` | > **Scope**: `User` = personal (`~/.claude/agents/`), `Project` = team-shared (`.claude/agents/`) @@ -367,6 +368,7 @@ Event-driven automation that executes shell commands on Claude Code events. | `context-tracker.py` | Token usage tracking | Stop | User | `cp 06-hooks/context-tracker.py ~/.claude/hooks/` | | `pre-commit.sh` | Pre-commit validation | PreToolUse:Bash | Project | `cp 06-hooks/pre-commit.sh .claude/hooks/` | | `log-bash.sh` | Command logging | PostToolUse:Bash | User | `cp 06-hooks/log-bash.sh ~/.claude/hooks/` | +| `dependency-check.sh` | Vulnerability scan on manifest changes | PostToolUse:Write | Project | `cp 06-hooks/dependency-check.sh .claude/hooks/` | > **Scope**: `Project` = team (`.claude/settings.json`), `User` = personal (`~/.claude/settings.json`)