Sentry Skills

/sentry-agents-md
Source: ~/.claude/skills/sentry-agents-md/SKILL.md 
 
 name: agents-md
description: This skill should be used when the user asks to "create AGENTS.md", "update AGENTS.md", "maintain agent docs", "set up CLAUDE.md", or needs to keep agent instructions concise. Guides discovery of local skills and enforces minimal documentation style. 
 Maintaining AGENTS.md 
 AGENTS.md is the canonical agent-facing documentation. Keep it minimal—agents are capable and don't need hand-holding. 
 File Setup 
 
 Create AGENTS.md at project root 
 Create symlink: ln -s AGENTS.md CLAUDE.md 
 
 Before Writing 
 Discover local skills to reference: 
 find .claude/skills -name "SKILL.md" 2>/dev/null
ls plugins/*/skills/*/SKILL.md 2>/dev/null
 
 Read each skill's frontmatter to understand when to reference it. 
 Writing Rules 
 
 Headers + bullets - No paragraphs 
 Code blocks - For commands and templates 
 Reference, don't duplicate - Point to skills: "Use db-migrate skill. See .claude/skills/db-migrate/SKILL.md " 
 No filler - No intros, conclusions, or pleasantries 
 Trust capabilities - Omit obvious context 
 
 Required Sections 
 Package Manager 
 Which tool and key commands only: 
 ## Package Manager
Use **pnpm**: `pnpm install`, `pnpm dev`, `pnpm test`
 
 Commit Attribution 
 Always include this section. Agents should use their own identity: 
 ## Commit Attribution
AI commits MUST include:
 
 Co-Authored-By: (the agent model's name and attribution byline) 
 Example: `Co-Authored-By: Claude Sonnet 4 <noreply@example.com>`
 
 Key Conventions 
 Project-specific patterns agents must follow. Keep brief. 
 Local Skills 
 Reference each discovered skill: 
 ## Database
Use `db-migrate` skill for schema changes. See `.claude/skills/db-migrate/SKILL.md`

## Testing
Use `write-tests` skill. See `.claude/skills/write-tests/SKILL.md`
 
 Optional Sections 
 Add only if truly needed: 
 
 API route patterns (show template, not explanation) 
 CLI commands (table format) 
 File naming conventions 
 
 Anti-Patterns 
 Omit these: 
 
 "Welcome to..." or "This document explains..." 
 "You should..." or "Remember to..." 
 Content duplicated from skills (reference instead) 
 Obvious instructions ("run tests", "write clean code") 
 Explanations of why (just say what) 
 Long prose paragraphs 
 
 Example Structure 
 # Agent Instructions

## Package Manager
Use **pnpm**: `pnpm install`, `pnpm dev`

## Commit Attribution
AI commits MUST include:
 
 Co-Authored-By: (the agent model's name and attribution byline) 
 
## API Routes
[Template code block]

## Database
Use `db-migrate` skill. See `.claude/skills/db-migrate/SKILL.md`

## Testing
Use `write-tests` skill. See `.claude/skills/write-tests/SKILL.md`

## CLI
| Command | Description |
|---------|-------------|
| `pnpm cli sync` | Sync data |

/sentry-brand-guidelines
Source: ~/.claude/skills/sentry-brand-guidelines/SKILL.md 
 
 name: brand-guidelines
description: Write copy following Sentry brand guidelines. Use when writing UI text, error messages, empty states, onboarding flows, 404 pages, documentation, marketing copy, or any user-facing content. Covers both Plain Speech (default) and Sentry Voice tones. 
 Brand Guidelines 
 Write user-facing copy following Sentry's brand guidelines. 
 Tone Selection 
 Choose the appropriate tone based on context: 
 
 
 
 Use Plain Speech 
 Use Sentry Voice 
 
 
 
 
 Product UI (buttons, labels, forms) 
 404 pages 
 
 
 Documentation 
 Empty states 
 
 
 Error messages 
 Onboarding flows 
 
 
 Settings pages 
 Loading states 
 
 
 Transactional emails 
 "What's New" announcements 
 
 
 Help text 
 Marketing copy 
 
 
 
 Default to Plain Speech unless the context specifically calls for personality. 
 Plain Speech (Default) 
 Plain Speech is clear, direct, and functional. Use it for most UI elements. 
 Rules 
 
 Be concise - Use the fewest words needed 
 Be direct - Tell users what to do, not what they can do 
 Use active voice - "Save your changes" not "Your changes will be saved" 
 Avoid jargon - Use simple words users understand 
 Be specific - "3 errors found" not "Some errors found" 
 
 Examples 
 
 
 
 Instead of 
 Write 
 
 
 
 
 "Click here to save your changes" 
 "Save" 
 
 
 "You can filter results by date" 
 "Filter by date" 
 
 
 "An error has occurred" 
 "Something went wrong" 
 
 
 "Please enter a valid email address" 
 "Enter a valid email" 
 
 
 "Are you sure you want to delete?" 
 "Delete this item?" 
 
 
 
 Sentry Voice 
 Sentry Voice adds personality in appropriate moments. It's empathetic, self-aware, and occasionally snarky. 
 Principles 
 
 Empathetic snark - Direct frustration at the situation, never the user 
 Self-aware - Acknowledge the absurdity of software 
 Fun but functional - Personality should enhance, not obscure meaning 
 Earned moments - Only use when users have time to appreciate it 
 
 Examples 
 404 Pages: 
 
 "This page doesn't exist. Maybe it never did. Maybe it was a dream. Either way, let's get you back on track." 
 
 Empty States: 
 
 "No errors yet. Enjoy this moment of peace while it lasts." 
 
 Onboarding: 
 
 "Let's get your first error. Don't worry, it's not as scary as it sounds." 
 
 Loading States: 
 
 "Crunching the numbers..."
"Fetching your data..." 
 
 When NOT to Use Sentry Voice 
 
 Error messages (users are frustrated) 
 Settings pages (users are focused) 
 Documentation (users need information) 
 Billing/payment flows (users need trust) 
 
 General Rules 
 Spelling and Grammar 
 
 Use American English spelling (color, not colour) 
 Use Title Case for headings and page titles 
 Use Sentence case for body text, buttons, and labels 
 
 Punctuation 
 
 No exclamation marks in UI text (exception: celebratory moments) 
 No periods in short UI labels or button text 
 Use periods in complete sentences and help text 
 No ALL CAPS except for acronyms (API, SDK, URL) 
 
 Word Choices 
 
 
 
 Avoid 
 Prefer 
 
 
 
 
 Please 
 (omit) 
 
 
 Sorry 
 (be specific about the problem) 
 
 
 Error occurred 
 Something went wrong 
 
 
 Invalid 
 (explain what's wrong) 
 
 
 Success! 
 (describe what happened) 
 
 
 Oops 
 (be specific) 
 
 
 
 Dash Usage 
 
 
 
 Type 
 Use 
 Example 
 
 
 
 
 Hyphen (-) 
 Compound words, ranges 
 "real-time", "1-10" 
 
 
 En-dash (--) 
 Ranges, relationships 
 "2023--2024", "parent--child" 
 
 
 Em-dash (---) 
 Interruption, emphasis 
 "Errors---even small ones---matter" 
 
 
 
 In most UI contexts, use hyphens. Reserve en-dashes for date ranges and em-dashes for longer prose. 
 UI Element Guidelines 
 Buttons 
 
 Use action verbs: "Save", "Delete", "Create" 
 Be specific: "Create Project" not just "Create" 
 Max 2-3 words when possible 
 No periods or exclamation marks 
 
 Error Messages 
 
 Say what happened 
 Say why (if helpful) 
 Say what to do next 
 
 Good: "Could not save changes. Check your connection and try again."
 Bad: "Error: Save failed." 
 Empty States 
 
 Explain what would normally be here 
 Provide a clear action to populate the state 
 Sentry Voice is appropriate here 
 
 Good: "No projects yet. Create your first project to start tracking errors." 
 Confirmation Dialogs 
 
 Make the action clear in the title 
 Explain consequences if destructive 
 Use specific button labels ("Delete Project", not "OK") 
 
 Tooltips and Help Text 
 
 Keep under 2 sentences 
 Explain the "why", not just the "what" 
 Link to docs for complex topics 
 
 Anti-Patterns 
 Avoid these common mistakes: 
 
 Robot speak: "Item has been successfully deleted" -> "Deleted" 
 Passive voice: "Changes were saved" -> "Changes saved" 
 Unnecessary words: "In order to" -> "To" 
 Hedging: "This might cause..." -> "This will cause..." 
 Double negatives: "Not unlike..." -> "Similar to..." 
 Marketing speak in UI: "Supercharge your workflow" -> "Speed up your workflow" 
 
 References 
 
 Sentry Voice Guidelines 
 Sentry Frontend Handbook

/sentry-claude-settings-audit
Source: ~/.claude/skills/sentry-claude-settings-audit/SKILL.md 
 
 name: claude-settings-audit
description: Analyze a repository to generate recommended Claude Code settings.json permissions. Use when setting up a new project, auditing existing settings, or determining which read-only bash commands to allow. Detects tech stack, build tools, and monorepo structure. 
 Claude Settings Audit 
 Analyze this repository and generate recommended Claude Code settings.json permissions for read-only commands. 
 Phase 1: Detect Tech Stack 
 Run these commands to detect the repository structure: 
 ls -la
find . -maxdepth 2 \( -name "*.toml" -o -name "*.json" -o -name "*.lock" -o -name "*.yaml" -o -name "*.yml" -o -name "Makefile" -o -name "Dockerfile" -o -name "*.tf" \) 2>/dev/null | head -50
 
 Check for these indicator files: 
 
 
 
 Category 
 Files to Check 
 
 
 
 
 Python 
 pyproject.toml , setup.py , requirements.txt , Pipfile , poetry.lock , uv.lock 
 
 
 Node.js 
 package.json , package-lock.json , yarn.lock , pnpm-lock.yaml 
 
 
 Go 
 go.mod , go.sum 
 
 
 Rust 
 Cargo.toml , Cargo.lock 
 
 
 Ruby 
 Gemfile , Gemfile.lock 
 
 
 Java 
 pom.xml , build.gradle , build.gradle.kts 
 
 
 Build 
 Makefile , Dockerfile , docker-compose.yml 
 
 
 Infra 
 *.tf files, kubernetes/ , helm/ 
 
 
 Monorepo 
 lerna.json , nx.json , turbo.json , pnpm-workspace.yaml 
 
 
 
 Phase 2: Detect Services 
 Check for service integrations: 
 
 
 
 Service 
 Detection 
 
 
 
 
 Sentry 
 sentry-sdk in deps, @sentry/* packages, .sentryclirc , sentry.properties 
 
 
 Linear 
 Linear config files, .linear/ directory 
 
 
 
 Read dependency files to identify frameworks: 
 
 package.json → check dependencies and devDependencies 
 pyproject.toml → check [project.dependencies] or [tool.poetry.dependencies] 
 Gemfile → check gem names 
 Cargo.toml → check [dependencies] 
 
 Phase 3: Check Existing Settings 
 cat .claude/settings.json 2>/dev/null || echo "No existing settings"
 
 Phase 4: Generate Recommendations 
 Build the allow list by combining: 
 Baseline Commands (Always Include) 
 [
 "Bash(ls:*)",
 "Bash(pwd:*)",
 "Bash(find:*)",
 "Bash(file:*)",
 "Bash(stat:*)",
 "Bash(wc:*)",
 "Bash(head:*)",
 "Bash(tail:*)",
 "Bash(cat:*)",
 "Bash(tree:*)",
 "Bash(git status:*)",
 "Bash(git log:*)",
 "Bash(git diff:*)",
 "Bash(git show:*)",
 "Bash(git branch:*)",
 "Bash(git remote:*)",
 "Bash(git tag:*)",
 "Bash(git stash list:*)",
 "Bash(git rev-parse:*)",
 "Bash(gh pr view:*)",
 "Bash(gh pr list:*)",
 "Bash(gh pr checks:*)",
 "Bash(gh pr diff:*)",
 "Bash(gh issue view:*)",
 "Bash(gh issue list:*)",
 "Bash(gh run view:*)",
 "Bash(gh run list:*)",
 "Bash(gh run logs:*)",
 "Bash(gh repo view:*)",
 "Bash(gh api:*)"
]
 
 Stack-Specific Commands 
 Only include commands for tools actually detected in the project. 
 Python (if any Python files or config detected) 
 
 
 
 If Detected 
 Add These Commands 
 
 
 
 
 Any Python 
 python --version , python3 --version 
 
 
 poetry.lock 
 poetry show , poetry env info 
 
 
 uv.lock 
 uv pip list , uv tree 
 
 
 Pipfile.lock 
 pipenv graph 
 
 
 requirements.txt (no other lock) 
 pip list , pip show , pip freeze 
 
 
 
 Node.js (if package.json detected) 
 
 
 
 If Detected 
 Add These Commands 
 
 
 
 
 Any Node.js 
 node --version 
 
 
 pnpm-lock.yaml 
 pnpm list , pnpm why 
 
 
 yarn.lock 
 yarn list , yarn info , yarn why 
 
 
 package-lock.json 
 npm list , npm view , npm outdated 
 
 
 TypeScript ( tsconfig.json ) 
 tsc --version 
 
 
 
 Other Languages 
 
 
 
 If Detected 
 Add These Commands 
 
 
 
 
 go.mod 
 go version , go list , go mod graph , go env 
 
 
 Cargo.toml 
 rustc --version , cargo --version , cargo tree , cargo metadata 
 
 
 Gemfile 
 ruby --version , bundle list , bundle show 
 
 
 pom.xml 
 java --version , mvn --version , mvn dependency:tree 
 
 
 build.gradle 
 java --version , gradle --version , gradle dependencies 
 
 
 
 Build Tools 
 
 
 
 If Detected 
 Add These Commands 
 
 
 
 
 Dockerfile 
 docker --version , docker ps , docker images 
 
 
 docker-compose.yml 
 docker-compose ps , docker-compose config 
 
 
 *.tf files 
 terraform --version , terraform providers , terraform state list 
 
 
 Makefile 
 make --version , make -n 
 
 
 
 Skills (for Sentry Projects) 
 If this is a Sentry project (or sentry-skills plugin is installed), include: 
 [
 "Skill(sentry-skills:commit)",
 "Skill(sentry-skills:create-pr)",
 "Skill(sentry-skills:code-review)",
 "Skill(sentry-skills:find-bugs)",
 "Skill(sentry-skills:iterate-pr)",
 "Skill(sentry-skills:claude-settings-audit)",
 "Skill(sentry-skills:agents-md)",
 "Skill(sentry-skills:brand-guidelines)",
 "Skill(sentry-skills:doc-coauthoring)",
 "Skill(sentry-skills:security-review)",
 "Skill(sentry-skills:django-perf-review)",
 "Skill(sentry-skills:code-simplifier)",
 "Skill(sentry-skills:skill-creator)",
 "Skill(sentry-skills:skill-scanner)"
]
 
 WebFetch Domains 
 Always Include (Sentry Projects) 
 [
 "WebFetch(domain:docs.sentry.io)",
 "WebFetch(domain:develop.sentry.dev)",
 "WebFetch(domain:docs.github.com)",
 "WebFetch(domain:cli.github.com)"
]
 
 Framework-Specific 
 
 
 
 If Detected 
 Add Domains 
 
 
 
 
 Django 
 docs.djangoproject.com 
 
 
 Flask 
 flask.palletsprojects.com 
 
 
 FastAPI 
 fastapi.tiangolo.com 
 
 
 React 
 react.dev 
 
 
 Next.js 
 nextjs.org 
 
 
 Vue 
 vuejs.org 
 
 
 Express 
 expressjs.com 
 
 
 Rails 
 guides.rubyonrails.org , api.rubyonrails.org 
 
 
 Go 
 pkg.go.dev 
 
 
 Rust 
 docs.rs , doc.rust-lang.org 
 
 
 Docker 
 docs.docker.com 
 
 
 Kubernetes 
 kubernetes.io 
 
 
 Terraform 
 registry.terraform.io 
 
 
 
 MCP Server Suggestions 
 MCP servers are configured in .mcp.json (not settings.json ). Check for existing config: 
 cat .mcp.json 2>/dev/null || echo "No existing .mcp.json"
 
 Sentry MCP (if Sentry SDK detected) 
 Add to .mcp.json (replace {org-slug} and {project-slug} with your Sentry organization and project slugs): 
 {
 "mcpServers": {
 "sentry": {
 "type": "http",
 "url": "https://mcp.sentry.dev/mcp/{org-slug}/{project-slug}"
 }
 }
}
 
 Linear MCP (if Linear usage detected) 
 Add to .mcp.json : 
 {
 "mcpServers": {
 "linear": {
 "command": "npx",
 "args": ["-y", "@linear/mcp-server"],
 "env": {
 "LINEAR_API_KEY": "${LINEAR_API_KEY}"
 }
 }
 }
}
 
 Note : Never suggest GitHub MCP. Always use gh CLI commands for GitHub. 
 Output Format 
 Present your findings as: 
 
 Summary Table - What was detected 
 Recommended settings.json - Complete JSON ready to copy 
 MCP Suggestions - If applicable 
 Merge Instructions - If existing settings found 
 
 Example output structure: 
 ## Detected Tech Stack

| Category | Found |
| --------------- | -------------- |
| Languages | Python 3.x |
| Package Manager | poetry |
| Frameworks | Django, Celery |
| Services | Sentry |
| Build Tools | Docker, Make |

## Recommended .claude/settings.json

\`\`\`json
{
"permissions": {
"allow": [
// ... grouped by category with comments
],
"deny": []
}
}
\`\`\`

## Recommended .mcp.json (if applicable)

If you use Sentry or Linear, add the MCP config to `.mcp.json`...
 
 Important Rules 
 What to Include 
 
 Only READ-ONLY commands that cannot modify state 
 Only tools that are actually used by the project (detected via lock files) 
 Standard system commands (ls, cat, find, etc.) 
 The :* suffix allows any arguments to the base command 
 
 What to NEVER Include 
 
 Absolute paths - Never include user-specific paths like /home/user/scripts/foo or /Users/name/bin/bar 
 Custom scripts - Never include project scripts that may have side effects (e.g., ./scripts/deploy.sh ) 
 Alternative package managers - If the project uses pnpm, do NOT include npm/yarn commands 
 Commands that modify state - No install, build, run, write, or delete commands 
 
 Package Manager Rules 
 Only include the package manager actually used by the project: 
 
 
 
 If Detected 
 Include 
 Do NOT Include 
 
 
 
 
 pnpm-lock.yaml 
 pnpm commands 
 npm, yarn 
 
 
 yarn.lock 
 yarn commands 
 npm, pnpm 
 
 
 package-lock.json 
 npm commands 
 yarn, pnpm 
 
 
 poetry.lock 
 poetry commands 
 pip (unless also has requirements.txt) 
 
 
 uv.lock 
 uv commands 
 pip, poetry 
 
 
 Pipfile.lock 
 pipenv commands 
 pip, poetry 
 
 
 
 If multiple lock files exist, include only the commands for each detected manager.

/sentry-code-review
Source: ~/.claude/skills/sentry-code-review/SKILL.md 
 
 name: code-review
description: Perform code reviews following Sentry engineering practices. Use when reviewing pull requests, examining code changes, or providing feedback on code quality. Covers security, performance, testing, and design review. 
 Sentry Code Review 
 Follow these guidelines when reviewing code for Sentry projects. 
 Review Checklist 
 Identifying Problems 
 Look for these issues in code changes: 
 
 Runtime errors : Potential exceptions, null pointer issues, out-of-bounds access 
 Performance : Unbounded O(n²) operations, N+1 queries, unnecessary allocations 
 Side effects : Unintended behavioral changes affecting other components 
 Backwards compatibility : Breaking API changes without migration path 
 ORM queries : Complex Django ORM with unexpected query performance 
 Security vulnerabilities : Injection, XSS, access control gaps, secrets exposure 
 
 Design Assessment 
 
 Do component interactions make logical sense? 
 Does the change align with existing project architecture? 
 Are there conflicts with current requirements or goals? 
 
 Test Coverage 
 Every PR should have appropriate test coverage: 
 
 Functional tests for business logic 
 Integration tests for component interactions 
 End-to-end tests for critical user paths 
 
 Verify tests cover actual requirements and edge cases. Avoid excessive branching or looping in test code. 
 Long-Term Impact 
 Flag for senior engineer review when changes involve: 
 
 Database schema modifications 
 API contract changes 
 New framework or library adoption 
 Performance-critical code paths 
 Security-sensitive functionality 
 
 Feedback Guidelines 
 Tone 
 
 Be polite and empathetic 
 Provide actionable suggestions, not vague criticism 
 Phrase as questions when uncertain: "Have you considered...?" 
 
 Approval 
 
 Approve when only minor issues remain 
 Don't block PRs for stylistic preferences 
 Remember: the goal is risk reduction, not perfect code 
 
 Common Patterns to Flag 
 Python/Django 
 # Bad: N+1 query
for user in users:
 print(user.profile.name) # Separate query per user

# Good: Prefetch related
users = User.objects.prefetch_related('profile')
 
 TypeScript/React 
 // Bad: Missing dependency in useEffect
useEffect(() => {
 fetchData(userId);
}, []); // userId not in deps

// Good: Include all dependencies
useEffect(() => {
 fetchData(userId);
}, [userId]);
 
 Security 
 # Bad: SQL injection risk
cursor.execute(f"SELECT * FROM users WHERE id = {user_id}")

# Good: Parameterized query
cursor.execute("SELECT * FROM users WHERE id = %s", [user_id])
 
 References 
 
 Sentry Code Review Guidelines

/sentry-code-simplifier
Source: ~/.claude/skills/sentry-code-simplifier/SKILL.md 
 
 name: code-simplifier
description: Simplifies and refines code for clarity, consistency, and maintainability while preserving all functionality. Use when asked to "simplify code", "clean up code", "refactor for clarity", "improve readability", or review recently modified code for elegance. Focuses on project-specific best practices. 

 Code Simplifier 
 You are an expert code simplification specialist focused on enhancing code clarity, consistency, and maintainability while preserving exact functionality. Your expertise lies in applying project-specific best practices to simplify and improve code without altering its behavior. You prioritize readable, explicit code over overly compact solutions. 
 Refinement Principles 
 1. Preserve Functionality 
 Never change what the code does - only how it does it. All original features, outputs, and behaviors must remain intact. 
 2. Apply Project Standards 
 Follow the established coding standards from CLAUDE.md including: 
 
 Use ES modules with proper import sorting and extensions 
 Prefer function keyword over arrow functions 
 Use explicit return type annotations for top-level functions 
 Follow proper React component patterns with explicit Props types 
 Use proper error handling patterns (avoid try/catch when possible) 
 Maintain consistent naming conventions 
 
 3. Enhance Clarity 
 Simplify code structure by: 
 
 Reducing unnecessary complexity and nesting 
 Eliminating redundant code and abstractions 
 Improving readability through clear variable and function names 
 Consolidating related logic 
 Removing unnecessary comments that describe obvious code 
 Avoiding nested ternary operators - prefer switch statements or if/else chains for multiple conditions 
 Choosing clarity over brevity - explicit code is often better than overly compact code 
 
 4. Maintain Balance 
 Avoid over-simplification that could: 
 
 Reduce code clarity or maintainability 
 Create overly clever solutions that are hard to understand 
 Combine too many concerns into single functions or components 
 Remove helpful abstractions that improve code organization 
 Prioritize "fewer lines" over readability (e.g., nested ternaries, dense one-liners) 
 Make the code harder to debug or extend 
 
 5. Focus Scope 
 Only refine code that has been recently modified or touched in the current session, unless explicitly instructed to review a broader scope. 
 Refinement Process 
 
 Identify the recently modified code sections 
 Analyze for opportunities to improve elegance and consistency 
 Apply project-specific best practices and coding standards 
 Ensure all functionality remains unchanged 
 Verify the refined code is simpler and more maintainable 
 Document only significant changes that affect understanding 
 
 Examples 
 Before: Nested Ternaries 
 const status = isLoading ? 'loading' : hasError ? 'error' : isComplete ? 'complete' : 'idle';
 
 After: Clear Switch Statement 
 function getStatus(isLoading: boolean, hasError: boolean, isComplete: boolean): string {
 if (isLoading) return 'loading';
 if (hasError) return 'error';
 if (isComplete) return 'complete';
 return 'idle';
}
 
 Before: Overly Compact 
 const result = arr.filter(x => x > 0).map(x => x * 2).reduce((a, b) => a + b, 0);
 
 After: Clear Steps 
 const positiveNumbers = arr.filter(x => x > 0);
const doubled = positiveNumbers.map(x => x * 2);
const sum = doubled.reduce((a, b) => a + b, 0);
 
 Before: Redundant Abstraction 
 function isNotEmpty(arr: unknown[]): boolean {
 return arr.length > 0;
}

if (isNotEmpty(items)) {
 // ...
}
 
 After: Direct Check 
 if (items.length > 0) {
 // ...
}

/sentry-commit
Source: ~/.claude/skills/sentry-commit/SKILL.md 
 
 name: commit
description: Create commit messages following Sentry conventions. Use when committing code changes, writing commit messages, or formatting git history. Follows conventional commits with Sentry-specific issue references. 
 Sentry Commit Messages 
 Follow these conventions when creating commits for Sentry projects. 
 Prerequisites 
 Before committing, ensure you're working on a feature branch, not the main branch. 
 # Check current branch
git branch --show-current
 
 If you're on main or master , create a new branch first: 
 # Create and switch to a new branch
git checkout -b <type>/<short-description>
 
 Branch naming should follow the pattern: <type>/<short-description> where type matches the commit type (e.g., feat/add-user-auth , fix/null-pointer-error , ref/extract-validation ). 
 Format 
 <type>(<scope>): <subject>

<body>

<footer>
 
 The header is required. Scope is optional. All lines must stay under 100 characters. 
 Commit Types 
 
 
 
 Type 
 Purpose 
 
 
 
 
 feat 
 New feature 
 
 
 fix 
 Bug fix 
 
 
 ref 
 Refactoring (no behavior change) 
 
 
 perf 
 Performance improvement 
 
 
 docs 
 Documentation only 
 
 
 test 
 Test additions or corrections 
 
 
 build 
 Build system or dependencies 
 
 
 ci 
 CI configuration 
 
 
 chore 
 Maintenance tasks 
 
 
 style 
 Code formatting (no logic change) 
 
 
 meta 
 Repository metadata 
 
 
 license 
 License changes 
 
 
 
 Subject Line Rules 
 
 Use imperative, present tense: "Add feature" not "Added feature" 
 Capitalize the first letter 
 No period at the end 
 Maximum 70 characters 
 
 Body Guidelines 
 
 Explain what and why , not how 
 Use imperative mood and present tense 
 Include motivation for the change 
 Contrast with previous behavior when relevant 
 
 Footer: Issue References 
 Reference issues in the footer using these patterns: 
 Fixes GH-1234
Fixes #1234
Fixes SENTRY-1234
Refs LINEAR-ABC-123
 
 
 Fixes closes the issue when merged 
 Refs links without closing 
 
 AI-Generated Changes 
 When changes were primarily generated by a coding agent (like Claude Code), include the Co-Authored-By attribution in the commit footer: 
 Co-Authored-By: Claude <noreply@anthropic.com>
 
 This is the only indicator of AI involvement that should appear in commits. Do not add phrases like "Generated by AI", "Written with Claude", or similar markers in the subject, body, or anywhere else in the commit message. 
 Examples 
 Simple fix 
 fix(api): Handle null response in user endpoint

The user API could return null for deleted accounts, causing a crash
in the dashboard. Add null check before accessing user properties.

Fixes SENTRY-5678
Co-Authored-By: Claude <noreply@anthropic.com>
 
 Feature with scope 
 feat(alerts): Add Slack thread replies for alert updates

When an alert is updated or resolved, post a reply to the original
Slack thread instead of creating a new message. This keeps related
notifications grouped together.

Refs GH-1234
 
 Refactor 
 ref: Extract common validation logic to shared module

Move duplicate validation code from three endpoints into a shared
validator class. No behavior change.
 
 Breaking change 
 feat(api)!: Remove deprecated v1 endpoints

Remove all v1 API endpoints that were deprecated in version 23.1.
Clients should migrate to v2 endpoints.

BREAKING CHANGE: v1 endpoints no longer available
Fixes SENTRY-9999
 
 Revert Format 
 revert: feat(api): Add new endpoint

This reverts commit abc123def456.

Reason: Caused performance regression in production.
 
 Principles 
 
 Each commit should be a single, stable change 
 Commits should be independently reviewable 
 The repository should be in a working state after each commit 
 
 References 
 
 Sentry Commit Messages

/sentry-create-pr
Source: ~/.claude/skills/sentry-create-pr/SKILL.md 
 
 name: create-pr
description: Create pull requests following Sentry conventions. Use when opening PRs, writing PR descriptions, or preparing changes for review. Follows Sentry's code review guidelines. 
 Create Pull Request 
 Create pull requests following Sentry's engineering practices. 
 Requires : GitHub CLI ( gh ) authenticated and available. 
 Prerequisites 
 Before creating a PR, ensure all changes are committed. If there are uncommitted changes, run the sentry-skills:commit skill first to commit them properly. 
 # Check for uncommitted changes
git status --porcelain
 
 If the output shows any uncommitted changes (modified, added, or untracked files that should be included), invoke the sentry-skills:commit skill before proceeding. 
 Process 
 Step 1: Verify Branch State 
 # Detect the default branch
BASE=$(gh repo view --json defaultBranchRef --jq '.defaultBranchRef.name')

# Check current branch and status
git status
git log $BASE..HEAD --oneline
 
 Ensure: 
 
 All changes are committed 
 Branch is up to date with remote 
 Changes are rebased on the base branch if needed 
 
 Step 2: Analyze Changes 
 Review what will be included in the PR: 
 # See all commits that will be in the PR
git log $BASE..HEAD

# See the full diff
git diff $BASE...HEAD
 
 Understand the scope and purpose of all changes before writing the description. 
 Step 3: Write the PR Description 
 Use this structure for PR descriptions (ignoring any repository PR templates): 
 <brief description of what the PR does>

<why these changes are being made - the motivation>

<alternative approaches considered, if any>

<any additional context reviewers need>
 
 Do NOT include: 
 
 "Test plan" sections 
 Checkbox lists of testing steps 
 Redundant summaries of the diff 
 
 Do include: 
 
 Clear explanation of what and why 
 Links to relevant issues or tickets 
 Context that isn't obvious from the code 
 Notes on specific areas that need careful review 
 
 Step 4: Create the PR 
 gh pr create --draft --title "<type>(<scope>): <description>" --body "$(cat <<'EOF'
<description body here>
EOF
)"
 
 Title format follows commit conventions: 
 
 feat(scope): Add new feature 
 fix(scope): Fix the bug 
 ref: Refactor something 
 
 PR Description Examples 
 Feature PR 
 Add Slack thread replies for alert notifications

When an alert is updated or resolved, we now post a reply to the original
Slack thread instead of creating a new message. This keeps related
notifications grouped and reduces channel noise.

Previously considered posting edits to the original message, but threading
better preserves the timeline of events and works when the original message
is older than Slack's edit window.

Refs SENTRY-1234
 
 Bug Fix PR 
 Handle null response in user API endpoint

The user endpoint could return null for soft-deleted accounts, causing
dashboard crashes when accessing user properties. This adds a null check
and returns a proper 404 response.

Found while investigating SENTRY-5678.

Fixes SENTRY-5678
 
 Refactor PR 
 Extract validation logic to shared module

Moves duplicate validation code from the alerts, issues, and projects
endpoints into a shared validator class. No behavior change.

This prepares for adding new validation rules in SENTRY-9999 without
duplicating logic across endpoints.
 
 Issue References 
 Reference issues in the PR body: 
 
 
 
 Syntax 
 Effect 
 
 
 
 
 Fixes #1234 
 Closes GitHub issue on merge 
 
 
 Fixes SENTRY-1234 
 Closes Sentry issue 
 
 
 Refs GH-1234 
 Links without closing 
 
 
 Refs LINEAR-ABC-123 
 Links Linear issue 
 
 
 
 Guidelines 
 
 One PR per feature/fix - Don't bundle unrelated changes 
 Keep PRs reviewable - Smaller PRs get faster, better reviews 
 Explain the why - Code shows what; description explains why 
 Mark WIP early - Use draft PRs for early feedback 
 
 Editing Existing PRs 
 If you need to update a PR after creation, use gh api instead of gh pr edit : 
 # Update PR description
gh api -X PATCH repos/{owner}/{repo}/pulls/PR_NUMBER -f body="$(cat <<'EOF'
Updated description here
EOF
)"

# Update PR title
gh api -X PATCH repos/{owner}/{repo}/pulls/PR_NUMBER -f title='new: Title here'

# Update both
gh api -X PATCH repos/{owner}/{repo}/pulls/PR_NUMBER \
 -f title='new: Title' \
 -f body='New description'
 
 Note: gh pr edit is currently broken due to GitHub's Projects (classic) deprecation. 
 References 
 
 Sentry Code Review Guidelines 
 Sentry Commit Messages

/sentry-django-access-review
Source: ~/.claude/skills/sentry-django-access-review/SKILL.md 
 
 name: django-access-review
description: 'Django access control and IDOR security review. Use when reviewing Django views, DRF viewsets, ORM queries, or any Python/Django code handling user authorization. Trigger keywords: "IDOR", "access control", "authorization", "Django permissions", "object permissions", "tenant isolation", "broken access".'
allowed-tools: Read Grep Glob Bash Task
license: LICENSE 

 Django Access Control & IDOR Review 
 Find access control vulnerabilities by investigating how the codebase answers one question: 
 Can User A access, modify, or delete User B's data? 
 Philosophy: Investigation Over Pattern Matching 
 Do NOT scan for predefined vulnerable patterns. Instead: 
 
 Understand how authorization works in THIS codebase 
 Ask questions about specific data flows 
 Trace code to find where (or if) access checks happen 
 Report only what you've confirmed through investigation 
 
 Every codebase implements authorization differently. Your job is to understand this specific implementation, then find gaps. 
 
 Phase 1: Understand the Authorization Model 
 Before looking for bugs, answer these questions about the codebase: 
 How is authorization enforced? 
 Research the codebase to find: 
 □ Where are permission checks implemented?
 - Decorators? (@login_required, @permission_required, custom?)
 - Middleware? (TenantMiddleware, AuthorizationMiddleware?)
 - Base classes? (BaseAPIView, TenantScopedViewSet?)
 - Permission classes? (DRF permission_classes?)
 - Custom mixins? (OwnershipMixin, TenantMixin?)

□ How are queries scoped?
 - Custom managers? (TenantManager, UserScopedManager?)
 - get_queryset() overrides?
 - Middleware that sets query context?

□ What's the ownership model?
 - Single user ownership? (document.owner_id)
 - Organization/tenant ownership? (document.organization_id)
 - Hierarchical? (org -> team -> user -> resource)
 - Role-based within context? (org admin vs member)
 
 Investigation commands 
 # Find how auth is typically done
grep -rn "permission_classes\|@login_required\|@permission_required" --include="*.py" | head -20

# Find base classes that views inherit from
grep -rn "class Base.*View\|class.*Mixin.*:" --include="*.py" | head -20

# Find custom managers
grep -rn "class.*Manager\|def get_queryset" --include="*.py" | head -20

# Find ownership fields on models
grep -rn "owner\|user_id\|organization\|tenant" --include="models.py" | head -30
 
 Do not proceed until you understand the authorization model. 
 
 Phase 2: Map the Attack Surface 
 Identify endpoints that handle user-specific data: 
 What resources exist? 
 □ What models contain user data?
□ Which have ownership fields (owner_id, user_id, organization_id)?
□ Which are accessed via ID in URLs or request bodies?
 
 What operations are exposed? 
 For each resource, map: 
 
 List endpoints - what data is returned? 
 Detail/retrieve endpoints - how is the object fetched? 
 Create endpoints - who sets the owner? 
 Update endpoints - can users modify others' data? 
 Delete endpoints - can users delete others' data? 
 Custom actions - what do they access? 
 
 
 Phase 3: Ask Questions and Investigate 
 For each endpoint that handles user data, ask: 
 The Core Question 
 "If I'm User A and I know the ID of User B's resource, can I access it?" 
 Trace the code to answer this: 
 1. Where does the resource ID enter the system?
 - URL path: /api/documents/{id}/
 - Query param: ?document_id=123
 - Request body: {"document_id": 123}

2. Where is that ID used to fetch data?
 - Find the ORM query or database call

3. Between (1) and (2), what checks exist?
 - Is the query scoped to current user?
 - Is there an explicit ownership check?
 - Is there a permission check on the object?
 - Does a base class or mixin enforce access?

4. If you can't find a check, is there one you missed?
 - Check parent classes
 - Check middleware
 - Check managers
 - Check decorators at URL level
 
 Follow-Up Questions 
 □ For list endpoints: Does the query filter to user's data, or return everything?

□ For create endpoints: Who sets the owner - the server or the request?

□ For bulk operations: Are they scoped to user's data?

□ For related resources: If I can access a document, can I access its comments?
 What if the document belongs to someone else?

□ For tenant/org resources: Can User in Org A access Org B's data by changing
 the org_id in the URL?
 
 
 Phase 4: Trace Specific Flows 
 Pick a concrete endpoint and trace it completely. 
 Example Investigation 
 Endpoint: GET /api/documents/{pk}/

1. Find the view handling this URL
 → DocumentViewSet.retrieve() in api/views.py

2. Check what DocumentViewSet inherits from
 → class DocumentViewSet(viewsets.ModelViewSet)
 → No custom base class with authorization

3. Check permission_classes
 → permission_classes = [IsAuthenticated]
 → Only checks login, not ownership

4. Check get_queryset()
 → def get_queryset(self):
 → return Document.objects.all()
 → Returns ALL documents!

5. Check for has_object_permission()
 → Not implemented

6. Check retrieve() method
 → Uses default, which calls get_object()
 → get_object() uses get_queryset(), which returns all

7. Conclusion: IDOR - Any authenticated user can access any document
 
 What to look for when tracing 
 Potential gap indicators (investigate further, don't auto-flag):
- get_queryset() returns .all() or filters without user
- Direct Model.objects.get(pk=pk) without ownership in query
- ID comes from request body for sensitive operations
- Permission class checks auth but not ownership
- No has_object_permission() and queryset isn't scoped

Likely safe patterns (but verify the implementation):
- get_queryset() filters by request.user or user's org
- Custom permission class with has_object_permission()
- Base class that enforces scoping
- Manager that auto-filters
 
 
 Phase 5: Report Findings 
 Only report issues you've confirmed through investigation. 
 Confidence Levels 
 
 
 
 Level 
 Meaning 
 Action 
 
 
 
 
 HIGH 
 Traced the flow, confirmed no check exists 
 Report with evidence 
 
 
 MEDIUM 
 Check may exist but couldn't confirm 
 Note for manual verification 
 
 
 LOW 
 Theoretical, likely mitigated 
 Do not report 
 
 
 
 Suggested Fixes Must Enforce, Not Document 
 Bad fix : Adding a comment saying "caller must validate permissions"
 Good fix : Adding code that actually validates permissions 
 A comment or docstring does not enforce authorization. Your suggested fix must include actual code that: 
 
 Validates the user has permission before proceeding 
 Raises an exception or returns an error if unauthorized 
 Makes unauthorized access impossible, not just discouraged 
 
 Example of a BAD fix suggestion: 
 def get_resource(resource_id):
 # IMPORTANT: Caller must ensure user has access to this resource
 return Resource.objects.get(pk=resource_id)
 
 Example of a GOOD fix suggestion: 
 def get_resource(resource_id, user):
 resource = Resource.objects.get(pk=resource_id)
 if resource.owner_id != user.id:
 raise PermissionDenied("Access denied")
 return resource
 
 If you can't determine the right enforcement mechanism, say so - but never suggest documentation as the fix. 
 Report Format 
 ## Access Control Review: [Component]

### Authorization Model
[Brief description of how this codebase handles authorization]

### Findings

#### [IDOR-001] [Title] (Severity: High/Medium)
- **Location**: `path/to/file.py:123`
- **Confidence**: High - confirmed through code tracing
- **The Question**: Can User A access User B's documents?
- **Investigation**:
 1. Traced GET /api/documents/{pk}/ to DocumentViewSet
 2. Checked get_queryset() - returns Document.objects.all()
 3. Checked permission_classes - only IsAuthenticated
 4. Checked for has_object_permission() - not implemented
 5. Verified no relevant middleware or base class checks
- **Evidence**: [Code snippet showing the gap]
- **Impact**: Any authenticated user can read any document by ID
- **Suggested Fix**: [Code that enforces authorization - NOT a comment]

### Needs Manual Verification
[Issues where authorization exists but couldn't confirm effectiveness]

### Areas Not Reviewed
[Endpoints or flows not covered in this review]
 
 
 Common Django Authorization Patterns 
 These are patterns you might find - not a checklist to match against. 
 Query Scoping 
 # Scoped to user
Document.objects.filter(owner=request.user)

# Scoped to organization
Document.objects.filter(organization=request.user.organization)

# Using a custom manager
Document.objects.for_user(request.user) # Investigate what this does
 
 Permission Enforcement 
 # DRF permission classes
permission_classes = [IsAuthenticated, IsOwner]

# Custom has_object_permission
def has_object_permission(self, request, view, obj):
 return obj.owner == request.user

# Django decorators
@permission_required('app.view_document')

# Manual checks
if document.owner != request.user:
 raise PermissionDenied()
 
 Ownership Assignment 
 # Server-side (safe)
def perform_create(self, serializer):
 serializer.save(owner=self.request.user)

# From request (investigate)
serializer.save(**request.data) # Does request.data include owner?
 
 
 Investigation Checklist 
 Use this to guide your review, not as a pass/fail checklist: 
 □ I understand how authorization is typically implemented in this codebase
□ I've identified the ownership model (user, org, tenant, etc.)
□ I've mapped the key endpoints that handle user data
□ For each sensitive endpoint, I've traced the flow and asked:
 - Where does the ID come from?
 - Where is data fetched?
 - What checks exist between input and data access?
□ I've verified my findings by checking parent classes and middleware
□ I've only reported issues I've confirmed through investigation

/sentry-django-perf-review
Source: ~/.claude/skills/sentry-django-perf-review/SKILL.md 
 
 name: django-perf-review
description: Django performance code review. Use when asked to "review Django performance", "find N+1 queries", "optimize Django", "check queryset performance", "database performance", "Django ORM issues", or audit Django code for performance problems.
allowed-tools: Read Grep Glob Bash Task
license: LICENSE 
 Django Performance Review 
 Review Django code for validated performance issues. Research the codebase to confirm issues before reporting. Report only what you can prove. 
 Review Approach 
 
 Research first - Trace data flow, check for existing optimizations, verify data volume 
 Validate before reporting - Pattern matching is not validation 
 Zero findings is acceptable - Don't manufacture issues to appear thorough 
 Severity must match impact - If you catch yourself writing "minor" in a CRITICAL finding, it's not critical. Downgrade or skip it. 
 
 Impact Categories 
 Issues are organized by impact. Focus on CRITICAL and HIGH - these cause real problems at scale. 
 
 
 
 Priority 
 Category 
 Impact 
 
 
 
 
 1 
 N+1 Queries 
 CRITICAL - Multiplies with data, causes timeouts 
 
 
 2 
 Unbounded Querysets 
 CRITICAL - Memory exhaustion, OOM kills 
 
 
 3 
 Missing Indexes 
 HIGH - Full table scans on large tables 
 
 
 4 
 Write Loops 
 HIGH - Lock contention, slow requests 
 
 
 5 
 Inefficient Patterns 
 LOW - Rarely worth reporting 
 
 
 
 
 Priority 1: N+1 Queries (CRITICAL) 
 Impact: Each N+1 adds O(n) database round trips. 100 rows = 100 extra queries. 10,000 rows = timeout. 
 Rule: Prefetch related data accessed in loops 
 Validate by tracing: View → Queryset → Template/Serializer → Loop access 
 # PROBLEM: N+1 - each iteration queries profile
def user_list(request):
 users = User.objects.all()
 return render(request, 'users.html', {'users': users})

# Template:
# {% for user in users %}
# {{ user.profile.bio }} ← triggers query per user
# {% endfor %}

# SOLUTION: Prefetch in view
def user_list(request):
 users = User.objects.select_related('profile')
 return render(request, 'users.html', {'users': users})
 
 Rule: Prefetch in serializers, not just views 
 DRF serializers accessing related fields cause N+1 if queryset isn't optimized. 
 # PROBLEM: SerializerMethodField queries per object
class UserSerializer(serializers.ModelSerializer):
 order_count = serializers.SerializerMethodField()

 def get_order_count(self, obj):
 return obj.orders.count() # ← query per user

# SOLUTION: Annotate in viewset, access in serializer
class UserViewSet(viewsets.ModelViewSet):
 def get_queryset(self):
 return User.objects.annotate(order_count=Count('orders'))

class UserSerializer(serializers.ModelSerializer):
 order_count = serializers.IntegerField(read_only=True)
 
 Rule: Model properties that query are dangerous in loops 
 # PROBLEM: Property triggers query when accessed
class User(models.Model):
 @property
 def recent_orders(self):
 return self.orders.filter(created__gte=last_week)[:5]

# Used in template loop = N+1

# SOLUTION: Use Prefetch with custom queryset, or annotate
 
 Validation Checklist for N+1 
 
 Traced data flow from view to template/serializer 
 Confirmed related field is accessed inside a loop 
 Searched codebase for existing select_related/prefetch_related 
 Verified table has significant row count (1000+) 
 Confirmed this is a hot path (not admin, not rare action) 
 
 
 Priority 2: Unbounded Querysets (CRITICAL) 
 Impact: Loading entire tables exhausts memory. Large tables cause OOM kills and worker restarts. 
 Rule: Always paginate list endpoints 
 # PROBLEM: No pagination - loads all rows
class UserListView(ListView):
 model = User
 template_name = 'users.html'

# SOLUTION: Add pagination
class UserListView(ListView):
 model = User
 template_name = 'users.html'
 paginate_by = 25
 
 Rule: Use iterator() for large batch processing 
 # PROBLEM: Loads all objects into memory at once
for user in User.objects.all():
 process(user)

# SOLUTION: Stream with iterator()
for user in User.objects.iterator(chunk_size=1000):
 process(user)
 
 Rule: Never call list() on unbounded querysets 
 # PROBLEM: Forces full evaluation into memory
all_users = list(User.objects.all())

# SOLUTION: Keep as queryset, slice if needed
users = User.objects.all()[:100]
 
 Validation Checklist for Unbounded Querysets 
 
 Table is large (10k+ rows) or will grow unbounded 
 No pagination class, paginate_by, or slicing 
 This runs on user-facing request (not background job with chunking) 
 
 
 Priority 3: Missing Indexes (HIGH) 
 Impact: Full table scans. Negligible on small tables, catastrophic on large ones. 
 Rule: Index fields used in WHERE clauses on large tables 
 # PROBLEM: Filtering on unindexed field
# User.objects.filter(email=email) # full scan if no index

class User(models.Model):
 email = models.EmailField() # ← no db_index

# SOLUTION: Add index
class User(models.Model):
 email = models.EmailField(db_index=True)
 
 Rule: Index fields used in ORDER BY on large tables 
 # PROBLEM: Sorting requires full scan without index
Order.objects.order_by('-created')

# SOLUTION: Index the sort field
class Order(models.Model):
 created = models.DateTimeField(db_index=True)
 
 Rule: Use composite indexes for common query patterns 
 class Order(models.Model):
 user = models.ForeignKey(User)
 status = models.CharField(max_length=20)
 created = models.DateTimeField()

 class Meta:
 indexes = [
 models.Index(fields=['user', 'status']), # for filter(user=x, status=y)
 models.Index(fields=['status', '-created']), # for filter(status=x).order_by('-created')
 ]
 
 Validation Checklist for Missing Indexes 
 
 Table has 10k+ rows 
 Field is used in filter() or order_by() on hot path 
 Checked model - no db_index=True or Meta.indexes entry 
 Not a foreign key (already indexed automatically) 
 
 
 Priority 4: Write Loops (HIGH) 
 Impact: N database writes instead of 1. Lock contention. Slow requests. 
 Rule: Use bulk_create instead of create() in loops 
 # PROBLEM: N inserts, N round trips
for item in items:
 Model.objects.create(name=item['name'])

# SOLUTION: Single bulk insert
Model.objects.bulk_create([
 Model(name=item['name']) for item in items
])
 
 Rule: Use update() or bulk_update instead of save() in loops 
 # PROBLEM: N updates
for obj in queryset:
 obj.status = 'done'
 obj.save()

# SOLUTION A: Single UPDATE statement (same value for all)
queryset.update(status='done')

# SOLUTION B: bulk_update (different values)
for obj in objects:
 obj.status = compute_status(obj)
Model.objects.bulk_update(objects, ['status'], batch_size=500)
 
 Rule: Use delete() on queryset, not in loops 
 # PROBLEM: N deletes
for obj in queryset:
 obj.delete()

# SOLUTION: Single DELETE
queryset.delete()
 
 Validation Checklist for Write Loops 
 
 Loop iterates over 100+ items (or unbounded) 
 Each iteration calls create(), save(), or delete() 
 This runs on user-facing request (not one-time migration script) 
 
 
 Priority 5: Inefficient Patterns (LOW) 
 Rarely worth reporting. Include only as minor notes if you're already reporting real issues. 
 Pattern: count() vs exists() 
 # Slightly suboptimal
if queryset.count() > 0:
 do_thing()

# Marginally better
if queryset.exists():
 do_thing()
 
 Usually skip - difference is <1ms in most cases. 
 Pattern: len(queryset) vs count() 
 # Fetches all rows to count
if len(queryset) > 0: # bad if queryset not yet evaluated

# Single COUNT query
if queryset.count() > 0:
 
 Only flag if queryset is large and not already evaluated. 
 Pattern: get() in small loops 
 # N queries, but if N is small (< 20), often fine
for id in ids:
 obj = Model.objects.get(id=id)
 
 Only flag if loop is large or this is in a very hot path. 
 
 Validation Requirements 
 Before reporting ANY issue: 
 
 Trace the data flow - Follow queryset from creation to consumption 
 Search for existing optimizations - Grep for select_related, prefetch_related, pagination 
 Verify data volume - Check if table is actually large 
 Confirm hot path - Trace call sites, verify this runs frequently 
 Rule out mitigations - Check for caching, rate limiting 
 
 If you cannot validate all steps, do not report. 
 
 Output Format 
 ## Django Performance Review: [File/Component Name]

### Summary
Validated issues: X (Y Critical, Z High)

### Findings

#### [PERF-001] N+1 Query in UserListView (CRITICAL)
**Location:** `views.py:45`

**Issue:** Related field `profile` accessed in template loop without prefetch.

**Validation:**
- Traced: UserListView → users queryset → user_list.html → `{{ user.profile.bio }}` in loop
- Searched codebase: no select_related('profile') found
- User table: 50k+ rows (verified in admin)
- Hot path: linked from homepage navigation

**Evidence:**
```python
def get_queryset(self):
 return User.objects.filter(active=True) # no select_related
 
 Fix: 
 def get_queryset(self):
 return User.objects.filter(active=True).select_related('profile')
 
 
If no issues found: "No performance issues identified after reviewing [files] and validating [what you checked]."

**Before submitting, sanity check each finding:**
- Does the severity match the actual impact? ("Minor inefficiency" ≠ CRITICAL)
- Is this a real performance issue or just a style preference?
- Would fixing this measurably improve performance?

If the answer to any is "no" - remove the finding.

---

## What NOT to Report

- Test files
- Admin-only views
- Management commands
- Migration files
- One-time scripts
- Code behind disabled feature flags
- Tables with <1000 rows that won't grow
- Patterns in cold paths (rarely executed code)
- Micro-optimizations (exists vs count, only/defer without evidence)

### False Positives to Avoid

**Queryset variable assignment is not an issue:**
```python
# This is FINE - no performance difference
projects_qs = Project.objects.filter(org=org)
projects = list(projects_qs)

# vs this - identical performance
projects = list(Project.objects.filter(org=org))
 
 Querysets are lazy. Assigning to a variable doesn't execute anything. 
 Single query patterns are not N+1: 
 # This is ONE query, not N+1
projects = list(Project.objects.filter(org=org))
 
 N+1 requires a loop that triggers additional queries. A single list() call is fine. 
 Missing select_related on single object fetch is not N+1: 
 # This is 2 queries, not N+1 - report as LOW at most
state = AutofixState.objects.filter(pr_id=pr_id).first()
project_id = state.request.project_id # second query
 
 N+1 requires a loop. A single object doing 2 queries instead of 1 can be reported as LOW if relevant, but never as CRITICAL/HIGH. 
 Style preferences are not performance issues: 
If your only suggestion is "combine these two lines" or "rename this variable" - that's style, not performance. Don't report it.

/sentry-doc-coauthoring
Source: ~/.claude/skills/sentry-doc-coauthoring/SKILL.md 
 
 name: doc-coauthoring
description: Guide users through a structured workflow for co-authoring documentation. Use when user wants to write documentation, proposals, technical specs, decision docs, or similar structured content. This workflow helps users efficiently transfer context, refine content through iteration, and verify the doc works for readers. Trigger when user mentions writing docs, creating proposals, drafting specs, or similar documentation tasks. 
 Doc Co-Authoring Workflow 
 This skill provides a structured workflow for guiding users through collaborative document creation. Act as an active guide, walking users through three stages: Context Gathering, Refinement & Structure, and Reader Testing. 
 When to Offer This Workflow 
 Trigger conditions: 
 
 User mentions writing documentation: "write a doc", "draft a proposal", "create a spec", "write up" 
 User mentions specific doc types: "PRD", "design doc", "decision doc", "RFC" 
 User seems to be starting a substantial writing task 
 
 Initial offer: 
Offer the user a structured workflow for co-authoring the document. Explain the three stages: 
 
 Context Gathering : User provides all relevant context while Claude asks clarifying questions 
 Refinement & Structure : Iteratively build each section through brainstorming and editing 
 Reader Testing : Test the doc with a fresh Claude (no context) to catch blind spots before others read it 
 
 Explain that this approach helps ensure the doc works well when others read it (including when they paste it into Claude). Ask if they want to try this workflow or prefer to work freeform. 
 If user declines, work freeform. If user accepts, proceed to Stage 1. 
 Stage 1: Context Gathering 
 Goal: Close the gap between what the user knows and what Claude knows, enabling smart guidance later. 
 Initial Questions 
 Start by asking the user for meta-context about the document: 
 
 What type of document is this? (e.g., technical spec, decision doc, proposal) 
 Who's the primary audience? 
 What's the desired impact when someone reads this? 
 Is there a template or specific format to follow? 
 Any other constraints or context to know? 
 
 Inform them they can answer in shorthand or dump information however works best for them. 
 If user provides a template or mentions a doc type: 
 
 Ask if they have a template document to share 
 If they provide a link to a shared document, use the appropriate integration to fetch it 
 If they provide a file, read it 
 
 If user mentions editing an existing shared document: 
 
 Use the appropriate integration to read the current state 
 Check for images without alt-text 
 If images exist without alt-text, explain that when others use Claude to understand the doc, Claude won't be able to see them. Ask if they want alt-text generated. If so, request they paste each image into chat for descriptive alt-text generation. 
 
 Info Dumping 
 Once initial questions are answered, encourage the user to dump all the context they have. Request information such as: 
 
 Background on the project/problem 
 Related team discussions or shared documents 
 Why alternative solutions aren't being used 
 Organizational context (team dynamics, past incidents, politics) 
 Timeline pressures or constraints 
 Technical architecture or dependencies 
 Stakeholder concerns 
 
 Advise them not to worry about organizing it - just get it all out. Offer multiple ways to provide context: 
 
 Info dump stream-of-consciousness 
 Point to team channels or threads to read 
 Link to shared documents 
 
 If integrations are available (e.g., Slack, Teams, Google Drive, SharePoint, or other MCP servers), mention that these can be used to pull in context directly. 
 If no integrations are detected and in Claude.ai or Claude app: Suggest they can enable connectors in their Claude settings to allow pulling context from messaging apps and document storage directly. 
 Inform them clarifying questions will be asked once they've done their initial dump. 
 During context gathering: 
 
 
 If user mentions team channels or shared documents: 
 
 If integrations available: Inform them the content will be read now, then use the appropriate integration 
 If integrations not available: Explain lack of access. Suggest they enable connectors in Claude settings, or paste the relevant content directly. 
 
 
 
 If user mentions entities/projects that are unknown: 
 
 Ask if connected tools should be searched to learn more 
 Wait for user confirmation before searching 
 
 
 
 As user provides context, track what's being learned and what's still unclear 
 
 
 Asking clarifying questions: 
 When user signals they've done their initial dump (or after substantial context provided), ask clarifying questions to ensure understanding: 
 Generate 5-10 numbered questions based on gaps in the context. 
 Inform them they can use shorthand to answer (e.g., "1: yes, 2: see #channel, 3: no because backwards compat"), link to more docs, point to channels to read, or just keep info-dumping. Whatever's most efficient for them. 
 Exit condition: 
Sufficient context has been gathered when questions show understanding - when edge cases and trade-offs can be asked about without needing basics explained. 
 Transition: 
Ask if there's any more context they want to provide at this stage, or if it's time to move on to drafting the document. 
 If user wants to add more, let them. When ready, proceed to Stage 2. 
 Stage 2: Refinement & Structure 
 Goal: Build the document section by section through brainstorming, curation, and iterative refinement. 
 Instructions to user: 
Explain that the document will be built section by section. For each section: 
 
 Clarifying questions will be asked about what to include 
 5-20 options will be brainstormed 
 User will indicate what to keep/remove/combine 
 The section will be drafted 
 It will be refined through surgical edits 
 
 Start with whichever section has the most unknowns (usually the core decision/proposal), then work through the rest. 
 Section ordering: 
 If the document structure is clear:
Ask which section they'd like to start with. 
 Suggest starting with whichever section has the most unknowns. For decision docs, that's usually the core proposal. For specs, it's typically the technical approach. Summary sections are best left for last. 
 If user doesn't know what sections they need:
Based on the type of document and template, suggest 3-5 sections appropriate for the doc type. 
 Ask if this structure works, or if they want to adjust it. 
 Once structure is agreed: 
 Create the initial document structure with placeholder text for all sections. 
 If access to artifacts is available: 
Use create_file to create an artifact. This gives both Claude and the user a scaffold to work from. 
 Inform them that the initial structure with placeholders for all sections will be created. 
 Create artifact with all section headers and brief placeholder text like "[To be written]" or "[Content here]". 
 Provide the scaffold link and indicate it's time to fill in each section. 
 If no access to artifacts: 
Create a markdown file in the working directory. Name it appropriately (e.g., decision-doc.md , technical-spec.md ). 
 Inform them that the initial structure with placeholders for all sections will be created. 
 Create file with all section headers and placeholder text. 
 Confirm the filename has been created and indicate it's time to fill in each section. 
 For each section: 
 Step 1: Clarifying Questions 
 Announce work will begin on the [SECTION NAME] section. Ask 5-10 clarifying questions about what should be included: 
 Generate 5-10 specific questions based on context and section purpose. 
 Inform them they can answer in shorthand or just indicate what's important to cover. 
 Step 2: Brainstorming 
 For the [SECTION NAME] section, brainstorm [5-20] things that might be included, depending on the section's complexity. Look for: 
 
 Context shared that might have been forgotten 
 Angles or considerations not yet mentioned 
 
 Generate 5-20 numbered options based on section complexity. At the end, offer to brainstorm more if they want additional options. 
 Step 3: Curation 
 Ask which points should be kept, removed, or combined. Request brief justifications to help learn priorities for the next sections. 
 Provide examples: 
 
 "Keep 1,4,7,9" 
 "Remove 3 (duplicates 1)" 
 "Remove 6 (audience already knows this)" 
 "Combine 11 and 12" 
 
 If user gives freeform feedback (e.g., "looks good" or "I like most of it but...") instead of numbered selections, extract their preferences and proceed. Parse what they want kept/removed/changed and apply it. 
 Step 4: Gap Check 
 Based on what they've selected, ask if there's anything important missing for the [SECTION NAME] section. 
 Step 5: Drafting 
 Use str_replace to replace the placeholder text for this section with the actual drafted content. 
 Announce the [SECTION NAME] section will be drafted now based on what they've selected. 
 If using artifacts: 
After drafting, provide a link to the artifact. 
 Ask them to read through it and indicate what to change. Note that being specific helps learning for the next sections. 
 If using a file (no artifacts): 
After drafting, confirm completion. 
 Inform them the [SECTION NAME] section has been drafted in [filename]. Ask them to read through it and indicate what to change. Note that being specific helps learning for the next sections. 
 Key instruction for user (include when drafting the first section): 
Provide a note: Instead of editing the doc directly, ask them to indicate what to change. This helps learning of their style for future sections. For example: "Remove the X bullet - already covered by Y" or "Make the third paragraph more concise". 
 Step 6: Iterative Refinement 
 As user provides feedback: 
 
 Use str_replace to make edits (never reprint the whole doc) 
 If using artifacts: Provide link to artifact after each edit 
 If using files: Just confirm edits are complete 
 If user edits doc directly and asks to read it: mentally note the changes they made and keep them in mind for future sections (this shows their preferences) 
 
 Continue iterating until user is satisfied with the section. 
 Quality Checking 
 After 3 consecutive iterations with no substantial changes, ask if anything can be removed without losing important information. 
 When section is done, confirm [SECTION NAME] is complete. Ask if ready to move to the next section. 
 Repeat for all sections. 
 Near Completion 
 As approaching completion (80%+ of sections done), announce intention to re-read the entire document and check for: 
 
 Flow and consistency across sections 
 Redundancy or contradictions 
 Anything that feels like "slop" or generic filler 
 Whether every sentence carries weight 
 
 Read entire document and provide feedback. 
 When all sections are drafted and refined: 
Announce all sections are drafted. Indicate intention to review the complete document one more time. 
 Review for overall coherence, flow, completeness. 
 Provide any final suggestions. 
 Ask if ready to move to Reader Testing, or if they want to refine anything else. 
 Stage 3: Reader Testing 
 Goal: Test the document with a fresh Claude (no context bleed) to verify it works for readers. 
 Instructions to user: 
Explain that testing will now occur to see if the document actually works for readers. This catches blind spots - things that make sense to the authors but might confuse others. 
 Testing Approach 
 If access to sub-agents is available (e.g., in Claude Code): 
 Perform the testing directly without user involvement. 
 Step 1: Predict Reader Questions 
 Announce intention to predict what questions readers might ask when trying to discover this document. 
 Generate 5-10 questions that readers would realistically ask. 
 Step 2: Test with Sub-Agent 
 Announce that these questions will be tested with a fresh Claude instance (no context from this conversation). 
 For each question, invoke a sub-agent with just the document content and the question. 
 Summarize what Reader Claude got right/wrong for each question. 
 Step 3: Run Additional Checks 
 Announce additional checks will be performed. 
 Invoke sub-agent to check for ambiguity, false assumptions, contradictions. 
 Summarize any issues found. 
 Step 4: Report and Fix 
 If issues found:
Report that Reader Claude struggled with specific issues. 
 List the specific issues. 
 Indicate intention to fix these gaps. 
 Loop back to refinement for problematic sections. 
 
 If no access to sub-agents (e.g., claude.ai web interface): 
 The user will need to do the testing manually. 
 Step 1: Predict Reader Questions 
 Ask what questions people might ask when trying to discover this document. What would they type into Claude.ai? 
 Generate 5-10 questions that readers would realistically ask. 
 Step 2: Setup Testing 
 Provide testing instructions: 
 
 Open a fresh Claude conversation: https://claude.ai 
 Paste or share the document content (if using a shared doc platform with connectors enabled, provide the link) 
 Ask Reader Claude the generated questions 
 
 For each question, instruct Reader Claude to provide: 
 
 The answer 
 Whether anything was ambiguous or unclear 
 What knowledge/context the doc assumes is already known 
 
 Check if Reader Claude gives correct answers or misinterprets anything. 
 Step 3: Additional Checks 
 Also ask Reader Claude: 
 
 "What in this doc might be ambiguous or unclear to readers?" 
 "What knowledge or context does this doc assume readers already have?" 
 "Are there any internal contradictions or inconsistencies?" 
 
 Step 4: Iterate Based on Results 
 Ask what Reader Claude got wrong or struggled with. Indicate intention to fix those gaps. 
 Loop back to refinement for any problematic sections. 
 
 Exit Condition (Both Approaches) 
 When Reader Claude consistently answers questions correctly and doesn't surface new gaps or ambiguities, the doc is ready. 
 Final Review 
 When Reader Testing passes:
Announce the doc has passed Reader Claude testing. Before completion: 
 
 Recommend they do a final read-through themselves - they own this document and are responsible for its quality 
 Suggest double-checking any facts, links, or technical details 
 Ask them to verify it achieves the impact they wanted 
 
 Ask if they want one more review, or if the work is done. 
 If user wants final review, provide it. Otherwise: 
Announce document completion. Provide a few final tips: 
 
 Consider linking this conversation in an appendix so readers can see how the doc was developed 
 Use appendices to provide depth without bloating the main doc 
 Update the doc as feedback is received from real readers 
 
 Tips for Effective Guidance 
 Tone: 
 
 Be direct and procedural 
 Explain rationale briefly when it affects user behavior 
 Don't try to "sell" the approach - just execute it 
 
 Handling Deviations: 
 
 If user wants to skip a stage: Ask if they want to skip this and write freeform 
 If user seems frustrated: Acknowledge this is taking longer than expected. Suggest ways to move faster 
 Always give user agency to adjust the process 
 
 Context Management: 
 
 Throughout, if context is missing on something mentioned, proactively ask 
 Don't let gaps accumulate - address them as they come up 
 
 Artifact Management: 
 
 Use create_file for drafting full sections 
 Use str_replace for all edits 
 Provide artifact link after every change 
 Never use artifacts for brainstorming lists - that's just conversation 
 
 Quality over Speed: 
 
 Don't rush through stages 
 Each iteration should make meaningful improvements 
 The goal is a document that actually works for readers 
 
 Attribution 
 This skill was adapted from anthropics/skills .

/sentry-find-bugs
Source: ~/.claude/skills/sentry-find-bugs/SKILL.md 
 
 name: find-bugs
description: Find bugs, security vulnerabilities, and code quality issues in local branch changes. Use when asked to review changes, find bugs, security review, or audit code on the current branch. 
 Find Bugs 
 Review changes on this branch for bugs, security vulnerabilities, and code quality issues. 
 Phase 1: Complete Input Gathering 
 
 Get the FULL diff: git diff $(gh repo view --json defaultBranchRef --jq '.defaultBranchRef.name')...HEAD 
 If output is truncated, read each changed file individually until you have seen every changed line 
 List all files modified in this branch before proceeding 
 
 Phase 2: Attack Surface Mapping 
 For each changed file, identify and list: 
 
 All user inputs (request params, headers, body, URL components) 
 All database queries 
 All authentication/authorization checks 
 All session/state operations 
 All external calls 
 All cryptographic operations 
 
 Phase 3: Security Checklist (check EVERY item for EVERY file) 
 
 Injection : SQL, command, template, header injection 
 XSS : All outputs in templates properly escaped? 
 Authentication : Auth checks on all protected operations? 
 Authorization/IDOR : Access control verified, not just auth? 
 CSRF : State-changing operations protected? 
 Race conditions : TOCTOU in any read-then-write patterns? 
 Session : Fixation, expiration, secure flags? 
 Cryptography : Secure random, proper algorithms, no secrets in logs? 
 Information disclosure : Error messages, logs, timing attacks? 
 DoS : Unbounded operations, missing rate limits, resource exhaustion? 
 Business logic : Edge cases, state machine violations, numeric overflow? 
 
 Phase 4: Verification 
 For each potential issue: 
 
 Check if it's already handled elsewhere in the changed code 
 Search for existing tests covering the scenario 
 Read surrounding context to verify the issue is real 
 
 Phase 5: Pre-Conclusion Audit 
 Before finalizing, you MUST: 
 
 List every file you reviewed and confirm you read it completely 
 List every checklist item and note whether you found issues or confirmed it's clean 
 List any areas you could NOT fully verify and why 
 Only then provide your final findings 
 
 Output Format 
 Prioritize : security vulnerabilities > bugs > code quality 
 Skip : stylistic/formatting issues 
 For each issue: 
 
 File:Line - Brief description 
 Severity : Critical/High/Medium/Low 
 Problem : What's wrong 
 Evidence : Why this is real (not already fixed, no existing test, etc.) 
 Fix : Concrete suggestion 
 References : OWASP, RFCs, or other standards if applicable 
 
 If you find nothing significant, say so - don't invent issues. 
 Do not make changes - just report findings. I'll decide what to address.

/sentry-iterate-pr
Source: ~/.claude/skills/sentry-iterate-pr/SKILL.md 
 
 name: iterate-pr
description: Iterate on a PR until CI passes. Use when you need to fix CI failures, address review feedback, or continuously push fixes until all checks are green. Automates the feedback-fix-push-wait cycle. 
 Iterate on PR Until CI Passes 
 Continuously iterate on the current branch until all CI checks pass and review feedback is addressed. 
 Requires : GitHub CLI ( gh ) authenticated. 
 Important : All scripts must be run from the repository root directory (where .git is located), not from the skill directory. Use the full path to the script via ${CLAUDE_SKILL_ROOT} . 
 Bundled Scripts 
 scripts/fetch_pr_checks.py 
 Fetches CI check status and extracts failure snippets from logs. 
 uv run ${CLAUDE_SKILL_ROOT}/scripts/fetch_pr_checks.py [--pr NUMBER]
 
 Returns JSON: 
 {
 "pr": {"number": 123, "branch": "feat/foo"},
 "summary": {"total": 5, "passed": 3, "failed": 2, "pending": 0},
 "checks": [
 {"name": "tests", "status": "fail", "log_snippet": "...", "run_id": 123},
 {"name": "lint", "status": "pass"}
 ]
}
 
 scripts/fetch_pr_feedback.py 
 Fetches and categorizes PR review feedback using the LOGAF scale . 
 uv run ${CLAUDE_SKILL_ROOT}/scripts/fetch_pr_feedback.py [--pr NUMBER]
 
 Returns JSON with feedback categorized as: 
 
 high - Must address before merge ( h: , blocker, changes requested) 
 medium - Should address ( m: , standard feedback) 
 low - Optional ( l: , nit, style, suggestion) 
 bot - Automated comments (Codecov, Sentry, etc.) 
 resolved - Already resolved threads 
 
 Workflow 
 1. Identify PR 
 gh pr view --json number,url,headRefName
 
 Stop if no PR exists for the current branch. 
 2. Check CI Status 
 Run ${CLAUDE_SKILL_ROOT}/scripts/fetch_pr_checks.py to get structured failure data. 
 Wait if pending: If bot-related checks (sentry, codecov, cursor, bugbot, seer) are still running, wait before proceeding—they may post additional feedback. 
 3. Fix CI Failures 
 For each failure in the script output: 
 
 Read the log_snippet to understand the failure 
 Read the relevant code before making changes 
 Fix the issue with minimal, targeted changes 
 
 Do NOT assume what failed based on check name alone—always read the logs. 
 4. Gather Review Feedback 
 Run ${CLAUDE_SKILL_ROOT}/scripts/fetch_pr_feedback.py to get categorized feedback. 
 5. Handle Feedback by LOGAF Priority 
 Auto-fix (no prompt): 
 
 high - must address (blockers, security, changes requested) 
 medium - should address (standard feedback) 
 
 Prompt user for selection: 
 
 low - present numbered list and ask which to address: 
 
 Found 3 low-priority suggestions:
1. [l] "Consider renaming this variable" - @reviewer in api.py:42
2. [nit] "Could use a list comprehension" - @reviewer in utils.py:18
3. [style] "Add a docstring" - @reviewer in models.py:55

Which would you like to address? (e.g., "1,3" or "all" or "none")
 
 Skip silently: 
 
 resolved threads 
 bot comments (informational only) 
 
 6. Commit and Push 
 git add <files>
git commit -m "fix: <descriptive message>"
git push
 
 7. Wait for CI 
 gh pr checks --watch --interval 30
 
 8. Repeat 
 Return to step 2 if CI failed or new feedback appeared. 
 Exit Conditions 
 Success: All checks pass, no unaddressed high/medium feedback, user has decided on low-priority items. 
 Ask for help: Same failure after 3 attempts, feedback needs clarification, infrastructure issues. 
 Stop: No PR exists, branch needs rebase. 
 Fallback 
 If scripts fail, use gh CLI directly: 
 
 gh pr checks --json name,state,bucket,link 
 gh run view <run-id> --log-failed 
 gh api repos/{owner}/{repo}/pulls/{number}/comments

/sentry-security-review
Source: ~/.claude/skills/sentry-security-review/SKILL.md 
 
 name: security-review
description: Security code review for vulnerabilities. Use when asked to "security review", "find vulnerabilities", "check for security issues", "audit security", "OWASP review", or review code for injection, XSS, authentication, authorization, cryptography issues. Provides systematic review with confidence-based reporting.
allowed-tools: Read Grep Glob Bash Task
license: LICENSE 

 Security Review Skill 
 Identify exploitable security vulnerabilities in code. Report only HIGH CONFIDENCE findings—clear vulnerable patterns with attacker-controlled input. 
 Scope: Research vs. Reporting 
 CRITICAL DISTINCTION: 
 
 Report on : Only the specific file, diff, or code provided by the user 
 Research : The ENTIRE codebase to build confidence before reporting 
 
 Before flagging any issue, you MUST research the codebase to understand: 
 
 Where does this input actually come from? (Trace data flow) 
 Is there validation/sanitization elsewhere? 
 How is this configured? (Check settings, config files, middleware) 
 What framework protections exist? 
 
 Do NOT report issues based solely on pattern matching. Investigate first, then report only what you're confident is exploitable. 
 Confidence Levels 
 
 
 
 Level 
 Criteria 
 Action 
 
 
 
 
 HIGH 
 Vulnerable pattern + attacker-controlled input confirmed 
 Report with severity 
 
 
 MEDIUM 
 Vulnerable pattern, input source unclear 
 Note as "Needs verification" 
 
 
 LOW 
 Theoretical, best practice, defense-in-depth 
 Do not report 
 
 
 
 Do Not Flag 
 General Rules 
 
 Test files (unless explicitly reviewing test security) 
 Dead code, commented code, documentation strings 
 Patterns using constants or server-controlled configuration 
 Code paths that require prior authentication to reach (note the auth requirement instead) 
 
 Server-Controlled Values (NOT Attacker-Controlled) 
 These are configured by operators, not controlled by attackers: 
 
 
 
 Source 
 Example 
 Why It's Safe 
 
 
 
 
 Django settings 
 settings.API_URL , settings.ALLOWED_HOSTS 
 Set via config/env at deployment 
 
 
 Environment variables 
 os.environ.get('DATABASE_URL') 
 Deployment configuration 
 
 
 Config files 
 config.yaml , app.config['KEY'] 
 Server-side files 
 
 
 Framework constants 
 django.conf.settings.* 
 Not user-modifiable 
 
 
 Hardcoded values 
 BASE_URL = "https://api.internal" 
 Compile-time constants 
 
 
 
 SSRF Example - NOT a vulnerability: 
 # SAFE: URL comes from Django settings (server-controlled)
response = requests.get(f"{settings.SEER_AUTOFIX_URL}{path}")
 
 SSRF Example - IS a vulnerability: 
 # VULNERABLE: URL comes from request (attacker-controlled)
response = requests.get(request.GET.get('url'))
 
 Framework-Mitigated Patterns 
 Check language guides before flagging. Common false positives: 
 
 
 
 Pattern 
 Why It's Usually Safe 
 
 
 
 
 Django {{ variable }} 
 Auto-escaped by default 
 
 
 React {variable} 
 Auto-escaped by default 
 
 
 Vue {{ variable }} 
 Auto-escaped by default 
 
 
 User.objects.filter(id=input) 
 ORM parameterizes queries 
 
 
 cursor.execute("...%s", (input,)) 
 Parameterized query 
 
 
 innerHTML = "<b>Loading...</b>" 
 Constant string, no user input 
 
 
 
 Only flag these when: 
 
 Django: {{ var|safe }} , {% autoescape off %} , mark_safe(user_input) 
 React: dangerouslySetInnerHTML={{__html: userInput}} 
 Vue: v-html="userInput" 
 ORM: .raw() , .extra() , RawSQL() with string interpolation 
 
 Review Process 
 1. Detect Context 
 What type of code am I reviewing? 
 
 
 
 Code Type 
 Load These References 
 
 
 
 
 API endpoints, routes 
 authorization.md , authentication.md , injection.md 
 
 
 Frontend, templates 
 xss.md , csrf.md 
 
 
 File handling, uploads 
 file-security.md 
 
 
 Crypto, secrets, tokens 
 cryptography.md , data-protection.md 
 
 
 Data serialization 
 deserialization.md 
 
 
 External requests 
 ssrf.md 
 
 
 Business workflows 
 business-logic.md 
 
 
 GraphQL, REST design 
 api-security.md 
 
 
 Config, headers, CORS 
 misconfiguration.md 
 
 
 CI/CD, dependencies 
 supply-chain.md 
 
 
 Error handling 
 error-handling.md 
 
 
 Audit, logging 
 logging.md 
 
 
 
 2. Load Language Guide 
 Based on file extension or imports: 
 
 
 
 Indicators 
 Guide 
 
 
 
 
 .py , django , flask , fastapi 
 languages/python.md 
 
 
 .js , .ts , express , react , vue , next 
 languages/javascript.md 
 
 
 .go , go.mod 
 languages/go.md 
 
 
 .rs , Cargo.toml 
 languages/rust.md 
 
 
 .java , spring , @Controller 
 languages/java.md 
 
 
 
 3. Load Infrastructure Guide (if applicable) 
 
 
 
 File Type 
 Guide 
 
 
 
 
 Dockerfile , .dockerignore 
 infrastructure/docker.md 
 
 
 K8s manifests, Helm charts 
 infrastructure/kubernetes.md 
 
 
 .tf , Terraform 
 infrastructure/terraform.md 
 
 
 GitHub Actions, .gitlab-ci.yml 
 infrastructure/ci-cd.md 
 
 
 AWS/GCP/Azure configs, IAM 
 infrastructure/cloud.md 
 
 
 
 4. Research Before Flagging 
 For each potential issue, research the codebase to build confidence: 
 
 Where does this value actually come from? Trace the data flow. 
 Is it configured at deployment (settings, env vars) or from user input? 
 Is there validation, sanitization, or allowlisting elsewhere? 
 What framework protections apply? 
 
 Only report issues where you have HIGH confidence after understanding the broader context. 
 5. Verify Exploitability 
 For each potential finding, confirm: 
 Is the input attacker-controlled? 
 
 
 
 Attacker-Controlled (Investigate) 
 Server-Controlled (Usually Safe) 
 
 
 
 
 request.GET , request.POST , request.args 
 settings.X , app.config['X'] 
 
 
 request.json , request.data , request.body 
 os.environ.get('X') 
 
 
 request.headers (most headers) 
 Hardcoded constants 
 
 
 request.cookies (unsigned) 
 Internal service URLs from config 
 
 
 URL path segments: /users/<id>/ 
 Database content from admin/system 
 
 
 File uploads (content and names) 
 Signed session data 
 
 
 Database content from other users 
 Framework settings 
 
 
 WebSocket messages 
 
 
 
 
 Does the framework mitigate this? 
 
 Check language guide for auto-escaping, parameterization 
 Check for middleware/decorators that sanitize 
 
 Is there validation upstream? 
 
 Input validation before this code 
 Sanitization libraries (DOMPurify, bleach, etc.) 
 
 6. Report HIGH Confidence Only 
 Skip theoretical issues. Report only what you've confirmed is exploitable after research. 
 
 Severity Classification 
 
 
 
 Severity 
 Impact 
 Examples 
 
 
 
 
 Critical 
 Direct exploit, severe impact, no auth required 
 RCE, SQL injection to data, auth bypass, hardcoded secrets 
 
 
 High 
 Exploitable with conditions, significant impact 
 Stored XSS, SSRF to metadata, IDOR to sensitive data 
 
 
 Medium 
 Specific conditions required, moderate impact 
 Reflected XSS, CSRF on state-changing actions, path traversal 
 
 
 Low 
 Defense-in-depth, minimal direct impact 
 Missing headers, verbose errors, weak algorithms in non-critical context 
 
 
 
 
 Quick Patterns Reference 
 Always Flag (Critical) 
 eval(user_input) # Any language
exec(user_input) # Any language
pickle.loads(user_data) # Python
yaml.load(user_data) # Python (not safe_load)
unserialize($user_data) # PHP
deserialize(user_data) # Java ObjectInputStream
shell=True + user_input # Python subprocess
child_process.exec(user) # Node.js
 
 Always Flag (High) 
 innerHTML = userInput # DOM XSS
dangerouslySetInnerHTML={user} # React XSS
v-html="userInput" # Vue XSS
f"SELECT * FROM x WHERE {user}" # SQL injection
`SELECT * FROM x WHERE ${user}` # SQL injection
os.system(f"cmd {user_input}") # Command injection
 
 Always Flag (Secrets) 
 password = "hardcoded"
api_key = "sk-..."
AWS_SECRET_ACCESS_KEY = "..."
private_key = "-----BEGIN"
 
 Check Context First (MUST Investigate Before Flagging) 
 # SSRF - ONLY if URL is from user input, NOT from settings/config
requests.get(request.GET['url']) # FLAG: User-controlled URL
requests.get(settings.API_URL) # SAFE: Server-controlled config
requests.get(f"{settings.BASE}/{x}") # CHECK: Is 'x' user input?

# Path traversal - ONLY if path is from user input
open(request.GET['file']) # FLAG: User-controlled path
open(settings.LOG_PATH) # SAFE: Server-controlled config
open(f"{BASE_DIR}/{filename}") # CHECK: Is 'filename' user input?

# Open redirect - ONLY if URL is from user input
redirect(request.GET['next']) # FLAG: User-controlled redirect
redirect(settings.LOGIN_URL) # SAFE: Server-controlled config

# Weak crypto - ONLY if used for security purposes
hashlib.md5(file_content) # SAFE: File checksums, caching
hashlib.md5(password) # FLAG: Password hashing
random.random() # SAFE: Non-security uses (UI, sampling)
random.random() for token # FLAG: Security tokens need secrets module
 
 
 Output Format 
 ## Security Review: [File/Component Name]

### Summary
- **Findings**: X (Y Critical, Z High, ...)
- **Risk Level**: Critical/High/Medium/Low
- **Confidence**: High/Mixed

### Findings

#### [VULN-001] [Vulnerability Type] (Severity)
- **Location**: `file.py:123`
- **Confidence**: High
- **Issue**: [What the vulnerability is]
- **Impact**: [What an attacker could do]
- **Evidence**:
 ```python
 [Vulnerable code snippet]
 
 
 Fix : [How to remediate] 
 
 Needs Verification 
 [VERIFY-001] [Potential Issue] 
 
 Location : file.py:456 
 Question : [What needs to be verified] 
 
 
If no vulnerabilities found, state: "No high-confidence vulnerabilities identified."

---

## Reference Files

### Core Vulnerabilities (`references/`)
| File | Covers |
|------|--------|
| `injection.md` | SQL, NoSQL, OS command, LDAP, template injection |
| `xss.md` | Reflected, stored, DOM-based XSS |
| `authorization.md` | Authorization, IDOR, privilege escalation |
| `authentication.md` | Sessions, credentials, password storage |
| `cryptography.md` | Algorithms, key management, randomness |
| `deserialization.md` | Pickle, YAML, Java, PHP deserialization |
| `file-security.md` | Path traversal, uploads, XXE |
| `ssrf.md` | Server-side request forgery |
| `csrf.md` | Cross-site request forgery |
| `data-protection.md` | Secrets exposure, PII, logging |
| `api-security.md` | REST, GraphQL, mass assignment |
| `business-logic.md` | Race conditions, workflow bypass |
| `modern-threats.md` | Prototype pollution, LLM injection, WebSocket |
| `misconfiguration.md` | Headers, CORS, debug mode, defaults |
| `error-handling.md` | Fail-open, information disclosure |
| `supply-chain.md` | Dependencies, build security |
| `logging.md` | Audit failures, log injection |

### Language Guides (`languages/`)
- `python.md` - Django, Flask, FastAPI patterns
- `javascript.md` - Node, Express, React, Vue, Next.js
- `go.md` - Go-specific security patterns
- `rust.md` - Rust unsafe blocks, FFI security
- `java.md` - Spring, Java EE patterns

### Infrastructure (`infrastructure/`)
- `docker.md` - Container security
- `kubernetes.md` - K8s RBAC, secrets, policies
- `terraform.md` - IaC security
- `ci-cd.md` - Pipeline security
- `cloud.md` - AWS/GCP/Azure security

/sentry-skill-creator
Source: ~/.claude/skills/sentry-skill-creator/SKILL.md 
 
 name: skill-creator
description: Create new agent skills following the Agent Skills specification. Use when asked to "create a skill", "add a new skill", "write a skill", "make a skill", "build a skill", or scaffold a new skill with SKILL.md. Guides through requirements, writing, registration, and verification. 

 Create a New Skill 
 Guide the user through creating a new agent skill following the Agent Skills specification . Follow each step in order. 
 Step 1: Understand the Skill 
 Gather requirements before writing anything. 
 Ask the user: 
 
 What should this skill do? (one sentence) 
 When should an agent use it? (trigger phrases) 
 What tools does the skill need? (Read, Grep, Glob, Bash, Task, WebFetch, etc.) 
 Where should the skill live? (which plugin or directory) 
 
 Determine the skill name: 
 
 Lowercase alphanumeric with hyphens, 1-64 characters 
 Descriptive and unique among existing skills 
 Check the target skills directory to avoid name collisions 
 
 Choose a complexity tier: 
 
 
 
 Tier 
 Structure 
 Use When 
 
 
 
 
 Simple 
 SKILL.md only 
 Self-contained instructions under ~200 lines 
 
 
 With references 
 SKILL.md + references/ 
 Domain knowledge that agents load conditionally 
 
 
 With scripts 
 SKILL.md + scripts/ 
 Workflow automation needing Python scripts 
 
 
 Full 
 All of the above 
 Complex skills with automation and domain knowledge 
 
 
 
 Read ${CLAUDE_SKILL_ROOT}/references/design-principles.md for guidance on keeping skills focused and concise. 
 Step 2: Study Existing Skills 
 Before writing, study 1-2 existing skills that match the chosen tier. Look for skills in the target repository or plugin to understand local conventions. 
 Read ${CLAUDE_SKILL_ROOT}/references/skill-patterns.md for concrete examples of each tier. 
 Also read CLAUDE.md (or AGENTS.md ) at the repository root for repo-specific conventions that the skill should follow. 
 Step 3: Write the SKILL.md 
 Create <skill-directory>/<name>/SKILL.md . 
 Frontmatter 
 The YAML frontmatter must be the first thing in the file. No comments or blank lines before --- . 
 ---
name: <skill-name>
description: <what it does>. Use when <trigger phrases>. <key capabilities>.
---
 
 Required fields: 
 
 name — must match the directory name exactly 
 description — up to 1024 chars; include trigger keywords that help agents match user intent 
 
 Optional fields: 
 
 model — override model ( sonnet , opus , haiku ); omit to use the user's default 
 allowed-tools — space-delimited list (e.g., Read Grep Glob Bash Task ); omit to allow all tools 
 license — license name or path (add when vendoring external content) 
 
 Body Guidelines 
 Write the body in imperative voice — these are instructions, not documentation. 
 
 
 
 Do 
 Don't 
 
 
 
 
 "Read the file and extract..." 
 "This skill reads the file and extracts..." 
 
 
 "Report only HIGH confidence findings" 
 "The agent should report only HIGH confidence findings" 
 
 
 "Ask the user which option to use" 
 "You may want to ask the user..." 
 
 
 
 Structure: 
 
 Start with a one-line summary of what the skill does 
 Organize steps with ## Step N: Title headings 
 Use tables for decision logic and mappings 
 Include concrete examples of expected output 
 End with validation criteria or exit conditions 
 
 Size limits: 
 
 Keep SKILL.md under 500 lines 
 If approaching the limit, move reference material to references/ files 
 Load reference files conditionally based on context (not all at once) 
 
 Attribution 
 If the skill is based on or adapted from external sources, add an HTML comment after the frontmatter closing --- : 
 ---
name: example
description: ...
---

<!--
Based on [Original Name] by [Author/Org]:
https://github.com/example/original-source
-->
 
 Step 4: Create Supporting Files 
 References ( references/ ) 
 Use for domain knowledge the agent loads conditionally. 
 <name>/
├── SKILL.md
└── references/
 ├── topic-a.md
 └── topic-b.md
 
 Reference from SKILL.md with: 
 Read `${CLAUDE_SKILL_ROOT}/references/topic-a.md` for details on [topic].
 
 Keep each reference file focused on one topic. Use markdown with tables and code blocks. 
 Scripts ( scripts/ ) 
 Use for workflow automation that benefits from structured Python. 
 <name>/
├── SKILL.md
└── scripts/
 └── do_thing.py
 
 Script requirements: 
 
 Always use uv run to execute: uv run ${CLAUDE_SKILL_ROOT}/scripts/do_thing.py 
 Add PEP 723 inline metadata for dependencies: 
 
 # /// script
# requires-python = ">=3.12"
# dependencies = ["requests"]
# ///
 
 
 Output structured JSON for agent consumption 
 Run from the repository root , not the skill directory 
 Document the script's interface in SKILL.md (arguments, output format) 
 
 Assets ( assets/ ) 
 Use for static files the skill references (templates, configs, etc.). 
 LICENSE 
 Include a LICENSE file in the skill directory when vendoring content with specific licensing requirements. 
 Step 5: Register the Skill 
 Registration steps vary by repository. Check the repository's CLAUDE.md or README.md for specific instructions. 
 
 Verify directory-name match — confirm the directory name matches the name field in SKILL.md frontmatter exactly 
 Update documentation — add the skill to any skills index or table in README.md 
 Update permissions — if the repo has .claude/settings.json , add Skill(<plugin>:<name>) to the permissions.allow array 
 Check CLAUDE.md — read the repository's CLAUDE.md for any additional registration steps specific to that project 
 
 Step 6: Verify 
 Run through this checklist before finishing: 
 Frontmatter 
 
 name matches directory name 
 description is under 1024 characters 
 description includes trigger keywords 
 No content before the opening --- 
 
 Content 
 
 SKILL.md is under 500 lines 
 Written in imperative voice 
 Steps are numbered and clear 
 Examples of expected output included 
 Reference files loaded conditionally (not unconditionally) 
 
 Registration 
 
 Directory name matches frontmatter name 
 Skill added to repo documentation (README or equivalent) 
 Permissions updated (if applicable) 
 Any repo-specific registration steps completed (check CLAUDE.md) 
 
 Scripts (if applicable) 
 
 Uses uv run ${CLAUDE_SKILL_ROOT}/scripts/... 
 Has PEP 723 inline metadata 
 Outputs structured JSON 
 Documented in SKILL.md 
 
 Report any issues found and fix them before completing.

/sentry-skill-scanner
Source: ~/.claude/skills/sentry-skill-scanner/SKILL.md 
 
 name: skill-scanner
description: Scan agent skills for security issues. Use when asked to "scan a skill",
"audit a skill", "review skill security", "check skill for injection", "validate SKILL.md",
or assess whether an agent skill is safe to install. Checks for prompt injection,
malicious scripts, excessive permissions, secret exposure, and supply chain risks.
allowed-tools: Read Grep Glob Bash 
 Skill Security Scanner 
 Scan agent skills for security issues before adoption. Detects prompt injection, malicious code, excessive permissions, secret exposure, and supply chain risks. 
 Important : Run all scripts from the repository root using the full path via ${CLAUDE_SKILL_ROOT} . 
 Bundled Script 
 scripts/scan_skill.py 
 Static analysis scanner that detects deterministic patterns. Outputs structured JSON. 
 uv run ${CLAUDE_SKILL_ROOT}/scripts/scan_skill.py <skill-directory>
 
 Returns JSON with findings, URLs, structure info, and severity counts. The script catches patterns mechanically — your job is to evaluate intent and filter false positives. 
 Workflow 
 Phase 1: Input & Discovery 
 Determine the scan target: 
 
 If the user provides a skill directory path, use it directly 
 If the user names a skill, look for it under plugins/*/skills/<name>/ or .claude/skills/<name>/ 
 If the user says "scan all skills", discover all */SKILL.md files and scan each 
 
 Validate the target contains a SKILL.md file. List the skill structure: 
 ls -la <skill-directory>/
ls <skill-directory>/references/ 2>/dev/null
ls <skill-directory>/scripts/ 2>/dev/null
 
 Phase 2: Automated Static Scan 
 Run the bundled scanner: 
 uv run ${CLAUDE_SKILL_ROOT}/scripts/scan_skill.py <skill-directory>
 
 Parse the JSON output. The script produces findings with severity levels, URL analysis, and structure information. Use these as leads for deeper analysis. 
 Fallback : If the script fails, proceed with manual analysis using Grep patterns from the reference files. 
 Phase 3: Frontmatter Validation 
 Read the SKILL.md and check: 
 
 Required fields : name and description must be present 
 Name consistency : name field should match the directory name 
 Tool assessment : Review allowed-tools — is Bash justified? Are tools unrestricted ( * )? 
 Model override : Is a specific model forced? Why? 
 Description quality : Does the description accurately represent what the skill does? 
 
 Phase 4: Prompt Injection Analysis 
 Load ${CLAUDE_SKILL_ROOT}/references/prompt-injection-patterns.md for context. 
 Review scanner findings in the "Prompt Injection" category. For each finding: 
 
 Read the surrounding context in the file 
 Determine if the pattern is performing injection (malicious) or discussing/detecting injection (legitimate) 
 Skills about security, testing, or education commonly reference injection patterns — this is expected 
 
 Critical distinction : A security review skill that lists injection patterns in its references is documenting threats, not attacking. Only flag patterns that would execute against the agent running the skill. 
 Phase 5: Behavioral Analysis 
 This phase is agent-only — no pattern matching. Read the full SKILL.md instructions and evaluate: 
 Description vs. instructions alignment : 
 
 Does the description match what the instructions actually tell the agent to do? 
 A skill described as "code formatter" that instructs the agent to read ~/.ssh is misaligned 
 
 Config/memory poisoning : 
 
 Instructions to modify CLAUDE.md , MEMORY.md , settings.json , .mcp.json , or hook configurations 
 Instructions to add itself to allowlists or auto-approve permissions 
 Writing to ~/.claude/ or any agent configuration directory 
 
 Scope creep : 
 
 Instructions that exceed the skill's stated purpose 
 Unnecessary data gathering (reading files unrelated to the skill's function) 
 Instructions to install other skills, plugins, or dependencies not mentioned in the description 
 
 Information gathering : 
 
 Reading environment variables beyond what's needed 
 Listing directory contents outside the skill's scope 
 Accessing git history, credentials, or user data unnecessarily 
 
 Phase 6: Script Analysis 
 If the skill has a scripts/ directory: 
 
 Load ${CLAUDE_SKILL_ROOT}/references/dangerous-code-patterns.md for context 
 Read each script file fully (do not skip any) 
 Check scanner findings in the "Malicious Code" category 
 For each finding, evaluate:
 
 Data exfiltration : Does the script send data to external URLs? What data? 
 Reverse shells : Socket connections with redirected I/O 
 Credential theft : Reading SSH keys, .env files, tokens from environment 
 Dangerous execution : eval/exec with dynamic input, shell=True with interpolation 
 Config modification : Writing to agent settings, shell configs, git hooks 
 
 
 Check PEP 723 dependencies — are they legitimate, well-known packages? 
 Verify the script's behavior matches the SKILL.md description of what it does 
 
 Legitimate patterns : gh CLI calls, git commands, reading project files, JSON output to stdout are normal for skill scripts. 
 Phase 7: Supply Chain Assessment 
 Review URLs from the scanner output and any additional URLs found in scripts: 
 
 Trusted domains : GitHub, PyPI, official docs — normal 
 Untrusted domains : Unknown domains, personal sites, URL shorteners — flag for review 
 Remote instruction loading : Any URL that fetches content to be executed or interpreted as instructions is high risk 
 Dependency downloads : Scripts that download and execute binaries or code at runtime 
 Unverifiable sources : References to packages or tools not on standard registries 
 
 Phase 8: Permission Analysis 
 Load ${CLAUDE_SKILL_ROOT}/references/permission-analysis.md for the tool risk matrix. 
 Evaluate: 
 
 Least privilege : Are all granted tools actually used in the skill instructions? 
 Tool justification : Does the skill body reference operations that require each tool? 
 Risk level : Rate the overall permission profile using the tier system from the reference 
 
 Example assessments: 
 
 Read Grep Glob — Low risk, read-only analysis skill 
 Read Grep Glob Bash — Medium risk, needs Bash justification (e.g., running bundled scripts) 
 Read Grep Glob Bash Write Edit WebFetch Task — High risk, near-full access 
 
 Confidence Levels 
 
 
 
 Level 
 Criteria 
 Action 
 
 
 
 
 HIGH 
 Pattern confirmed + malicious intent evident 
 Report with severity 
 
 
 MEDIUM 
 Suspicious pattern, intent unclear 
 Note as "Needs verification" 
 
 
 LOW 
 Theoretical, best practice only 
 Do not report 
 
 
 
 False positive awareness is critical. The biggest risk is flagging legitimate security skills as malicious because they reference attack patterns. Always evaluate intent before reporting. 
 Output Format 
 ## Skill Security Scan: [Skill Name]

### Summary
- **Findings**: X (Y Critical, Z High, ...)
- **Risk Level**: Critical / High / Medium / Low / Clean
- **Skill Structure**: SKILL.md only / +references / +scripts / full

### Findings

#### [SKILL-SEC-001] [Finding Type] (Severity)
- **Location**: `SKILL.md:42` or `scripts/tool.py:15`
- **Confidence**: High
- **Category**: Prompt Injection / Malicious Code / Excessive Permissions / Secret Exposure / Supply Chain / Validation
- **Issue**: [What was found]
- **Evidence**: [code snippet]
- **Risk**: [What could happen]
- **Remediation**: [How to fix]

### Needs Verification
[Medium-confidence items needing human review]

### Assessment
[Safe to install / Install with caution / Do not install]
[Brief justification for the assessment]
 
 Risk level determination : 
 
 Critical : Any high-confidence critical finding (prompt injection, credential theft, data exfiltration) 
 High : High-confidence high-severity findings or multiple medium findings 
 Medium : Medium-confidence findings or minor permission concerns 
 Low : Only best-practice suggestions 
 Clean : No findings after thorough analysis 
 
 Reference Files 
 
 
 
 File 
 Purpose 
 
 
 
 
 references/prompt-injection-patterns.md 
 Injection patterns, jailbreaks, obfuscation techniques, false positive guide 
 
 
 references/dangerous-code-patterns.md 
 Script security patterns: exfiltration, shells, credential theft, eval/exec 
 
 
 references/permission-analysis.md 
 Tool risk tiers, least privilege methodology, common skill permission profiles