Skills in the pack
Skills are short instructions your coding agent loads when they fit the task. The pack puts them in .agents/skills for Codex, OpenCode and Cursor and in .claude/skills for Claude Code. Every one was read in full before it went in, is pinned to an exact version, and changes only in a reviewed prd-help release. Nothing is downloaded while your agent works.
Ours, in every pack
Lean builder
In every pack · by prd-help · version 1.1, 2026-10-23
Use whenever you write or change code in this project. Keeps the build to what PRD.md asks for: the smallest change that works, with no extra features, libraries or abstractions.
Read lean-builder/SKILL.md
---
name: lean-builder
description: "Use whenever you write or change code in this project. Keeps the build to what PRD.md asks for: the smallest change that works, with no extra features, libraries or abstractions."
metadata:
author: prd-help
version: "1.1"
---
# Lean builder
Build what PRD.md asks for with the least new code. Less code means fewer bugs, and a project the student can still read and change.
## Before you write
- Read the step and the code it touches. List every place the change must reach: callers, tests, config.
- Check the step against the Scope section of PRD.md. Must is in. Later and Never are out, even when they look easy.
## Take the first option that works
1. Does it need to exist? If PRD.md does not ask for it, skip it and say so in one line.
2. Is it already in the project? Reuse it the way the surrounding code does.
3. Does the language, framework or platform already do it? Use that.
4. Is a library from the Stack section already installed? Use it. Never add a library for a few lines of code, and never add one that PRD.md does not name without asking the student.
5. Otherwise write the minimum code that works.
## Never cut
- Validation of anything that comes from users or other systems.
- Error handling that prevents data loss.
- Security: secrets stay in .env, never in code, logs or commits.
- Accessibility: labels, keyboard use, readable contrast.
- Anything PRD.md lists as an acceptance check.
## Keep it readable
- Match the names and style already in the project.
- Comment only why, never what.
- No options, settings or "for later" code that nobody asked for.
## Simpler, not just shorter
When you tidy code, change how it reads, never what it does. Tidy only code you touched in this step, then run its checks again.
- A chain of conditions squeezed into one expression: write plain if statements with early returns.
- A helper that only wraps one obvious expression: use the expression.
- A line doing four things at once: split it into named steps.
```ts
// hard to read
const label = loading ? 'loading' : failed ? 'error' : done ? 'done' : 'idle';
// clear
function statusLabel(loading: boolean, failed: boolean, done: boolean) {
if (loading) return 'loading';
if (failed) return 'error';
if (done) return 'done';
return 'idle';
}
```
Fewer lines is not the goal: a dense one-liner nobody can read is worse than three plain ones.
Credits: the tidying ideas come from Sentry's code-simplifier skill (Apache-2.0), rewritten for prd-help.
Prove before tick
In every pack · by prd-help · version 1.1, 2026-10-23
Use before you tick a step in PROGRESS.md or say that a step is done. A step is done only when its acceptance checks were actually run and passed, with the evidence written down.
Read prove-before-tick/SKILL.md
--- name: prove-before-tick description: "Use before you tick a step in PROGRESS.md or say that a step is done. A step is done only when its acceptance checks were actually run and passed, with the evidence written down." metadata: author: prd-help version: "1.1" --- # Prove before tick A step is done when its checks pass, not when its code is written. ## For every acceptance check the step covers 1. Turn it into something you can run: a test, a command, or exact steps in the running app. 2. Run it. Never assume a check passes because the code looks right. 3. Write down the evidence: the command and the lines of output that matter, or what you clicked and what you saw. 4. If you cannot run it yourself (it needs a phone, an account or a human eye), mark it "needs the student" and give exact steps they can follow. That is not passed. ## Then - Tick the step in PROGRESS.md only when every check passed. Under Notes, list each check as passed, failed or needs the student, with its evidence in one line. - When a check fails, fix it and run it again. After three failed attempts at the same check, stop and tell the student what you tried. - Never weaken, skip or delete a check to make it pass. If a check in PRD.md looks wrong, say so instead. - Report failed checks as failed, even when everything else passed. ## Before you say done, fixed or passes Those words are claims. Make one only after you ran the command that proves it in this step and read its whole output. | Claim | Proof | Not proof | | --- | --- | --- | | Tests pass | A test run just now with 0 failures | An earlier run, "should pass" | | It builds | The build command, exit code 0 | The linter passed | | Bug fixed | The original symptom is gone | The code changed | | A regression test works | It fails without the fix and passes with it | It passed once | | Step done | Every check of the step listed with its result | The tests pass | If you are about to write "should", "probably" or "seems to", you have not checked yet: run the check first. Credits: the claims table follows obra/superpowers' verification-before-completion skill (MIT), rewritten for prd-help.
Report to prd-help
Only in packs linked to prd-help · by prd-help · version 1.0, 2026-10-23
Use in a project linked to prd-help, an MCP server named prd-help with the tools next_step, get_prd and report_step. How to take each step from prd-help, read the current PRD and report back.
Read report-to-prd-help/SKILL.md
--- name: report-to-prd-help description: "Use in a project linked to prd-help, an MCP server named prd-help with the tools next_step, get_prd and report_step. How to take each step from prd-help, read the current PRD and report back." metadata: author: prd-help version: "1.0" --- # Report to prd-help The student keeps refining the PRD in prd-help while you build. prd-help gives you the steps and receives your reports. Claude Haiku reviews each report and proposes PRD fixes, which the student applies, discards or corrects. ## The loop 1. Call next_step. It names the step and what to check. 2. Call get_prd. If it differs from PRD.md, replace PRD.md with it and follow the new version. 3. Build that step only (lean-builder skill) and run its checks (prove-before-tick skill). 4. Call report_step with: - step: the number next_step gave you - summary: what you built, in a few sentences - checks_passed and checks_failed: one item per check, with its evidence in short - unclear: anything in PRD.md that was missing, vague or contradictory, and what you assumed 5. If a check failed, fix it and report the same step again. Otherwise call next_step. ## Stop and ask the student when - the step needs a decision PRD.md does not make, such as a paid service, a new library or deleting data - PRD.md contradicts itself - a check needs a person: a phone, an account, a judgement about how something looks ## Rules - Report honestly. A failed check reported as failed helps the student; a hidden one does not. - Never put secrets, keys or personal data in a report. - If a prd-help tool fails, keep building from PRD.md and tell the student.
From other publishers, in every pack
Copied unchanged with their licence. The pack lists their sources in .agents/skills/SOURCES.md.
systematic-debugging
by obra/superpowers · MIT · obra/superpowers@2ce8aa1 · 12 files
Find the root cause before fixing anything, in four phases. Its one script only runs the project's own tests.
Read systematic-debugging/SKILL.md
---
name: systematic-debugging
description: Use when encountering any bug, test failure, or unexpected behavior, before proposing fixes
---
# Systematic Debugging
## Overview
**Core principle:** ALWAYS find root cause before attempting fixes. Symptom fixes are failure.
**Violating the letter of this process is violating the spirit of debugging.**
## The Iron Law
```
NO FIXES WITHOUT ROOT CAUSE INVESTIGATION FIRST
```
If you haven't completed Phase 1, you cannot propose fixes.
## When to Use
Use for ANY technical issue:
- Test failures
- Bugs in production
- Unexpected behavior
- Performance problems
- Build failures
- Integration issues
**Use this ESPECIALLY when:**
- Under time pressure (emergencies make guessing tempting)
- "Just one quick fix" seems obvious
- You've already tried multiple fixes
- Previous fix didn't work
- You don't fully understand the issue
**Don't skip when:**
- Issue seems simple (simple bugs have root causes too)
- You're in a hurry (rushing guarantees rework)
- Manager wants it fixed NOW (systematic is faster than thrashing)
## The Four Phases
You MUST complete each phase before proceeding to the next.
### Phase 1: Root Cause Investigation
**BEFORE attempting ANY fix:**
1. **Read Error Messages Carefully**
- Don't skip past errors or warnings
- They often contain the exact solution
- Read stack traces completely
- Note line numbers, file paths, error codes
2. **Reproduce Consistently**
- Can you trigger it reliably?
- What are the exact steps?
- Does it happen every time?
- If not reproducible → gather more data, don't guess
3. **Check Recent Changes**
- What changed that could cause this?
- Git diff, recent commits
- New dependencies, config changes
- Environmental differences
4. **Gather Evidence in Multi-Component Systems**
**WHEN system has multiple components (CI → build → signing, API → service → database):**
**BEFORE proposing fixes, add diagnostic instrumentation:**
```
For EACH component boundary:
- Log what data enters component
- Log what data exits component
- Verify environment/config propagation
- Check state at each layer
Run once to gather evidence showing WHERE it breaks
THEN analyze evidence to identify failing component
THEN investigate that specific component
```
**Example (multi-layer system):**
```bash
# Layer 1: Workflow
echo "=== Secrets available in workflow: ==="
echo "IDENTITY: $([ -n "${IDENTITY:-}" ] && echo SET || echo UNSET)"
# Layer 2: Build script
echo "=== Env vars in build script: ==="
printenv IDENTITY >/dev/null 2>&1 && echo "IDENTITY in environment" || echo "IDENTITY not in environment"
# Layer 3: Signing script
echo "=== Keychain state: ==="
security list-keychains
security find-identity -v
# Layer 4: Actual signing
codesign --sign "$IDENTITY" --verbose=4 "$APP"
```
**This reveals:** Which layer fails (secrets → workflow ✓, workflow → build ✗)
5. **Trace Data Flow**
**WHEN error is deep in call stack:**
See `root-cause-tracing.md` in this directory for the complete backward tracing technique.
**Quick version:**
- Where does bad value originate?
- What called this with bad value?
- Keep tracing up until you find the source
- Fix at source, not at symptom
### Phase 2: Pattern Analysis
**Find the pattern before fixing:**
1. **Find Working Examples**
- Locate similar working code in same codebase
- What works that's similar to what's broken?
2. **Compare Against References**
- If implementing pattern, read reference implementation COMPLETELY
- Don't skim - read every line
- Understand the pattern fully before applying
3. **Identify Differences**
- What's different between working and broken?
- List every difference, however small
- Don't assume "that can't matter"
4. **Understand Dependencies**
- What other components does this need?
- What settings, config, environment?
- What assumptions does it make?
### Phase 3: Hypothesis and Testing
**Scientific method:**
1. **Form Single Hypothesis**
- State clearly: "I think X is the root cause because Y"
- Write it down
- Be specific, not vague
2. **Test Minimally**
- Make the SMALLEST possible change to test hypothesis
- One variable at a time
- Don't fix multiple things at once
3. **Verify Before Continuing**
- Did it work? Yes → Phase 4
- Didn't work? Form NEW hypothesis
- DON'T add more fixes on top
4. **When You Don't Know**
- Say "I don't understand X"
- Don't pretend to know
- Ask for help
- Research more
### Phase 4: Implementation
**Fix the root cause, not the symptom:**
1. **Create Failing Test Case**
- Simplest possible reproduction
- Automated test if possible
- One-off test script if no framework
- MUST have before fixing
- Use the `superpowers:test-driven-development` skill for writing proper failing tests
2. **Implement Single Fix**
- Address the root cause identified
- ONE change at a time
- No "while I'm here" improvements
- No bundled refactoring
3. **Verify Fix**
- Test passes now?
- No other tests broken?
- Issue actually resolved?
- Use the `superpowers:verification-before-completion` skill before claiming success
4. **If Fix Doesn't Work**
- STOP
- Count: How many fixes have you tried?
- If < 3: Return to Phase 1, re-analyze with new information
- **If ≥ 3: STOP and question the architecture (step 5 below)**
- DON'T attempt Fix #4 without architectural discussion
5. **If 3+ Fixes Failed: Question Architecture**
**Pattern indicating architectural problem:**
- Each fix reveals new shared state/coupling/problem in different place
- Fixes require "massive refactoring" to implement
- Each fix creates new symptoms elsewhere
**STOP and question fundamentals:**
- Is this pattern fundamentally sound?
- Are we "sticking with it through sheer inertia"?
- Should we refactor architecture vs. continue fixing symptoms?
**Discuss with your human partner before attempting more fixes**
This is NOT a failed hypothesis - this is a wrong architecture.
## Red Flags - STOP and Follow Process
If you catch yourself thinking:
- "Quick fix for now, investigate later"
- "Just try changing X and see if it works"
- "Add multiple changes, run tests"
- "Skip the test, I'll manually verify"
- "It's probably X, let me fix that"
- "I don't fully understand but this might work"
- "Pattern says X but I'll adapt it differently"
- "Here are the main problems: [lists fixes without investigation]"
- Proposing solutions before tracing data flow
- **"One more fix attempt" (when already tried 2+)**
- **Each fix reveals new problem in different place**
**ALL of these mean: STOP. Return to Phase 1.**
**If 3+ fixes failed:** Question the architecture (see Phase 4.5)
## your human partner's Signals You're Doing It Wrong
**Watch for these redirections:**
- "Is that not happening?" - You assumed without verifying
- "Will it show us...?" - You should have added evidence gathering
- "Stop guessing" - You're proposing fixes without understanding
- "Ultra-think this" - Question fundamentals, not just symptoms
- "We're stuck?" (frustrated) - Your approach isn't working
**When you see these:** STOP. Return to Phase 1.
## Common Rationalizations
| Excuse | Reality |
|--------|---------|
| "Issue is simple, don't need process" | Simple issues have root causes too. Process is fast for simple bugs. |
| "Emergency, no time for process" | Systematic debugging is FASTER than guess-and-check thrashing. |
| "Just try this first, then investigate" | First fix sets the pattern. Do it right from the start. |
| "I'll write test after confirming fix works" | Untested fixes don't stick. Test first proves it. |
| "Multiple fixes at once saves time" | Can't isolate what worked. Causes new bugs. |
| "Reference too long, I'll adapt the pattern" | Partial understanding guarantees bugs. Read it completely. |
| "I see the problem, let me fix it" | Seeing symptoms ≠ understanding root cause. |
| "One more fix attempt" (after 2+ failures) | 3+ failures = architectural problem. Question pattern, don't fix again. |
## Quick Reference
| Phase | Key Activities | Success Criteria |
|-------|---------------|------------------|
| **1. Root Cause** | Read errors, reproduce, check changes, gather evidence | Understand WHAT and WHY |
| **2. Pattern** | Find working examples, compare | Identify differences |
| **3. Hypothesis** | Form theory, test minimally | Confirmed or new hypothesis |
| **4. Implementation** | Create test, fix, verify | Bug resolved, tests pass |
## When Process Reveals "No Root Cause"
If systematic investigation reveals issue is truly environmental, timing-dependent, or external:
1. You've completed the process
2. Document what you investigated
3. Implement appropriate handling (retry, timeout, error message)
4. Add monitoring/logging for future investigation
**But:** 95% of "no root cause" cases are incomplete investigation.
## Supporting Techniques
These techniques are part of systematic debugging and available in this directory:
- **`root-cause-tracing.md`** - Trace bugs backward through call stack to find original trigger
- **`defense-in-depth.md`** - Add validation at multiple layers after finding root cause
- **`condition-based-waiting.md`** - Replace arbitrary timeouts with condition polling
find-bugs
by Sentry · Apache-2.0 · getsentry/skills@f57ada2 · 2 files
Checks the branch's changes for bugs and security holes and only reports; the student decides what to fix.
Read 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 1. Get the FULL diff: `git diff $(gh repo view --json defaultBranchRef --jq '.defaultBranchRef.name')...HEAD` 2. If output is truncated, read each changed file individually until you have seen every changed line 3. 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: 1. List every file you reviewed and confirm you read it completely 2. List every checklist item and note whether you found issues or confirmed it's clean 3. List any areas you could NOT fully verify and why 4. 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.
security-review
by Sentry · CC-BY-SA-4.0 · getsentry/skills@f57ada2 · 22 files
Reports only security issues it can trace to attacker input, with OWASP-based references.
Read 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
---
<!--
Reference material based on OWASP Cheat Sheet Series (CC BY-SA 4.0)
https://cheatsheetseries.owasp.org/
-->
# 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:**
```python
# SAFE: URL comes from Django settings (server-controlled)
response = requests.get(f"{settings.SEER_AUTOFIX_URL}{path}")
```
**SSRF Example - IS a vulnerability:**
```python
# 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
```markdown
## 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
security-best-practices
by OpenAI · Apache-2.0 · openai/skills@49f948f · 13 files
Secure-by-default rules for Next.js, React, Vue, Express, Django, FastAPI, Flask and Go; reads only the guide for the project's stack.
Read security-best-practices/SKILL.md
--- name: "security-best-practices" description: "Perform language and framework specific security best-practice reviews and suggest improvements. Trigger only when the user explicitly requests security best practices guidance, a security review/report, or secure-by-default coding help. Trigger only for supported languages (python, javascript/typescript, go). Do not trigger for general code review, debugging, or non-security tasks." --- # Security Best Practices ## Overview This skill provides a description of how to identify the language and frameworks used by the current context, and then to load information from this skill's references directory about the security best practices for this language and or frameworks. This information, if present, can be used to write new secure by default code, or to passively detect major issues within existing code, or (if requested by the user) provide a vulnerability report and suggest fixes. ## Workflow The initial step for this skill is to identify ALL languages and ALL frameworks which you are being asked to use or already exist in the scope of the project you are working in. Focus on the primary core frameworks. Often you will want to identify both frontend and backend languages and frameworks. Then check this skill's references directory to see if there are any relevant documentation for the language and or frameworks. Make sure you read ALL reference files which relate to the specific framework or language. The format of the filenames is `<language>-<framework>-<stack>-security.md`. You should also check if there is a `<language>-general-<stack>-security.md` which is agnostic to the framework you may be using. If working on a web application which includes a frontend and a backend, make sure you have checked for reference documents for BOTH the frontend and backend! If you are asked to make a web app which will include both a frontend and backend, but the frontend framework is not specified, also check out `javascript-general-web-frontend-security.md`. It is important that you understand how to secure both the frontend and backend. If no relevant information is available in the skill's references directory, think a little bit about what you know about the language, the framework, and all well known security best practices for it. If you are unsure you can try to search online for documentation on security best practices. From there it can operate in a few ways. 1. The primary mode is to just use the information to write secure by default code from this point forward. This is useful for starting a new project or when writing new code. 2. The secondary mode is to passively detect vulnerabilities while working in the project and writing code for the user. Critical or very important vulnerabilities or major issues going against security guidance can be flagged and the user can be told about them. This passive mode should focus on the largest impact vulnerabilities and secure defaults. 3. The user can ask for a security report or to improve the security of the codebase. In this case a full report should be produced describe anyways the project fails to follow security best practices guidance. The report should be prioritized and have clear sections of severity and urgency. Then offer to start working on fixes for these issues. See #fixes below. ## Workflow Decision Tree - If the language/framework is unclear, inspect the repo to determine it and list your evidence. - If matching guidance exists in `references/`, load only the relevant files and follow their instructions. - If no matching guidance exists, consider if you know any well known security best practices for the chosen language and or frameworks, but if asked to generate a report, let the user know that concrete guidance is not available (you can still generate the report or detect for sure critical vulnerabilities) # Overrides While these references contain the security best practices for languages and frameworks, customers may have cases where they need to bypass or override these practices. Pay attention to specific rules and instructions in the project's documentation and prompt files which may require you to override certain best practices. When overriding a best practice, you MAY report it to the user, but do not fight with them. If a security best practice needs to be bypassed / ignored for some project specific reason, you can also suggest to add documentation about this to the project so it is clear why the best practice is not being followed and to follow that bypass in the future. # Report Format When producing a report, you should write the report as a markdown file in `security_best_practices_report.md` or some other location if provided by the user. You can ask the user where they would like the report to be written to. The report should have a short executive summary at the top. The report should be clearly delineated into multiple sections based on severity of the vulnerability. The report should focus on the most critical findings as these have the highest impact for the user. All findings should be noted with an numeric ID to make them easier to reference. For critical findings include a one sentence impact statement. Once the report is written, also report it to the user directly, although you may be less verbose. You can offer to explain any of the findings or the reasons behind the security best practices guidance if the user wants more info on any findings. Important: When referencing code in the report, make sure to find and include line numbers for the code you are referencing. After you write the report file, summarize the findings to the user. Also tell the user where the final report was written to # Fixes If you produced a report, let the user read the report and ask to begin performing fixes. If you passively found a critical finding, notify the user and ask if they would like you to fix this finding. When producing fixes, focus on fixing a single finding at a time. The fixes should have concise clear comments explaining that the new code is based on the specific security best practice, and perhaps a very short reason why it would be dangerous to not do it in this way. Always consider if the changes you want to make will impact the functionality of the user's code. Consider if the changes may cause regressions with how the project works currently. It is often the case that insecure code is relied on for other reasons (and this is why insecure code lives on for so long). Avoid breaking the user's project as this may make them not want to apply security fixes in the future. It is better to write a well thought out, well informed by the rest of the project, fix, then a quick slapdash change. Always follow any normal change or commit flow the user has configured. If making git commits, provide clear commit messages explaining this is to align with security best practices. Try to avoid bunching a number of unrelated findings into a single commit. Always follow any normal testing flows the user has configured (if any) to confirm that your changes are not introducing regressions. Consider the second order impacts the changes may have and inform the user before making them if there are any. # General Security Advice Below is a few bits of secure coding advice that applies to almost any language or framework. ### Avoid Using Incrementing IDs for Public IDs of Resources When assigning an ID for some resource, which will then be used by exposed to the internet, avoid using small auto-incrementing IDs. Use longer, random UUID4 or random hex string instead. This will prevent users from learning the quantity of a resource and being able to guess resource IDs. ### A note on TLS While TLS is important for production deployments, most development work will be with TLS disabled or provided by some out-of-scope TLS proxy. Due to this, be very careful about not reporting lack of TLS as a security issue. Also be very careful around use of "secure" cookies. They should only be set if the application will actually be over TLS. If they are set on non-TLS applications (such as when deployed for local dev or testing), it will break the application. You can provide a env or other flag to override setting secure as a way to keep it off until on a TLS production deployment. Additionally avoid recommending HSTS. It is dangerous to use without full understanding of the lasting impacts (can cause major outages and user lockout) and it is not generally recommended for the scope of projects being reviewed by codex.
web-interface-review
by prd-help, rules by Vercel · MIT · vercel-labs/web-interface-guidelines@434b7f9 · 3 files
Reviews UI code for accessibility, focus, forms and layout. Vercel's rules are frozen into the skill, so it downloads nothing.
Read web-interface-review/SKILL.md
--- name: web-interface-review description: "Use after building or changing a screen, and when asked to review the UI, check accessibility or polish the interface. Checks the code against the Web Interface Guidelines in guidelines.md." metadata: author: prd-help rules: "Vercel Web Interface Guidelines, MIT, commit 434b7f9" --- # Web interface review Check UI code against the rules in guidelines.md, next to this file. They are Vercel's Web Interface Guidelines (MIT, see LICENSE.txt), copied at commit 434b7f9, so this skill never downloads anything. ## When - After you build or change a screen, before you tick its step. - When the student asks you to review the UI or check accessibility. ## How 1. Read guidelines.md in full. 2. Read the files of the screens you changed, or the ones the student names. 3. Check every rule that applies. Accessibility rules come first. 4. Report each finding in one line: file:line, the rule, the fix. Fix what the current step covers; list the rest for the student. 5. Where DESIGN.md or tokens.css exist, they win over guidelines.md on colours, fonts and spacing.
Matched to your stack
prd-help reads the Stack and Deployment sections of your PRD and adds up to 6 of these. No model decides this: a fixed list does.
| Your PRD mentions | The pack adds |
|---|---|
| Postgres, Supabase or Neon | supabase-postgres-best-practices |
| Prisma | prisma-client-api |
| MongoDB | mongodb-schema-design, mongodb-query-optimizer |
| Expo or React Native | react-navigation, react-native-testing |
| Sign in with Google | sign-in-with-google-web |
| PostHog | instrument-error-tracking |
| Cloudflare Agents | agents-sdk |
| Firebase | firestore-rules-creation |
| Redis | redis-core |
| Cloudflare | workers-best-practices |
| Resend | email-best-practices, react-email |
supabase-postgres-best-practices
by Supabase · MIT · supabase/agent-skills@c9be0e9 · 37 files
Postgres schema, index, security and query rules that apply to any Postgres, Supabase and Neon included.
Read supabase-postgres-best-practices/SKILL.md
--- name: supabase-postgres-best-practices description: "Postgres best practices maintained by Supabase, for Postgres running anywhere. Load this skill BEFORE writing or changing anything that lives in a Postgres database: creating or altering tables and columns (including choosing column types), schema design, migrations and declarative schema files, RLS policies and the tests that verify them, indexes, triggers, database functions, queues and scheduled jobs (pg_cron, pgmq), vector/semantic search (pgvector), and restoring dumps (pg_restore) or importing data. Also load it when diagnosing slow queries, high CPU, timeouts, EXPLAIN plans, connection exhaustion, locking, bloat, or rows visible to the wrong user or tenant. This is not just a performance guide — schema, migration, security, and SQL authoring tasks need these rules too, even for a one-column change or a single query." license: MIT metadata: author: supabase version: "1.1.1" organization: Supabase date: January 2026 abstract: Comprehensive Postgres performance optimization guide for developers using Supabase and Postgres. Contains performance rules across 8 categories, prioritized by impact from critical (query performance, connection management) to incremental (advanced features). Each rule includes detailed explanations, incorrect vs. correct SQL examples, query plan analysis, and specific performance metrics to guide automated optimization and code generation. --- # Supabase Postgres Best Practices Comprehensive performance optimization guide for Postgres, maintained by Supabase. Contains rules across 8 categories, prioritized by impact to guide automated query optimization and schema design. ## When to Apply Reference these guidelines when: - Writing SQL queries or designing schemas - Implementing indexes or query optimization - Reviewing database performance issues - Configuring connection pooling or scaling - Optimizing for Postgres-specific features - Working with Row-Level Security (RLS) ## Rule Categories by Priority | Priority | Category | Impact | Prefix | |----------|----------|--------|--------| | 1 | Query Performance | CRITICAL | `query-` | | 2 | Connection Management | CRITICAL | `conn-` | | 3 | Security & RLS | CRITICAL | `security-` | | 4 | Schema Design | HIGH | `schema-` | | 5 | Concurrency & Locking | MEDIUM-HIGH | `lock-` | | 6 | Data Access Patterns | MEDIUM | `data-` | | 7 | Monitoring & Diagnostics | LOW-MEDIUM | `monitor-` | | 8 | Advanced Features | LOW | `advanced-` | ## How to Use Read individual rule files for detailed explanations and SQL examples: ``` references/query-missing-indexes.md references/query-partial-indexes.md references/_sections.md ``` Each rule file contains: - Brief explanation of why it matters - Incorrect SQL example with explanation - Correct SQL example with explanation - Optional EXPLAIN output or metrics - Additional context and references - Supabase-specific notes (when applicable) ## References - https://www.postgresql.org/docs/current/ - https://supabase.com/docs - https://wiki.postgresql.org/wiki/Performance_Optimization - https://supabase.com/docs/guides/database/overview - https://supabase.com/docs/guides/auth/row-level-security
prisma-client-api
by Prisma · MIT · prisma/skills@ba3f9d7 · 10 files
Correct Prisma Client queries, relations and transactions.
Read prisma-client-api/SKILL.md
---
name: prisma-client-api
description: Prisma Client API reference covering model queries, filters, operators, and client methods. Use when writing database queries, using CRUD operations, filtering data, or configuring Prisma Client. Triggers on "prisma query", "findMany", "create", "update", "delete", "$transaction".
license: MIT
metadata:
author: prisma
version: "7.9.1"
---
# Prisma Client API Reference
Complete API reference for Prisma Client. This skill provides guidance on model queries, filtering, relations, and client methods for current Prisma projects.
## When to Apply
Reference this skill when:
- Writing database queries with Prisma Client
- Performing CRUD operations (create, read, update, delete)
- Filtering and sorting data
- Working with relations
- Using transactions
- Configuring client options
## Rule Categories by Priority
| Priority | Category | Impact | Prefix |
|----------|----------|--------|--------|
| 1 | Client Construction | HIGH | `constructor` |
| 2 | Model Queries | CRITICAL | `model-queries` |
| 3 | Query Shape | HIGH | `query-options` |
| 4 | Filtering | HIGH | `filters` |
| 5 | Relations | HIGH | `relations` |
| 6 | Transactions | CRITICAL | `transactions` |
| 7 | Raw SQL | CRITICAL | `raw-queries` |
| 8 | Client Methods | MEDIUM | `client-methods` |
## Quick Reference
- `constructor` - `PrismaClient` setup, adapter wiring, logging, and SQL commenter plugins
- `model-queries` - CRUD operations and bulk operations
- `query-options` - `select`, `include`, `omit`, sort, pagination
- `filters` - scalar and logical filter operators
- `relations` - relation reads and nested writes
- `transactions` - array and interactive transaction patterns
- `raw-queries` - `$queryRaw` and `$executeRaw` safety
- `client-methods` - lifecycle methods, extensions, and `satisfies` patterns for `prisma-client`
## Client Instantiation
```typescript
import { PrismaClient } from '../generated/client'
import { PrismaPg } from '@prisma/adapter-pg'
const adapter = new PrismaPg({
connectionString: process.env.DATABASE_URL
})
const prisma = new PrismaClient({ adapter })
```
## Model Query Methods
| Method | Description |
|--------|-------------|
| `findUnique()` | Find one record by unique field |
| `findUniqueOrThrow()` | Find one or throw error |
| `findFirst()` | Find first matching record |
| `findFirstOrThrow()` | Find first or throw error |
| `findMany()` | Find multiple records |
| `create()` | Create a new record |
| `createMany()` | Create multiple records |
| `createManyAndReturn()` | Create multiple and return them |
| `update()` | Update one record |
| `updateMany()` | Update multiple records |
| `updateManyAndReturn()` | Update multiple and return them |
| `upsert()` | Update or create record |
| `delete()` | Delete one record |
| `deleteMany()` | Delete multiple records |
| `count()` | Count matching records |
| `aggregate()` | Aggregate values (sum, avg, etc.) |
| `groupBy()` | Group and aggregate |
## Query Options
| Option | Description |
|--------|-------------|
| `where` | Filter conditions |
| `select` | Fields to include |
| `include` | Relations to load |
| `omit` | Fields to exclude |
| `orderBy` | Sort order |
| `take` | Limit results |
| `skip` | Skip results (pagination) |
| `cursor` | Cursor-based pagination |
| `distinct` | Unique values only |
## Client Methods
| Method | Description |
|--------|-------------|
| `$connect()` | Explicitly connect to database |
| `$disconnect()` | Disconnect from database |
| `$transaction()` | Execute transaction |
| `$queryRaw()` | Execute raw SQL query |
| `$executeRaw()` | Execute raw SQL command |
| `$on()` | Subscribe to events |
| `$extends()` | Add extensions |
## Quick Examples
### Find records
```typescript
// Find by unique field
const user = await prisma.user.findUnique({
where: { email: 'alice@prisma.io' }
})
// Find with filter
const users = await prisma.user.findMany({
where: { role: 'ADMIN' },
orderBy: { createdAt: 'desc' },
take: 10
})
```
### Create records
```typescript
const user = await prisma.user.create({
data: {
email: 'alice@prisma.io',
name: 'Alice',
posts: {
create: { title: 'Hello World' }
}
},
include: { posts: true }
})
```
### Update records
```typescript
const user = await prisma.user.update({
where: { id: 1 },
data: { name: 'Alice Smith' }
})
```
### Delete records
```typescript
await prisma.user.delete({
where: { id: 1 }
})
```
### Transactions
```typescript
const [user, post] = await prisma.$transaction([
prisma.user.create({ data: { email: 'alice@prisma.io' } }),
prisma.post.create({ data: { title: 'Hello', authorId: 1 } })
])
```
## Rule Files
Detailed API documentation:
```
references/constructor.md - PrismaClient constructor options
references/model-queries.md - CRUD operations
references/query-options.md - select, include, omit, where, orderBy
references/filters.md - Filter conditions and operators
references/relations.md - Relation queries and nested operations
references/transactions.md - Transaction API
references/raw-queries.md - $queryRaw, $executeRaw
references/client-methods.md - $connect, $disconnect, $on, $extends
```
## Filter Operators
| Operator | Description |
|----------|-------------|
| `equals` | Exact match |
| `not` | Not equal |
| `in` | In array |
| `notIn` | Not in array |
| `lt`, `lte` | Less than |
| `gt`, `gte` | Greater than |
| `contains` | String contains |
| `startsWith` | String starts with |
| `endsWith` | String ends with |
| `mode` | Case sensitivity |
## Relation Filters
| Operator | Description |
|----------|-------------|
| `some` | At least one related record matches |
| `every` | All related records match |
| `none` | No related records match |
| `is` | Related record matches (1-to-1) |
| `isNot` | Related record doesn't match |
## Resources
- [Prisma Client API Reference](https://www.prisma.io/docs/orm/reference/prisma-client-reference)
- [CRUD Operations](https://www.prisma.io/docs/orm/prisma-client/queries/crud)
- [Filtering and Sorting](https://www.prisma.io/docs/orm/prisma-client/queries/filtering-and-sorting)
## How to Use
Pick the category from the table above, then open the matching reference file for implementation details and examples.
mongodb-schema-design
by MongoDB · Apache-2.0 · mongodb/agent-skills@155bb9c · 22 files
Document schema design: when to embed, when to reference. Asks before any write to a database.
Read mongodb-schema-design/SKILL.md
--- name: mongodb-schema-design description: MongoDB schema design patterns and anti-patterns. Use when designing data models, reviewing schemas, migrating from SQL, or troubleshooting performance issues caused by schema problems. Triggers on "design schema", "embed vs reference", "MongoDB data model", "schema review", "unbounded arrays", "one-to-many", "tree structure", "16MB limit", "schema validation", "JSON Schema", "time series", "schema migration", "polymorphic", "TTL", "data lifecycle", "archive", "index explosion", "unnecessary indexes", "approximation pattern", "document versioning". license: Apache-2.0 metadata: version: "1.0.0" --- # MongoDB Schema Design Data modeling patterns and anti-patterns for MongoDB, maintained by MongoDB. Bad schema is the root cause of most MongoDB performance and cost issues—queries and indexes cannot fix a fundamentally wrong model. ## When to Apply Reference these guidelines when: - Designing a new MongoDB schema from scratch - Migrating from SQL/relational databases to MongoDB - Reviewing existing data models for performance issues - Troubleshooting slow queries or growing document sizes - Deciding between embedding and referencing - Modeling relationships (one-to-one, one-to-many, many-to-many) - Implementing tree/hierarchical structures - Seeing Atlas Schema Suggestions or Performance Advisor warnings - Hitting the 16MB document limit - Adding schema validation to existing collections ## Quick Reference ### 1. Schema Anti-Patterns - 3 rules - [antipattern-unnecessary-collections](references/antipattern-unnecessary-collections.md) - Splitting homogeneous data into multiple collections is often an anti-pattern; consult this reference to validate whether this is the case. - [antipattern-excessive-lookups](references/antipattern-excessive-lookups.md) - When encountering overly normalized collections that reference each other or frequent and possibly slow $lookup operations, consult this reference to validate whether this is problematic and how to fix it. - [antipattern-unnecessary-indexes](references/antipattern-unnecessary-indexes.md) - Consult this reference when indexes overlap or are not used by queries, to identify and remove unnecessary indexes that add overhead without benefit. ### 2. Schema Fundamentals - 4 rules - [fundamental-embed-vs-reference](references/fundamental-embed-vs-reference.md) - Consult this reference for approaches to modeling different types of relationships (1:1, 1:few, 1:many, many:many, tree/hierarchical data) and how to decide between embedding and referencing based on access patterns. - [fundamental-document-model](references/fundamental-document-model.md) - Fundamentals of the document model. Consult this reference when migrating from SQL or other normalized data to a document database like MongoDB. - [fundamental-schema-validation](references/fundamental-schema-validation.md) - Consult this reference when creating new collections, or adding validation to existing collections, for example in response to finding inconsistent document structures or data quality issues. - [fundamental-document-size](references/fundamental-document-size.md) - Consult this reference when documents hit the hard 16MB limit, or when accesses are slower than expected as a result of large documents. ### 3. Design Patterns - 11 rules - [pattern-approximation](references/pattern-approximation.md) - Use approximate values for high-frequency counters - [pattern-archive](references/pattern-archive.md) - Move historical data to separate/cold storage for performance - [pattern-attribute](references/pattern-attribute.md) - Collapse many optional fields into key-value attributes - [pattern-bucket](references/pattern-bucket.md) - Group time-series or IoT data into buckets - [pattern-computed](references/pattern-computed.md) - Pre-calculate expensive aggregations - [pattern-document-versioning](references/pattern-document-versioning.md) - Track document changes to enable historical queries and audit trails - [pattern-extended-reference](references/pattern-extended-reference.md) - Cache frequently-accessed data from related entities - [pattern-outlier](references/pattern-outlier.md) - Handle collections in which a small subset of documents are much larger than the rest, to prevent outliers from dominating memory and index costs - [pattern-polymorphic](references/pattern-polymorphic.md) - Store different types of entities in the same collection, often when they are different types of the same base entity (e.g. different types of users or different types of products) - [pattern-schema-versioning](references/pattern-schema-versioning.md) - Schema evolution, preventing drift, and safe online migrations. Consult when encountering inconsistent document structures, or when planning a schema change that cannot be applied atomically. - [pattern-time-series-collections](references/pattern-time-series-collections.md) - Use native time series collections for high-frequency time series data ### Access Pattern Analysis Do not immediately recommend a pattern or schema change without understanding the broader context. Together with the user, analyze access patterns to identify pain points and opportunities for optimization. #### Workflow **Step 1: Assess the environment** Ask the user: - Is this a new design or is there a production database with existing access patterns to analyze? - If there is production data, is it on Atlas? If yes, what tier? (M0/M2/M5 vs M10+) **Step 2: Determine workload type** Is the workload read-heavy, write-heavy, or balanced? This will influence which diagnostic sources are most relevant. Ask the user: - What's the primary workload for these collections — read-heavy (analytics, reports, searches), write-heavy (logging, IoT ingestion, frequent updates), or balanced? Verify with `db.serverStatus().opcounters`. **Step 3: Work with the user to choose the best source(s)** Recommend the best source(s) for their situation, explaining the tradeoffs. For schema design decisions, we often need to combine multiple sources for a complete picture. **Step 4: Proceed with analysis** Only after source selection, fetch data or guide the user through analysis. #### Sources - [Query statistics](references/source-query-stats.md) - Returns runtime statistics for recorded queries showing query shapes and frequency. **Limitation**: Currently only captures read operations (pair with other sources for write patterns). Requires Atlas M10+ tier. - [Atlas Slow Query Logs](references/source-slow-query-logs.md) - Review slow queries (actual queries, not shapes) to identify performance bottlenecks. Captures all reads and writes. Requires Atlas M10+ tier. - Codebase - Examine actual queries in application code to understand access patterns, especially for new applications or with changing workloads. Can be used in conjunction with query stats for a more complete picture. - Natural language input - Ask the user to describe their typical queries and access patterns in natural language. Can be used as the only source or to supplement and validate other sources - the user might have contextual knowledge that is not reflected in the data or codebase. **Combining Query Stats and Slow Query Logs:** Use both together for comprehensive analysis: 1. Query Stats → identify frequent access patterns (which queries run most often) 2. Slow Query Logs → identify performance bottlenecks (which queries are slow) 3. Focus schema optimization on queries that are both frequent AND slow (highest impact) ## Key Principle > **"Data that is accessed together should be stored together."** This is MongoDB's core philosophy. Embedding related data eliminates joins, reduces round trips, and enables atomic updates. Reference only when you must. A core way to implement this philosophy is the fact that MongoDB exposes **flexible schemas**. This means you can have different fields in different documents, and even different structures. This allows you to model data in the way that best fits your access patterns, without being constrained by a rigid schema. For example, if different documents have different sets of fields, that is perfectly fine as long as it serves your application's needs. You can also use schema validation to enforce certain rules while still allowing for flexibility. Another implication of the key principle is that information about the expected read and write workload becomes very relevant to schema design. If pieces of information from different entities are often queried or updated together, that means that prioritizing co-location of that data in the same document can lead to significant performance benefits. On the other hand, if certain pieces of information are rarely accessed together, it may make sense to store them separately to avoid loading more data than necessary. #### Schema Fundamentals Summary - **Embed vs Reference**: Choose embedding or referencing based on access patterns: embed when data is always accessed together (1:1, 1:few, bounded arrays, atomic updates needed); reference when data is accessed independently, relationships are many-to-many, or arrays can grow without bound. - **Data accessed together stored together**: MongoDB's core principle: design schemas around queries, not entities. Embed related data to eliminate cross-collection joins and reduce round trips. Identify your API endpoints/pages, list the data each returns, then shape documents to match those queries. - **Embrace the document model**: Don't recreate SQL tables 1:1 as MongoDB collections. Instead, denormalize joined tables into rich documents for single-query reads and atomic updates. When migrating from SQL, identify tables that are always joined together and merge them into single documents. - **Schema validation**: Use MongoDB's built-in `$jsonSchema` validator to catch invalid data at the database level (type checks, required fields, enum constraints, array size limits). Start with `validationLevel: "moderate"` and `validationAction: "warn"` on existing collections, then tighten to `strict`/`error`. - **16MB document limit**: MongoDB documents cannot exceed 16MB—this is a hard limit, not a guideline. Common causes: unbounded arrays, large embedded binaries, deeply nested objects. Mitigate by moving unbounded data to separate collections and monitoring document sizes with `$bsonSize`. ## Embed/Reference Decision Framework | Relationship | Cardinality | Access Pattern | Recommendation | |-------------|-------------|----------------|----------------| | One-to-One | 1:1 | Always together | Embed | | One-to-Few | 1:N (N < 100) | Usually together | Embed array | | One-to-Many | 1:N (N > 100) | Often separate | Reference | | Many-to-Many | M:N | Varies | Two-way reference | This is a **rough** guideline, and whether to embed or reference depends on your specific access patterns, data size, and read/write frequencies. Always verify with your actual workload. ## How to Use Each reference file listed above contains detailed explanations and code examples. Use the descriptions in the Quick Reference to identify which files are relevant to your current task. Each reference file contains: - Brief explanation of why it matters - Incorrect code example with explanation - Correct code example with explanation - "When NOT to use" exceptions - Performance impact and metrics - Verification diagnostics --- ## How These Rules Work ### MongoDB MCP Integration For automatic verification, connect the [MongoDB MCP Server](https://github.com/mongodb-js/mongodb-mcp-server). If the MCP server is running and connected, I can automatically run verification commands to check your actual schema, document sizes, array lengths, index usage, slow query logs, and more. This allows me to provide tailored recommendations based on your real data, not just code patterns. **⚠️ Security**: Use `--readOnly` for safety. Remove only if you need write operations. When connected, I can automatically: - Infer schema via `mcp__mongodb__collection-schema` - Measure document/array sizes via `mcp__mongodb__aggregate` - Check collection statistics via `mcp__mongodb__db-stats` ### ⚠️ Action Policy **I will NEVER execute write operations without your explicit approval.** Before any write or destructive operation via MCP, I will: (1) summarize the exact operation (collection, index/validator, estimated number of docs affected), and (2) ask for explicit confirmation (yes/no). I will not proceed on partial or ambiguous approvals. | Operation Type | MCP Tools | Action | |---------------|-----------|--------| | **Read (Safe)** | `find`, `aggregate`, `collection-schema`, `db-stats`, `count` | I may run automatically to verify | | **Write (Requires Approval)** | `update-many`, `insert-many`, `create-collection` | I will show the command and wait for your "yes" | | **Destructive (Requires Approval)** | `delete-many`, `drop-collection`, `drop-database` | I will warn you and require explicit confirmation | When I recommend schema changes or data modifications: 1. I'll explain **what** I want to do and **why** 2. I'll show you the **exact command** 3. I'll **wait for your approval** before executing 4. If you say "go ahead" or "yes", only then will I run it **Your database, your decision.** I'm here to advise, not to act unilaterally. ### Working Together If you're not sure about a recommendation: 1. Run the verification commands I provide 2. Share the output with me 3. I'll adjust my recommendation based on your actual data We're a team—let's get this right together.
firestore-rules-creation
by Firebase · Apache-2.0 · firebase/agent-skills@92eed24 · 2 files
Strict Firestore security rules that validate every write. Checks them with a dry run only.
Read firestore-rules-creation/SKILL.md
---
name: firestore-rules-creation
description: >-
Designs, authors, refactors, and hardens production-grade Cloud Firestore Security Rules (firestore.rules). IMPORTANT: If subagent delegation AND the firestore-rules-author subagent are available in your environment, delegate authoring firestore.rules to the firestore-rules-author subagent. If subagent delegation is unavailable (e.g. not enabled in the IDE), firestore-rules-author is not installed, or you are running inside firestore-rules-author, follow this skill directly.
metadata:
author: Google LLC
category: Databases
---
# Firestore Security Rules Creation
> [!IMPORTANT] **Subagent Delegation vs. Direct Authoring**
>
> - **If subagent delegation AND the `firestore-rules-author` subagent are
> available** in your active environment: **DO NOT** author `firestore.rules`
> directly in the main agent. Invoke the `firestore-rules-author` subagent and
> delegate the analysis and creation of `firestore.rules` to it.
> - **If subagent delegation is unavailable** (e.g., in IDE environments where
> subagent tools are not enabled) **OR the `firestore-rules-author` subagent
> is not installed**, **OR if you are already executing inside
> `firestore-rules-author`**: proceed with the workflow below to author
> `firestore.rules` directly.
You are an expert Firebase Security Rules engineer with deep knowledge of
Firestore security best practices. Your task is to generate comprehensive,
secure Firebase Security rules for the user's project. To minimize the risk of
security incidents and avoid misleading the user about the security of their
application, you must be extremely humble about the rules you generate. Always
present the rules you've written as a prototype that needs review.
After generating the rules, you MUST explicitly communicate to the user exactly
like this: "I've set up prototype Security Rules to keep the data in Firestore
safe. They are designed to be secure for <explain reasons here>. However, you
should review and verify them before broadly sharing your app. If you'd like, I
can help you harden these rules."
### Workflow
Follow this structured workflow strictly:
#### Phase-1: Codebase Analysis
1. **Scan the entire codebase** to identify:
- Programming language(s) used (for understanding context only)
- All Firestore collection and document paths
- **All Firestore Queries:** Identify every `where()`, `orderBy()`, and
`limit()` clause. The security rules **MUST** allow these specific queries.
- Data models and schemas (interfaces, classes, types)
- Data types for each field (strings, numbers, booleans, timestamps, URLs,
emails, etc.)
- Required vs. optional fields
- Field constraints (min/max length, format patterns, allowed values)
- CRUD operations (create, read, update, delete)
- Authentication patterns (Firebase Auth, custom tokens, anonymous)
- Access patterns and business logic rules
1. **Synthesize your findings** concisely (in memory; do not create extra
untracked scratch files in the workspace) and refer to them when generating
the security rules.
#### Phase-2: Security Rules Generation
**CRITICAL**: Follow the following principles **every time you modify the
security rules file**
Generate Firebase Security Rules following these principles:
- **Default deny:** Start with denying all access, then explicitly allow only
what's needed
- **Least privilege:** Grant minimum permissions required
- **Validate data:** Check data types, allowed fields, and constraints on both
creates and updates.
- **MANDATORY:** You **MUST** use the **Validator Function Pattern** described
in the "Critical Directives" section below. This involves defining a
specific validation function (e.g., `isValidUser`) and calling it in
**BOTH** `create` and `update` rules.
- **MANDATORY:** For **ALL** creates **AND ALL** updates, ensure that after
the operation, the required fields are still available and that the data is
valid.
- **Authentication checks:** Verify user identity before granting access
- **Authorization logic:** Implement role-based or ownership-based access
control
- **UID Protection:** Prevent users from changing ownership of data
- **Initially restricted:** Never make any collection or data publicly readable,
always require authentication for any access to data unless the user makes an
*explicit* request for unauthenticated data.
This means the first firestore.rules file you generate must never have any
"allow read: true" statements.
**Structure Requirements:**
1. **Document assumed data models at the beginning of the rules file:**
```javascript
// ===============================================================
// Assumed Data Model
// ===============================================================
//
// This security rules file assumes the following data structures:
//
// Collection: [name]
// Document ID: [pattern]
// Fields:
// - field1: type (required/optional, constraints) - description
// - field2: type (required/optional, constraints) - description
// [List all fields with types, constraints, and whether immutable]
//
// [Repeat for all collections]
//
// ===============================================================
```
1. **Include comprehensive helper functions to avoid repetition:**
```javascript
// ===============================================================
// Helper Functions
// ===============================================================
//
// Check if the user is authenticated
function isAuthenticated() {
return request.auth != null;
}
//
// Check if user owns the resource (for user-owned documents)
function isOwner(userId) {
return isAuthenticated() && request.auth.uid == userId;
}
//
// Check if user is owner based on document's uid field
function isDocOwner() {
return isAuthenticated() && request.auth.uid == resource.data.uid;
}
//
// Verify UID hasn't been tampered with on create
function uidUnchanged() {
return !('uid' in request.resource.data) ||
request.resource.data.uid == request.auth.uid;
}
//
// Ensure uid field is not modified on update
function uidNotModified() {
return !('uid' in request.resource.data) ||
request.resource.data.uid == resource.data.uid;
}
//
// Validate required fields exist
function hasRequiredFields(fields) {
return request.resource.data.keys().hasAll(fields);
}
//
// Validate string length
function validStringLength(field, minLen, maxLen) {
return request.resource.data[field] is string &&
request.resource.data[field].size() >= minLen &&
request.resource.data[field].size() <= maxLen;
}
//
// Validate URL format (must start with https:// or http://)
function isValidUrl(url) {
return url is string &&
(url.matches("^https://.*") || url.matches("^http://.*"));
}
//
// Validate email format
function isValidEmail(email) {
return email is string &&
email.matches("^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$");
}
//
// Validate ISO 8601 date string format (YYYY-MM-DDTHH:MM:SS)
// CRITICAL: This validates format ONLY, not logical date values (e.g., month 13).
// Use the 'timestamp' type for documents where logical date validation is required.
function isValidDateString(dateStr) {
return dateStr is string &&
dateStr.matches("^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}.*Z?$");
}
//
// Validate that a string path is correctly scoped to the user's ID
function isScopedPath(path) {
return path is string && path.matches("^users/" + request.auth.uid + "/.*");
}
//
// Validate that a value is positive
function isPositive(field) {
return request.resource.data[field] is number && request.resource.data[field] > 0;
}
//
// Validate that a list is a list and enforces size limits
function isValidList(list, maxSize) {
return list is list && list.size() <= maxSize;
}
//
// Validate optional string (if present, must be string and within length)
function isValidOptionalString(field, minLen, maxLen) {
return !(field in request.resource.data) ||
(request.resource.data[field] is string &&
request.resource.data[field].size() >= minLen &&
request.resource.data[field].size() <= maxLen);
}
//
// Validate that a map contains only allowed keys
function isValidMap(mapData, allowedKeys) {
return mapData is map && mapData.keys().hasOnly(allowedKeys);
}
//
// Validate that the document contains only the allowed fields
function hasOnlyAllowedFields(fields) {
return request.resource.data.keys().hasOnly(fields);
}
//
// Validate that the document hasn't changed in the fields that are not allowed to be changed
function areImmutableFieldsUnchanged(fields) {
return !request.resource.data.diff(resource.data).affectedKeys().hasAny(fields);
}
//
// Validate that a timestamp is recent (within the last 5 minutes)
function isRecent(time) {
return time is timestamp &&
time > request.time - duration.value(5, 'm') &&
time <= request.time;
}
//
// [Add more helper functions as needed for the data validation like the example below]
//
// ===============================================================
//
// Domain Validators (CRITICAL: Use these in both create and update)
//
// function isValidUser(data) {
// // Only allow admin to create admin roles
// return hasOnlyAllowedFields(['name', 'email', 'age', 'role']) &&
// data.name is string && data.name.size() > 0 && data.name.size() < 50 &&
// data.email is string && isValidEmail(data.email) &&
// data.age is number && data.age >= 18 &&
// data.role in ['admin', 'user', 'guest'];
// }
```
#### Mandatory: User Data Separation (The "No Mixed Content" Rule)
- Firestore security rules apply to the entire document. You cannot allow users
to read the displayName field while hiding the email field in the same
document.
- If a collection (e.g., users) contains ANY PII (email, phone, address, private
settings), you MUST strictly limit read access to the document owner only
(allow read: if isOwner(userId);).
- If the application requires public profiles (e.g., showing user names/avatars
on posts):
- 1. Denormalization (Preferred): Copy the user's public info (name, photoURL)
directly onto the resources they create (e.g., store authorName and
authorPhoto inside the posts document).
- 2. Split Collections: Create a separate users_public collection that
contains only non-sensitive data, and keep the sensitive data in a
locked-down users_private collection.
- NEVER write a rule that allows read access to a document containing PII for
anyone other than the owner.
#### **CRITICAL** RBAC Guidelines
This is one of the most important set of instructions to follow. Failing to
follow these rules will result in catastrophic security vulnerabilities.
- **NEVER** allow users to create their own privileged roles. That means that no
user should be able to create an item in a database with their role set to a
role similar to "admin" unless they are already a bootstrapped admin.
- **NEVER** allow users to update their own roles or permissions.
- **NEVER** allow users to grant themselves access to other users' data.
- **NEVER** allow users to bypass the role hierarchy.
- **ALWAYS** validate that the user is authorized to perform the requested
action.
- **ALWAYS** validate that the user is not attempting to escalate their
privileges.
- **ALWAYS** validate that the user is not attempting to access data they do not
have permission to access.
Here's a **bad** example of what **NOT** to do:
```javascript
match /users/{userId} {
// BAD: Allows users to create their own roles because a user can create a new user document with a role of 'admin' and the isAdmin() function will return true
allow create: if (isOwner(userId) && isValidUser(request.resource.data)) || isAdmin();
// BAD: Allows users to update their own roles because a user can update their own user document with a role of 'admin' and the isAdmin() function will return true
allow update: if (isOwner(userId) && isValidUser(request.resource.data)) || isAdmin();
}
```
Here's a **good** example of what **TO** do:
```javascript
match /users/{userId} {
// GOOD: Does NOT allow users to create their own roles unless they are an admin or the user is updating their own role to a less privileged role
allow create: if isAuthenticated() && isValidUser(request.resource.data) && ((isOwner(userId) && request.resource.data.role == 'client') || isAdmin());
// GOOD: Does NOT allow users to update their own roles unless they are an admin
allow update: if isAuthenticated() && isValidUser(request.resource.data) && ((isOwner(userId) && request.resource.data.role == resource.data.role) || isAdmin());
}
```
#### Critical Directives for Secure Generation
- **PREFER USING READ OVER LIST OR GET** `list` and `get` can add complexity to
security rules. Prefer using `read` over them.
- **Date and Timestamp Validation:**
- **Prefer Timestamps:** ALWAYS prefer the `timestamp` type for date fields.
Firestore automatically ensures they are logically valid dates.
- **String Date Risks:** If using strings for dates (e.g., ISO 8601), a regex
check like `isValidDateString` only validates **format**, not **logic** (it
would accept Feb 31st).
- **Regex Escaping:** When using regex for digits, you **MUST** use double
backslashes (e.g., `\\\\d`) in the rules string. Using a single backslash
(`\\d`) is a common bug that causes validation to fail.
- **Immutable Fields:** Fields like `createdAt`, `authorUID`, or any other field
that should not change after creation must be explicitly protected in `update`
rules. (e.g., `request.resource.data.createdAt == resource.data.createdAt`).
**CRITICAL**: When allowing non-owners to update specific fields (like
incrementing a counter), you **MUST** explicitly verify that all other fields
(e.g., `authorName`, `tags`, `body`) remain unchanged to prevent unauthorized
metadata modification. For sensitive fields, ensure that the logged in user is
also the owner of the document.
- **Identity Integrity:** When storing denormalized user identity (e.g.
`authorName`, `authorPhoto`), you **MUST** validate this data.
- **Prefer Auth Token:** If possible, check if
`request.resource.data.authorName == request.auth.token.name`.
- **Strict Validation:** If the auth token is unavailable, you **MUST**
strictly validate the type (string) and length (e.g. < 50 chars) to prevent
spoofing with massive or malicious payloads.
- **Client-Side Fetching:** The most secure pattern is to store ONLY
`authorUid` and fetch the profile client-side. If you denormalize, you
accept the risk of stale or spoofed data unless you validate it.
- **Enforce Strict Schema (No Extraneous Fields):** Documents must not contain
any fields other than those explicitly defined in the data model. This
prevents users from adding arbitrary data.
- **NEVER allow PII EXPOSURE LEAKS:** Never allow PII (Personally Identifiable
Information) to be exposed in the data model. This includes email addresses,
phone numbers, and any other information that could be used to identify a
user. For example, even if a user is logged-in, they should not have access to
read another user's information.
- **No Blanket User Read Access:** You are strictly FORBIDDEN from generating
`allow read: if isAuthenticated();` for the users collection if that
collection is defined to contain email addresses or other private data.
- **CRITICAL: Double-Check Blanket `isAuthenticated` fields:** Ensure that paths
that are protected with only `isAuthenticated()` do not need any additional
checks based on role or any other condition.
- **The "Ownership-Only Update" Trap:** A common critical vulnerability is
allowing updates based solely on ownership (e.g.,
`allow update: if isOwner(resource.data.uid);`). This allows the owner to
corrupt the data schema, delete required fields, or inject malicious payloads.
You **MUST** always combine ownership checks with data validation (e.g.,
`allow update: if isOwner(...) && isValidEntity(...);`) **AND** validate that
self-escalation is not possible.
- **Deep Array Inspection:** It is insufficient to check if a field `is list`.
You **MUST** validate the contents of the array (e.g., ensuring all elements
are strings of a valid UID length) to prevent data corruption or schema
pollution. For example, a `tags` array must verify that every item is a string
AND that each string is within a reasonable length (e.g., < 20 chars).
- **Permission-Field Lockdown:** Fields that control access (e.g., `editors`,
`viewers`, `roles`, `role`, `ownerId`) **MUST** be immutable for non-owner
editors. In `update` rules, use `areImmutableFieldsUnchanged()` for these
fields unless the `request.auth.uid` matches the document's original
owner/creator. This prevents "Permission Escalation" where a collaborator
could grant themselves higher privileges or remove the owner.
### Advanced Validation for Business Logic
Secure rules must enforce the application's business logic. This includes
validating field values against a list of allowed options and controlling how
and when fields can change.
#### 1. Enforce Enum Values
If a field should only contain specific values (e.g., a status), validate
against a list.
**Example:**
```javascript
// A 'task' document's status can only be one of three values
function isValidStatus() {
let validStatuses = ['pending', 'in-progress', 'completed'];
return request.resource.data.status in validStatuses;
}
allow create: if isValidStatus() && ...
```
#### 2. Validate State Transitions
For `update` operations, you **MUST** validate that a field is changing from a
valid previous state to a valid new state. This prevents users from bypassing
workflows (e.g., marking a task as 'completed' from 'archived').
**Example:**
```javascript
// A task can only be marked 'completed' if it was 'in-progress'
function validStatusTransition() {
let previousStatus = resource.data.status;
let newStatus = request.resource.data.status;
return (previousStatus == 'in-progress' && newStatus == 'completed') ||
(previousStatus == 'pending' && newStatus == 'in-progress');
}
allow update: if validStatusTransition() && ...
```
#### 3. Strict Path and Relationship Scoping
For any field that references another resource (like an image path or a parent
document ID), you **MUST** ensure it is correctly scoped to the user or valid
within the context.
**Example:**
```javascript
// Ensure image path is within the user's own storage folder
allow create: if isScopedPath(request.resource.data.imageBucket) && ...
```
#### 4. Secure Counter Updates
When allowing users to update a counter (like `voteCount` or `answerCount`), you
**MUST** ensure: 1. **Atomic Increments:** The field is only changing by exactly
+1 or -1. 2. **Isolation:** **NO OTHER FIELDS** are being modified. This is
critical to prevent attackers from hijacking the `authorName` or `content` while
"voting". 3. **Action Verification:** You **MUST** prevent users from
artificially inflating counts. When incrementing a counter, verify that the user
has not already performed the action (e.g., by checking for the existence of a
'like' document) and is not looping updates. * **CRITICAL:** Relying solely on
`!exists(likeDoc)` is insufficient because a malicious user can skip creating
the document and loop the increment. * **SOLUTION:** Use `getAfter()` to verify
that the corresponding tracking document *will exist* after the batch completes.
**Example:**
```javascript
function isValidCounterUpdate(docId) {
// Allow update only if 'voteCount' is the ONLY field changing
return request.resource.data.diff(resource.data).affectedKeys().hasOnly(['voteCount']) &&
// And the change is exactly +1 or -1
math.abs(request.resource.data.voteCount - resource.data.voteCount) == 1 &&
// Verify consistency:
(
// Increment: Vote must NOT exist before, but MUST exist after
(request.resource.data.voteCount > resource.data.voteCount &&
!exists(/databases/$(database)/documents/votes/$(request.auth.uid + '_' + docId)) &&
getAfter(/databases/$(database)/documents/votes/$(request.auth.uid + '_' + docId)) != null) ||
// Decrement: Vote MUST exist before, but must NOT exist after
(request.resource.data.voteCount < resource.data.voteCount &&
exists(/databases/$(database)/documents/votes/$(request.auth.uid + '_' + docId)) &&
getAfter(/databases/$(database)/documents/votes/$(request.auth.uid + '_' + docId)) == null)
);
}
allow update: if isValidCounterUpdate(docId) && ...
```
#### 5. **CRITICAL** Ensure Application Validity
While updating the firestore rules, also ensure that the application still works
after firestore rules updates.
1. **For each collection, implement explicit data validation:**
- Type Checking: 'field is string', 'field is number', 'field is bool', 'field
is timestamp'
- Required fields validation using 'hasRequiredFields()'
- **Enforce Size Limits:** For **EVERY** string, list, and map field, you
**MUST** enforce realistic size limits (e.g., `text.size() < 1000`,
`tags.size() < 20`). **Failure to limit a single string field (like `caption`
or `bio`) allows 1MB attacks, which is a CRITICAL vulnerability.**
- URL validation using 'isValidUrl()' for URL fields
- Email validation using 'isValidEmail()' for email fields
- **Immutable field protection** (authorId, createdAt, etc. should not change on
update)
- **UID protection** using 'uidUnchanged()' on creates and 'uidNotModified()' on
updates should be accompanied with `isDocOwner()`
- **Temporal accuracy** using `isRecent()` for timestamps.
- **Range validation** using `isPositive()` or similar for numbers.
- **Path scoping** using `isScopedPath()` for storage paths.
Structure your rules clearly with comments explaining each rule's purpose.
#### Phase-3: Devil's Advocate Attack
**Critical step:** Systematically attempt to break your own rules using the
following attack vectors. You MUST document the outcome of each attempt.
1. **Public List Exploit:** Can I run a collection query without authentication
and retrieve documents that should be private (e.g., where
`visible == false`)?
1. **Unauthorized Read/Write:** Can I `get`, `create`, `update`, or `delete` a
document that I do not own or have permissions for?
1. **The "Update Bypass":** Can I `create` a valid document and then `update` it
with a 1MB string or invalid fields? (Tests if validation logic is missing
from `update`).
1. **Ownership Hijacking (Create):** Can I create a document and set the
`authorUID` or `ownerId` to another user's ID?
1. **Ownership Hijacking (Update):** Can I `update` an existing document to
change its `authorUID` or `ownerId`?
1. **Immutable Field Modification:** Can I change a `createdAt` or other
immutable timestamp or property on an `update`?
1. **Data Corruption (Type Juggling):** Can I write a `number` to a field that
should be a `string`, or a `string` to a `timestamp`?
1. **Validation Bypass (Create vs. Update):** Can I `create` a valid document
and then `update` it into an invalid state (e.g., remove a required field,
write a string that's too long)?
1. **Resource Exhaustion / DoS:** Can I write an enormous string (e.g., 1MB) to
any field that accepts a string or a massive array to a list field? Every
string field (e.g., `bio`, `url`, `name`) MUST have a `.size()` check. If any
are missing, it's a "Resource Exhaustion/DoS" risk.
1. **Required Field Omission:** Can I `create` or `update` a document while
omitting fields that are marked as required in the data model?
1. **Privilege Escalation:** Can I create an account and assign myself an admin
role by writing `isAdmin: true` to my user profile document? (Tests reliance
on document data vs. custom claims).
1. **Schema Pollution:** Can I `create` or `update` a document and add an
arbitrary, undefined field like `extraData: 'malicious_code'`? (Tests for
strict schema enforcement).
1. **Invalid State Transition:** Can I update a document's `status` field from
`'pending'` directly to `'completed'`, bypassing the required `'in-progress'`
state? (Tests business logic enforcement).
1. **Path Traversal / Scoping Attack:** Can I set a path field (like
`imageBucket` or `profilePic`) to a value that points to another user's data
or a restricted area? (Tests for regex path scoping).
1. **Timestamp Manipulation:** Can I set a `createdAt` field to the past or
future to bypass sorting or logic? (Tests for `request.time` validation).
1. **Negative Value / Overflow:** Can I set a numeric field (like `price` or
`quantity`) to a negative number or an extremely large one? (Tests for range
validation).
1. **The "Mixed Content" Leak:** Create a second user. Can User B read User A's
users document? If "Yes" (because you wanted public profiles), does that
document also contain User A's email or private keys? If both are true, the
rules are insecure.
1. **Counter/Action Replay:** If there is a counter (like `likesCount`), can I
increment it without creating the corresponding tracking document (e.g.,
inside `likes/{userId}`)? Can I increment it twice? (Tests for `getAfter()`
consistency checks).
1. **Orphaned Subcollection Access:** Can I read/write to a subcollection (e.g.,
`users/123/posts/456`) if the parent document (`users/123`) does not exist?
(Tests for parent existence checks).
1. **Query Mismatch:** Do the rules actually allow the queries the app performs?
(e.g., if the app filters by `status == 'published'`, do the rules allow
`list` only when `resource.data.status == 'published'`?)
1. **Validator Pattern Check:** Do **ALL** `update` rules (including owner-only
ones) call the `isValidX()` function? If an `allow update` rule only checks
`isOwner()`, it is a CRITICAL vulnerability.
Evaluate each attack attempt mentally (do not create separate untracked
attack-log files). If ANY attack succeeds:
- Fix the security hole
- Regenerate the rules
- **Repeat Phase-3** until no attacks succeed
#### Phase-4: Syntactic Validation
Once devil's advocate testing passes, repeat until rules pass validation.
**After all phases are complete, create or update the `firestore.rules` file.**
### Critical Constraints
1. **Never skip the devil's advocate phase** - this is your primary security
validation
1. **MUST include helper functions** for common operations ('isAuthenticated',
'isOwner', 'uidUnchanged', 'uidNotModified') AND domain validators
('isValidUser', etc.)
1. **MUST document assumed data models** at the beginning of the rules file
1. **Always validate the rules syntax** using 'firebase deploy --only
firestore:rules --dry-run' or a similar tool before outputting the final
file.
1. **Provide complete, runnable code** - no placeholders or TODOs
1. **Document all assumptions** about data structure or access patterns
1. **Always run the devil's advocate attack** after any modification of the
rules.
1. **Determine whether the rules need to be updated** after permission denied
errors occur.
1. **Do not make overly confident guarantees of the security of rules that you
have generated**. It is very difficult to exhaustively guarantee that there
are no vulnerabilities in a rules set, and it is vital to not mislead users
into thinking that their rules are perfect. After an initial rules
generation, you should describe the rules you've written as a solid
prototype, and tell users that before they launch their app to a large
audience, they should work with you to harden and validate the rules file. Be
clear that users should carefully review rules to ensure security.
redis-core
by Redis · MIT · redis/agent-skills@a84871d · 4 files
Redis data types, keys and expiry used the right way.
Read redis-core/SKILL.md
---
name: redis-core
description: Core Redis modeling guidance — choose the right data structure (String, Hash, List, Set, Sorted Set, JSON, Stream, Vector Set) and use consistent colon-separated key names. Use when designing a Redis data model, caching objects, deciding between Hash and JSON, building counters, leaderboards, membership sets, or session stores, or when reviewing/cleaning up Redis key naming.
license: MIT
metadata:
author: Redis, Inc.
version: "0.1.0"
---
# Redis Core
Foundational guidance for modeling data in Redis. Covers data-type selection and key-name conventions — the two decisions that most directly drive memory, performance, and maintainability.
## When to apply
- Caching objects, sessions, or per-user state.
- Counters, leaderboards, recent-items lists, unique-membership sets.
- Reviewing or refactoring Redis key names.
- Deciding between a Redis Hash and a JSON document for an entity.
## 1. Choose the right data structure
Pick the type that matches the *access pattern*, not just the shape of the data.
| Use case | Recommended type | Why |
|---|---|---|
| Simple values, counters | String | Atomic `INCR`/`DECR`, `SET`/`GET` |
| Object with independently updated fields | Hash | Per-field reads/writes, no whole-object rewrite |
| Queue, recent-N items | List | O(1) push/pop at ends |
| Unique items, membership checks | Set | O(1) `SADD`/`SISMEMBER`/`SCARD` |
| Rankings, score-based ranges | Sorted Set | Score-ordered; `ZADD`/`ZRANGE`/`ZRANK` |
| Nested / hierarchical data | JSON | Path-level updates, nested arrays, RQE indexing |
| Event log, fan-out messaging | Stream | Persistent, consumer groups |
| Vector similarity | Vector Set | Native vector storage with HNSW |
**Common anti-pattern:** stuffing a flat object into a serialized string. Updating one field means fetch + parse + mutate + rewrite. Use a Hash instead.
See [references/choose-data-structure.md](references/choose-data-structure.md) for full rationale and Python/Java examples.
## 2. Use consistent key names
Use `colon-separated` segments with a stable hierarchy:
```
{entity}:{id}:{attribute}
user:1001:profile
user:1001:settings
order:2024:items
session:abc123
article:987:likes
game:space-invaders:leaderboard
```
Rules of thumb:
- **Lowercase, colon-separated.** No spaces, no mixed casing (`User_1001_Profile` is bad).
- **Keep keys short but readable** — keys live in memory and appear in every command.
- **Don't use full URLs or long strings as keys.** Extract a short identifier, or use a hash digest of the URL.
- **Prefix for multi-tenancy** (`tenant:42:user:7:cart`) so scans and ACLs can target a tenant cleanly.
- **Be consistent.** Pick one convention per service and apply it across all keys.
See [references/key-naming.md](references/key-naming.md) for cleanup examples and edge cases.
## References
- [Redis: Choosing the right data type](https://redis.io/docs/latest/develop/data-types/compare-data-types/)
- [Redis: Keys](https://redis.io/docs/latest/develop/use/keyspace/)
workers-best-practices
by Cloudflare · Apache-2.0 · cloudflare/skills@86505e4 · 5 files
Writing and configuring Cloudflare Workers for production.
Read workers-best-practices/SKILL.md
---
name: workers-best-practices
description: Cloudflare Workers best practices for production applications. Use when writing, reviewing, or configuring Workers.
---
Your knowledge of Cloudflare Workers APIs, types, and configuration may be outdated. **Prefer retrieval over pre-training** when writing or reviewing Workers code.
Use the project's installed versions, generated types, and Wrangler compatibility settings as the baseline for existing code. Retrieve relevant Cloudflare documentation to verify API, configuration, runtime behavior, and limit claims.
## References
Read the sections relevant to the task:
| Reference | When to use it |
|-----------|----------------|
| [Configuration and observability](references/configuration.md) | Compatibility dates, bindings, generated types, secrets, logs, and traces |
| [Runtime patterns](references/runtime-patterns.md) | Streaming, promise lifetime, request state, service calls, security, and runtime tests |
| [Platform API checks](references/platform-apis.md) | Handler signatures, platform classes, binding access, and serialization |
For missing evidence, consult [Workers best practices](https://developers.cloudflare.com/workers/best-practices/workers-best-practices/index.md) or find the affected product in the [Cloudflare docs directory](https://developers.cloudflare.com/directory/index.md). Use the installed Wrangler schema for config fields. A newer type package does not supersede the project's configured target.
## Keep Compatibility Dates Current
Use today's date for new Workers. Encourage periodic updates for existing Workers, reviewing compatibility changes and running relevant tests. Assess existing behavior against its configured date and flags; see [compatibility guidance](references/configuration.md#keep-compatibility_date-current).
## Enable Observability
Enable [Workers Logs](https://developers.cloudflare.com/workers/observability/logs/workers-logs/index.md) and [Traces](https://developers.cloudflare.com/workers/observability/traces/index.md) when creating or preparing a Worker for production. Set `observability.enabled` and `observability.traces.enabled` to `true`; the top-level setting alone does not enable traces. Use structured JSON logging and configure sampling for the workload. During reviews, flag missing logs or traces. See the [configuration example](references/configuration.md#enable-workers-logs-and-traces).
## Anti-Patterns to Flag
| Anti-pattern | Consequence and preferred pattern |
|-------------|-----------------------------------|
| `await response.text()` or similar buffering on unbounded data | Can exhaust Worker memory; [stream large or unbounded bodies](references/runtime-patterns.md#stream-request-and-response-bodies). |
| Hardcoded secrets in source or config | Leaks credentials through version control; use Wrangler secrets. |
| `Math.random()` for security-sensitive tokens or IDs | Predictable values; use `crypto.randomUUID()` or `crypto.getRandomValues()`. |
| Async work started without awaiting, returning, or attaching it to `ctx.waitUntil()` | Work can be dropped and errors missed; tie it to the request or background-work lifetime. |
| Module-level mutable request state | Leaks data across requests and can cause I/O ownership errors; pass request state explicitly. |
| Cloudflare REST API calls for operations available through Worker bindings | Adds network and authentication overhead; use the available binding. |
| `ctx.passThroughOnException()` used as general error handling | Can conceal Worker failures by forwarding to the origin; use explicit error handling and structured error responses. |
| Hand-written `Env` that duplicates Wrangler bindings | Can drift from configuration; generate binding types with `wrangler types`. |
| Direct string comparison of secret values | Can expose timing differences; use the [Web Crypto comparison pattern](references/runtime-patterns.md#use-web-crypto-for-secure-token-generation). |
| Destructuring `ctx` methods, such as `const { waitUntil } = ctx` | Loses the receiver; call `ctx.waitUntil(...)`. |
| `any` on `Env` or handler parameters | Hides binding and handler contract errors; use the project's generated and platform types. |
| `as unknown as T` to force a platform type match | Hides incompatibilities; fix the underlying contract. |
| `implements` used in place of extending a platform base class | Does not inherit runtime behavior, `this.ctx`, or `this.env`; use the appropriate base class. |
| Unbound `env.X` in a platform class method | Bindings are available through `this.env.X`; see [binding access patterns](references/platform-apis.md#binding-access--the-most-common-error). |
| Applying one serialization rule across Queues, Workflow steps, storage, and WebSockets | Can reject valid payloads or accept unsupported ones; check the [specific API and encoding](references/platform-apis.md#serialization-boundaries). |
## Validation
Use the project's existing checks for affected Workers behavior: type-check binding or handler contract changes, and run relevant runtime tests for behavior changes. Preserve required repository checks; a narrow edit does not require a full Workers audit.
## Scope
This skill covers Workers-specific best practices and code review. For related topics:
- **Durable Objects**: load the `durable-objects` skill
- **Workflows**: see [Rules of Workflows](https://developers.cloudflare.com/workflows/build/rules-of-workflows/index.md)
- **CLI commands**: load the `cf-cli` skill, or the `wrangler` skill in a project with a Wrangler configuration file
email-best-practices
by Resend · MIT · resend/resend-skills@b2ae7b1 · 13 files
Sending email that arrives: domains, templates, bounces.
Read email-best-practices/SKILL.md
---
name: email-best-practices
description: Use when building email features, emails going to spam, high bounce rates, setting up SPF/DKIM/DMARC authentication, implementing email capture, ensuring compliance (CAN-SPAM, GDPR, CASL), handling webhooks, retry logic, making emails accessible (alt text, headings, contrast, screen readers), or deciding transactional vs marketing.
license: MIT
metadata:
author: Resend
version: "1.0.2"
homepage: https://resend.com/agent-skills
source: https://github.com/resend/email-best-practices
openclaw:
links:
repository: https://github.com/resend/email-best-practices
documentation: https://resend.com/docs/email-best-practices-skill
---
# Email Best Practices
Guidance for building deliverable, compliant, user-friendly emails.
## Architecture Overview
```
[User] → [Email Form] → [Validation] → [Double Opt-In]
↓
[Consent Recorded]
↓
[Suppression Check] ←──────────────[Ready to Send]
↓
[Idempotent Send + Retry] ──────→ [Email API]
↓
[Webhook Events]
↓
┌────────┬────────┬─────────────┐
↓ ↓ ↓ ↓
Delivered Bounced Complained Opened/Clicked
↓ ↓
[Suppression List Updated]
↓
[List Hygiene Jobs]
```
## Quick Reference
| Need to... | See |
|------------|-----|
| Set up SPF/DKIM/DMARC, fix spam issues | [Deliverability](./references/deliverability.md) |
| Build password reset, OTP, confirmations | [Transactional Emails](./references/transactional-emails.md) |
| Plan which emails your app needs | [Transactional Email Catalog](./references/transactional-email-catalog.md) |
| Build newsletter signup, validate emails | [Email Capture](./references/email-capture.md) |
| Send newsletters, promotions | [Marketing Emails](./references/marketing-emails.md) |
| Ensure CAN-SPAM/GDPR/CASL compliance | [Compliance](./references/compliance.md) |
| Decide transactional vs marketing | [Email Types](./references/email-types.md) |
| Handle retries, idempotency, errors | [Sending Reliability](./references/sending-reliability.md) |
| Process delivery events, set up webhooks | [Webhooks & Events](./references/webhooks-events.md) |
| Manage bounces, complaints, suppression | [List Management](./references/list-management.md) |
| Make emails accessible (screen readers, alt text, contrast) | [Accessibility](./references/accessibility.md) |
## Start Here
**New app?**
Start with the [Catalog](./references/transactional-email-catalog.md) to plan which emails your app needs (password reset, verification, etc.), then set up [Deliverability](./references/deliverability.md) (DNS authentication) before sending your first email.
**Spam issues?**
Check [Deliverability](./references/deliverability.md) first—authentication problems are the most common cause. Gmail/Yahoo reject unauthenticated emails.
**Marketing emails?**
Follow this path: [Email Capture](./references/email-capture.md) (collect consent) → [Compliance](./references/compliance.md) (legal requirements) → [Marketing Emails](./references/marketing-emails.md) (best practices).
**Production-ready sending?**
Add reliability: [Sending Reliability](./references/sending-reliability.md) (retry + idempotency) → [Webhooks & Events](./references/webhooks-events.md) (track delivery) → [List Management](./references/list-management.md) (handle bounces).
**Accessibility?**
Most emails fail basic accessibility checks. See [Accessibility](./references/accessibility.md) for `lang`/`dir`, presentational tables, headings, alt text, `<title>`, and contrast.
react-email
by Resend · MIT · resend/resend-skills@b2ae7b1 · 8 files
Email templates as React components. Sends nothing by itself; the API key stays in .env.
Read react-email/SKILL.md
---
name: react-email
description: Use when building HTML email templates with React components, adding a visual email editor to an application using the React Email visual editor, rendering emails to HTML, or sending emails with Resend. Covers welcome emails, password resets, notifications, order confirmations, newsletters, transactional emails, and the embeddable email editor component.
license: MIT
metadata:
author: Resend
version: "2.1.0"
homepage: https://react.email
source: https://github.com/resend/react-email
openclaw:
install:
- kind: node
package: react-email
label: React Email
links:
repository: https://github.com/resend/react-email
documentation: https://resend.com/docs/react-email-skill
---
# React Email
Build and send HTML emails using React components. A modern, component-based approach to email development that works across all major email clients.
## Installation
```sh
npm i react-email
```
Or scaffold a new project:
```sh
npx create-email@latest
cd react-email-starter
npm install
npm run dev
```
This works with any package manager (npm, yarn, pnpm, bun) — substitute accordingly.
The dev server runs at localhost:3000 with a preview interface for templates in the `emails` folder.
### Adding to an Existing Project
Install the packages and add a script to your `package.json`:
```json
{
"scripts": {
"email": "email dev --dir emails --port 3000"
}
}
```
Make sure the path to the emails folder is relative to the base project directory. Ensure `tsconfig.json` includes proper support for JSX.
## Basic Email Template
Create an email component with proper structure using the Tailwind component for styling:
```tsx
import {
Html,
Head,
Preview,
Body,
Container,
Heading,
Text,
Button,
Tailwind,
pixelBasedPreset
} from 'react-email';
interface WelcomeEmailProps {
name: string;
verificationUrl: string;
}
export default function WelcomeEmail({ name, verificationUrl }: WelcomeEmailProps) {
return (
<Html lang="en">
<Tailwind
config={{
presets: [pixelBasedPreset],
theme: {
extend: {
colors: {
brand: '#007bff',
},
},
},
}}
>
<Head />
<Body className="bg-gray-100 font-sans">
<Preview>Welcome - Verify your email</Preview>
<Container className="max-w-xl mx-auto p-5">
<Heading className="text-2xl text-gray-800">
Welcome!
</Heading>
<Text className="text-base text-gray-800">
Hi {name}, thanks for signing up!
</Text>
<Button
href={verificationUrl}
className="bg-brand text-white px-5 py-3 rounded block text-center no-underline box-border"
>
Verify Email
</Button>
</Container>
</Body>
</Tailwind>
</Html>
);
}
// Preview props for testing
WelcomeEmail.PreviewProps = {
name: 'John Doe',
verificationUrl: 'https://example.com/verify/abc123'
} satisfies WelcomeEmailProps;
export { WelcomeEmail };
```
## Behavioral Guidelines
- When iterating over the code, only update what the user asked for. Keep the rest intact.
- If the user asks to use media queries, inform them that most email clients don't support them and suggest a different approach.
- Never use template variables (like `{{name}}`) directly in TypeScript code. Instead, reference the underlying properties directly. If the user explicitly asks for `{{variableName}}`, place the mustache string only in PreviewProps, never in the component JSX:
```typescript
const EmailTemplate = (props) => {
return (
<h1>Hello, {props.variableName}!</h1>
);
}
EmailTemplate.PreviewProps = {
variableName: "{{variableName}}",
};
export default EmailTemplate;
```
- Never write the `{{variableName}}` pattern directly in the component structure. If the user insists, explain that this would make the template invalid.
## Essential Components
See [references/COMPONENTS.md](references/COMPONENTS.md) for complete component documentation.
**Core Structure:**
- `Html` - Root wrapper with `lang` attribute
- `Head` - Meta elements, styles, fonts
- `Body` - Main content wrapper
- `Container` - Outermost centering wrapper (has built-in `max-width: 37.5em`). Use only once per email.
- `Section` - Interior content blocks (no built-in max-width). Use for grouping content inside `Container`.
- `Row` & `Column` - Multi-column layouts
- `Tailwind` - Enables Tailwind CSS utility classes
**Content:**
- `Preview` - Inbox preview text, always first inside `<Body>`
- `Heading` - h1-h6 headings
- `Text` - Paragraphs
- `Button` - Styled link buttons (always include `box-border`)
- `Link` - Hyperlinks
- `Img` - Images (see Static Files section below)
- `Hr` - Horizontal dividers
**Specialized:**
- `CodeBlock` - Syntax-highlighted code
- `CodeInline` - Inline code
- `Markdown` - Render markdown
- `Font` - Custom web fonts
## Before Writing Code
When a user requests an email template, ask clarifying questions FIRST if they haven't provided:
1. **Brand colors** - Ask for primary brand color (hex code like #007bff)
2. **Logo** - Ask if they have a logo file and its format (PNG/JPG only - warn if SVG/WEBP)
3. **Style preference** - Professional, casual, or minimal tone
4. **Production URL** - Where will static assets be hosted in production?
## Static Files and Images
### Directory Structure
Local images must be placed in the `static` folder inside your emails directory:
```
project/
├── emails/
│ ├── welcome.tsx
│ └── static/ <-- Images go here
│ └── logo.png
```
### Dev vs Production URLs
Use this pattern for images that work in both dev preview and production:
```tsx
const baseURL = process.env.NODE_ENV === "production"
? "https://cdn.example.com" // User's production CDN
: "";
export default function Email() {
return (
<Img
src={`${baseURL}/static/logo.png`}
alt="Logo"
width="150"
height="50"
/>
);
}
```
**How it works:**
- **Development:** `baseURL` is empty, so URL is `/static/logo.png` - served by React Email's dev server
- **Production:** `baseURL` is the CDN domain, so URL is `https://cdn.example.com/static/logo.png`
**Important:** Always ask the user for their production hosting URL. Do not hardcode `localhost:3000`.
## Styling
See [references/STYLING.md](references/STYLING.md) for comprehensive styling documentation including typography, layout patterns, dark mode, and brand consistency.
### Key Rules
- Use `Tailwind` with `pixelBasedPreset` (email clients don't support `rem`). Import `pixelBasedPreset` from `react-email`.
- Never use flexbox or grid — use `Row`/`Column` components or tables for layouts.
- Avoid CSS/Tailwind media queries (`sm:`, `md:`, `lg:`, `xl:`) — limited email client support.
- Never use theme selectors (`dark:`, `light:`) — not supported.
- Never use SVG or WEBP images — warn users about rendering issues.
- Always specify border type (`border-solid`, `border-dashed`, etc.) — email clients don't inherit it.
- For single-side borders, reset others first (`border-none border-l border-solid`).
### Required Classes
| Component | Required Class | Why |
|-----------|---------------|-----|
| `Button` | `box-border` | Prevents padding from overflowing the button width |
| `Hr` / any border | `border-solid` (or `border-dashed`, etc.) | Email clients don't inherit border type |
| Single-side borders | `border-none` + the side | Resets default borders on other sides |
### Structure Notes
- Always define `<Head />` inside `<Tailwind>` when using Tailwind CSS
- `<Preview>` should always be the first element inside `<Body>`
- Only include props in `PreviewProps` that the component actually uses
- Use fixed width/height for known-size elements (logos, icons); responsive sizing (`w-full`, `h-auto`) for content images
## Rendering
### Convert to HTML
```tsx
import { render } from 'react-email';
import { WelcomeEmail } from './emails/welcome';
const html = await render(
<WelcomeEmail name="John" verificationUrl="https://example.com/verify" />
);
```
### Convert to Plain Text
```tsx
const text = await render(<WelcomeEmail name="John" verificationUrl="https://example.com/verify" />, { plainText: true });
```
## Sending
React Email supports sending with any email service provider. See [references/SENDING.md](references/SENDING.md) for complete sending documentation including Resend, Nodemailer, and SendGrid examples.
Quick example using the Resend SDK:
```tsx
import { Resend } from 'resend';
import { WelcomeEmail } from './emails/welcome';
const resend = new Resend(process.env.RESEND_API_KEY);
const { data, error } = await resend.emails.send({
from: 'Acme <onboarding@resend.dev>',
to: ['user@example.com'],
subject: 'Welcome to Acme',
react: <WelcomeEmail name="John" verificationUrl="https://example.com/verify" />
});
```
The Resend Node SDK automatically handles both HTML and plain-text rendering.
## CLI Commands
The `react-email` package provides a CLI accessible via the `email` command:
| Command | Description |
|---------|-------------|
| `email dev --dir <path> --port <port>` | Start the preview development server (default: `./emails`, port 3000) |
| `email build --dir <path>` | Build the preview app for production deployment |
| `email start` | Run the built preview app |
| `email export --outDir <path> --pretty --plainText --dir <path>` | Export templates to static HTML files |
| `email resend setup` | Connect the CLI to your Resend account via API key |
| `email resend reset` | Remove the stored Resend API key |
## Internationalization
See [references/I18N.md](references/I18N.md) for complete i18n documentation. React Email supports three libraries: next-intl, react-i18next, and react-intl.
## Email Editor
React Email includes a visual editor (`@react-email/editor`) that can be embedded in your app. It's built on TipTap/ProseMirror and produces email-ready HTML.
See [references/EDITOR.md](references/EDITOR.md) for complete documentation including:
- `EmailEditor` — batteries-included component with bubble menus, slash commands, and theming
- `StarterKit` — 35+ email-aware extensions (headings, lists, tables, columns, buttons, etc.)
- `Inspector` — contextual sidebar for editing styles
- `EmailTheming` — built-in themes (`basic`, `minimal`) with customizable CSS properties
- `composeReactEmail` — export editor content to email-ready HTML and plain text
- Custom extensions via `EmailNode` and `EmailMark`
Quick example:
```tsx
import { EmailEditor, type EmailEditorRef } from '@react-email/editor';
import '@react-email/editor/themes/default.css';
import { useRef } from 'react';
export function MyEditor() {
const ref = useRef<EmailEditorRef>(null);
return (
<EmailEditor
ref={ref}
content="<p>Start typing...</p>"
theme="basic"
/>
);
}
```
## Common Patterns
See [references/PATTERNS.md](references/PATTERNS.md) for complete examples including:
- Password reset emails
- Order confirmations with product lists
- Notification emails with code blocks
- Multi-column layouts
- Team invitation emails
## Email Best Practices
1. **Test across email clients** - Gmail, Outlook, Apple Mail, Yahoo Mail
2. **Keep it responsive** - Max-width around 600px, test on mobile
3. **Use absolute image URLs** - Host on reliable CDN
4. **Write meaningful alt text** - Describe purpose and details for content images; use `alt=""` for decorative images (spacers, dividers, background flourishes). React Email's `<Img>` defaults to `alt=""`.
5. **Provide plain text version** - Required for accessibility
6. **Keep file size under 102KB** - Gmail clips larger emails
7. **Add proper TypeScript types** - Define interfaces for all email props
8. **Include preview props** - Add `.PreviewProps` for development testing
9. **Use verified domains** - For production `from` addresses
### Accessibility
React Email handles the structural defaults; the rest is content.
**What React Email gives you for free:**
- `<Html>` sets `lang` and `dir` (defaults: `lang="en" dir="ltr"` — override per locale)
- `<Img>` defaults to `alt=""` so decorative images are skipped by screen readers
- `<Markdown>` renders layout tables with `role="presentation"`
- `<Preview>` also emits a `<title>` tag
Upgrade with `npm install react-email@latest` to get these defaults.
**What you still have to do (content choices):**
- Open with a single `<Heading as="h1">`, nest subheadings in order, never skip levels (very short SMS-style emails may skip the heading entirely)
- Set descriptive `alt` on meaningful images; pass an explicit `alt=""` on decorative images — never omit the attribute
- **Linked images are never decorative.** When an `<Img>` is inside a `<Link>` or `<Button>`, the `alt` must describe where the link goes — `alt=""` on a linked image leaves the link with no accessible name
- Write link text that describes the destination (`<Button>Read the report</Button>`, not `click here`)
- Hit 4.5:1 text contrast (WCAG AA); preview in dark mode
- For layout tables you build by hand (outside `<Markdown>`), add `role="presentation"`
- For non-English emails, pass the locale: `<Html lang={locale} dir={isRTL ? 'rtl' : 'ltr'}>` (see [I18N.md](references/I18N.md))
For the full rule set, severity ranking, and authoring checklist, see the [accessibility reference](https://github.com/resend/email-best-practices/blob/main/references/accessibility.md) in the `email-best-practices` skill.
## Additional Resources
- [React Email Documentation](https://react.email/docs/llms.txt)
- [React Email GitHub](https://github.com/resend/react-email)
- [Resend Documentation](https://resend.com/docs/llms.txt)
- [Email Client CSS Support](https://www.caniemail.com)
- Component Reference: [references/COMPONENTS.md](references/COMPONENTS.md)
- Styling Guide: [references/STYLING.md](references/STYLING.md)
- Email Editor: [references/EDITOR.md](references/EDITOR.md)
- Sending Guide: [references/SENDING.md](references/SENDING.md)
- Internationalization Guide: [references/I18N.md](references/I18N.md)
- Common Patterns: [references/PATTERNS.md](references/PATTERNS.md)
mongodb-query-optimizer
by MongoDB · Apache-2.0 · mongodb/agent-skills@155bb9c · 6 files
Finds why a MongoDB query is slow; creates indexes only with the student's approval.
Read mongodb-query-optimizer/SKILL.md
---
name: mongodb-query-optimizer
description: >-
Help with MongoDB query optimization and indexing. Use only when the user asks for optimization or performance: "How do I optimize this query?", "How do I index this?", "Why is this query slow?", "Can you fix my slow queries?", "What are the slow queries on my cluster?", etc. Do not invoke for general MongoDB query writing unless user asks for performance or index help. Prefer indexing as optimization strategy. Use MongoDB MCP when available.
compatibility: >-
Best with MongoDB MCP server. Uses collection-indexes and explain when the connection string works; uses Atlas Performance Advisor when Atlas API is configured. Without either, suggest indexes from query shape only. User creates indexes in Atlas or migrations unless tooling allows otherwise.
license: Apache-2.0
metadata:
version: "1.0.0"
---
# MongoDB Query Optimizer
## When this skill is invoked
Invoke **only** when the user wants:
- Query/index **optimization** or **performance** help
- **Why** a query is slow or **how to speed it up**
- **Slow queries** on their cluster and/or **how to optimize them**
Do **not** invoke for routine query authoring unless the user has requested help with optimization, slow queries, or indexing.
## High Level Workflow
### General Performance Help
If the user wants to examine slow queries, or is looking for general performance suggestions (not regarding any particular query):
- Use MongoDB MCP server **atlas-get-performance-advisor** tool to fetch slow query logs and performance advisor output
- Make suggestions based on this information
If Atlas MCP Server for Atlas is not configured or you don’t have enough information to run **atlas-get-performance-advisor** against the correct cluster, tell the user that general performance analysis requires Atlas MCP Server configuration with API credentials, and suggest they configure it or ask about a specific query instead.
### Help with a Specific Query
If the user is asking about a particular query:
- Use **collection-indexes**, **explain**, and **find** MCP tools to get existing indexes on the collection, explain() output for the query, and a sample document from the collection
- Use **atlas-get-performance-advisor MCP** tool to fetch slow query logs and performance advisor output
Then make an optimization suggestion based on collected information and MongoDB best practices and examples from reference files. Prefer creating an index that fully covers the query if possible. If you cannot use MongoDB MCP Server then still try to make a suggestion.
## MCP: available tools
**How to invoke.** Call the **MongoDB MCP server** with the **exact tool name** as `toolName` and a single **arguments object** as `arguments`. Do not pass the tool name as an option, query param, or nested key; pass it as the MCP tool name and the parameters as the arguments object. Full MCP Server tool reference: [MongoDB MCP Server Tools](https://www.mongodb.com/docs/mcp-server/tools/).
**Database tools** (when the MCP cluster connection works):
| Tool name (exact) | Arguments object |
| :---- | :---- |
| `collection-indexes` | `{ "database": "<db>", "collection": "<coll>" }` — both required strings. |
| `explain` | `{ "database": "<db>", "collection": "<coll>", "method": [ { "name": "find", "arguments": { "filter": {...}, "sort": {...}, "limit": N } } ], "verbosity": "executionStats" }`. `method` is an array of one object: `name` is `"find"`, `"aggregate"`, or `"count"`; `arguments` holds that method's params (e.g. find: `filter`, `sort`, `limit`; aggregate: `pipeline`; count: `query`). Optional `verbosity`: `"queryPlanner"` (default), `"executionStats"`, `"queryPlannerExtended"`, `"allPlansExecution"`. |
| `find` | `{ "database": "<db>", "collection": "<coll>", "filter": {...}, "projection": {...}, "sort": {...}, "limit": N }` — `database`, `collection`, and `filter` are required. Optional: `projection`, `sort`, `limit`. |
**Atlas tools** (when Atlas API credentials are configured):
| Tool name (exact) | Arguments object |
| :---- | :---- |
| `atlas-list-projects` | `{}` or `{ "orgId": "<24-char hex>" }`. Returns projects with their IDs; use to get `projectId` for Performance Advisor. |
| `atlas-get-performance-advisor` | **Required:** `"projectId"` (24-character hex string), `"clusterName"` (string, 1–64 chars, alphanumeric/underscore/dash). **Optional:** `"operations"` — array of strings from `"suggestedIndexes"`, `"dropIndexSuggestions"`, `"slowQueryLogs"`, `"schemaSuggestions"` (request only what you need); for slowQueryLogs only: `"since"` (ISO 8601 date-time), `"namespaces"` (array of `"db.coll"` strings). |
For a user question, try to fetch information from both the connection string and Atlas API related to the query you are optimizing.
### 1\. DB connection string works for MongoDB MCP
Typical flow: call `collection-indexes` → `explain` → `find` (sample doc).
- **`collection-indexes`** — Use the result's `classicIndexes` (each has `name`, `key`) to see if the query can already use an existing index.
- **`explain`** — Run in `"queryPlanner"` mode first to check for COLLSCAN. If the query uses an index or the collection is very small, run again with `"executionStats"` (10-second timeout) to get docs scanned vs. returned.
### 2\. Atlas API access works for MongoDB MCP
If you need a project ID, call `atlas-list-projects` first. Then call `atlas-get-performance-advisor` with only the `operations` you need:
| Operation value | Use when |
| :---- | :---- |
| `slowQueryLogs` | Fetching slow queries—**prioritize by slowest and most frequent**. Optional: `namespaces` to scope to a collection; `since` for a time window. |
| `suggestedIndexes` | Fetching cluster index recommendations |
| `dropIndexSuggestions` | User asks what to remove or reduce index overhead |
| `schemaSuggestions` | User asks for schema/query-structure advice alongside indexes |
Do not pass the MCP tool name as an `operations` value—`operations` is a separate argument listing what data to fetch.
## Example workflow 1 (help with specific query)
**User:** "Why is this query slow? `db.orders.find({status: 'shipped', region: 'US'}).sort({date: -1})`"
**If MCP db connection is configured and the database + collection names are known**, run steps 1–3. Otherwise skip to step 4.
1. **Check existing collection indexes:**
- Call `collection-indexes` with database=`store`, collection=`orders`
- Result shows: `{_id: 1}`, `{status: 1}`, `{date: -1}`
2. **Run explain:**
- Call `explain` with method=`find`, filter=`{status: 'shipped', region: 'US'}`, sort=`{date: -1}`, verbosity=`queryPlanner` and `executionStats`
- Result: Uses `{status: 1}` index, then in-memory SORT, `totalKeysExamined: 50000`, `nReturned: 100`
3. **Run find:**
- Call `find` with limit=1 to fetch a sample document to impute the schema.
**If MCP Atlas connection is configured**, run step 4. Otherwise skip to step 5.
4. **Run atlas-get-performance-advisor:**
- Try to get the cluster name from the MCP connection string, or ask the user for projectId/clusterName
- Use slowQueryLogs to fetch slow query logs from database=`store`, collection=`orders` in the past 24 hours
- Use suggestedIndexes to check for index suggestions for the query
5. **Diagnose:** Based on explain output and slow query logs, this query targets 100 docs but scans 50K index entries (poor selectivity: 0.002). In-memory sort adds overhead. Index doesn't support both filter fields or sort.
6. **Recommend:** Create compound index `{status: 1, region: 1, date: -1}` following ESR (two equality fields, then sort). This eliminates in-memory sort and improves selectivity by filtering on both status and region.
If the MongoDB MCP server is not set up, follow best indexing practices.
## Example workflow 2 (general database performance help)
**User:** "Can you help with optimizing slow queries on my cluster?”
1. **Run atlas-get-performance-advisor:**
- Try to get the cluster name from the connection string and deduce the project name you need in atlas-list-projects; if you are not sure, then ask the user for cluster name and project id.
- Use slowQueryLogs to fetch slow query logs from the past 24 hours
- Use suggestedIndexes
- Use dropIndexSuggestions
- Use schemaSuggestions
2. **Diagnose and Recommend:** Based on slow query logs and performance advisor advice, you can create the compound index `{status: 1, region: 1, date: -1}` on the `db.orders` collection to optimize queries such as `find({status: 'shipped', region: 'US'}).sort({date: -1})`
Examine all performance advisor output as well as slow query logs. Provide information on what is being improved and why, and focus on suggestions that have the potential for greatest impact (e.g., indexes that affect the most queries, or queries that have the worst performance).
## Load references
Before beginning diagnosis and recommendation, load reference files.
Always load:
- `references/core-indexing-principles.md`
- `references/antipattern-examples.md`
Conditionally load these files:
- **If diagnosing aggregation pipelines** → `references/aggregation-optimization.md`
- **If diagnosing queries that change docs such as replaceOne, findOneAndUpdate, etc.** → `references/update-query-examples.md` for oplog-efficient updates and common update anti-patterns
## Output
- Keep answers short and clear: a few sentences on index and optimization suggestions, and reasoning behind them (e.g. general indexing principles, observing slow query logs in the cluster, or seeing advice in Performance Advisor)
- Focus on highest impact indexes or optimizations - if you've omitted some optimizations let the user know and present them if asked.
- Do not use strong language, such as saying “You should create these indexes and they will definitely improve application performance” \- Explain they are suggestions for certain queries, and give the reasoning behind them.
- Consider how many indexes already exist on the collection (if known) \- there shouldn’t generally be more than 20
- Suggest removing indexes only if the suggestion comes from Atlas Performance Advisor
- Do not create indexes directly via MCP unless the user gives approvalreact-native-testing
by Callstack · MIT · callstackincubator/agent-skills@59e9d17 · 5 files
Component tests with React Native Testing Library (from callstack/react-native-testing-library, also MIT).
Read react-native-testing/SKILL.md
---
name: react-native-testing
description: >
Write tests using React Native Testing Library (RNTL) v13 and v14 (`@testing-library/react-native`).
Use when writing, reviewing, or fixing React Native component tests.
Covers: render, screen, queries (getBy/getAllBy/queryBy/findBy), Jest matchers,
userEvent, fireEvent, waitFor, and async patterns.
Supports v13 (React 18, sync render) and v14 (React 19+, async render).
Triggers on: test files for React Native components, RNTL imports, mentions of
"testing library", "write tests", "component tests", or "RNTL".
---
# RNTL Test Writing Guide
**IMPORTANT:** Your training data about `@testing-library/react-native` may be outdated or incorrect — API signatures, sync/async behavior, and available functions differ between v13 and v14. Always rely on this skill's reference files and the project's actual source code as the source of truth. Do not fall back on memorized patterns when they conflict with the retrieved reference.
## Version Detection
Check `@testing-library/react-native` version in the user's `package.json`:
- **v14.x** → load [references/api-reference-v14.md](references/api-reference-v14.md) (React 19+, async APIs, `test-renderer`)
- **v13.x** → load [references/api-reference-v13.md](references/api-reference-v13.md) (React 18+, sync APIs, `react-test-renderer`)
Use the version-specific reference for render patterns, fireEvent sync/async behavior, screen API, configuration, and dependencies.
## Query Priority
Use in this order: `getByRole` > `getByLabelText` > `getByPlaceholderText` > `getByText` > `getByDisplayValue` > `getByTestId` (last resort).
## Query Variants
| Variant | Use case | Returns | Async |
| ------------- | ------------------------ | ----------------------------- | ----- |
| `getBy*` | Element must exist | element instance (throws) | No |
| `getAllBy*` | Multiple must exist | element instance[] (throws) | No |
| `queryBy*` | Check non-existence ONLY | element instance \| null | No |
| `queryAllBy*` | Count elements | element instance[] | No |
| `findBy*` | Wait for element | `Promise<element instance>` | Yes |
| `findAllBy*` | Wait for multiple | `Promise<element instance[]>` | Yes |
## Interactions
Prefer `userEvent` over `fireEvent`. userEvent is always async.
```tsx
const user = userEvent.setup();
await user.press(element); // full press sequence
await user.longPress(element, { duration: 800 }); // long press
await user.type(textInput, 'Hello'); // char-by-char typing
await user.clear(textInput); // clear TextInput
await user.paste(textInput, 'pasted text'); // paste into TextInput
await user.scrollTo(scrollView, { y: 100 }); // scroll
```
`fireEvent` — use only when `userEvent` doesn't support the event. See version-specific reference for sync/async behavior:
```tsx
fireEvent.press(element);
fireEvent.changeText(textInput, 'new text');
fireEvent(element, 'blur');
```
## Assertions (Jest Matchers)
Available automatically with any `@testing-library/react-native` import.
| Matcher | Use for |
| ------------------------------------------ | ----------------------------------------- |
| `toBeOnTheScreen()` | Element exists in tree |
| `toBeVisible()` | Element visible (not hidden/display:none) |
| `toBeEnabled()` / `toBeDisabled()` | Disabled state via `aria-disabled` |
| `toBeChecked()` / `toBePartiallyChecked()` | Checked state |
| `toBeSelected()` | Selected state |
| `toBeExpanded()` / `toBeCollapsed()` | Expanded state |
| `toBeBusy()` | Busy state |
| `toHaveTextContent(text)` | Text content match |
| `toHaveDisplayValue(value)` | TextInput display value |
| `toHaveAccessibleName(name)` | Accessible name |
| `toHaveAccessibilityValue(val)` | Accessibility value |
| `toHaveStyle(style)` | Style match |
| `toHaveProp(name, value?)` | Prop check (last resort) |
| `toContainElement(el)` | Contains child element |
| `toBeEmptyElement()` | No children |
## Rules
1. **Use `screen`** for queries, not destructuring from `render()`
2. **Use `getByRole` first** with `{ name: '...' }` option
3. **Use `queryBy*` ONLY** for `.not.toBeOnTheScreen()` checks
4. **Use `findBy*`** for async elements, NOT `waitFor` + `getBy*`
5. **Never put side-effects in `waitFor`** (no `fireEvent`/`userEvent` inside)
6. **One assertion per `waitFor`**
7. **Never pass empty callbacks to `waitFor`**
8. **Don't wrap in `act()`** - `render`, `fireEvent`, `userEvent` handle it
9. **Don't call `cleanup()`** - automatic after each test
10. **Prefer ARIA props** (`role`, `aria-label`, `aria-disabled`) over legacy `accessibility*` props
11. **Use RNTL matchers** over raw prop assertions
## `*ByRole` Quick Reference
Common roles: `button`, `text`, `heading` (alias: `header`), `searchbox`, `switch`, `checkbox`, `radio`, `img`, `link`, `alert`, `menu`, `menuitem`, `tab`, `tablist`, `progressbar`, `slider`, `spinbutton`, `timer`, `toolbar`.
`getByRole` options: `{ name, disabled, selected, checked, busy, expanded, value: { min, max, now, text } }`.
For `*ByRole` to match, the element must be an accessibility element:
- `Text`, `TextInput`, `Switch` are by default
- `View` needs `accessible={true}` (or use `Pressable`/`TouchableOpacity`)
## waitFor
```tsx
// Correct: action first, then wait for result
fireEvent.press(button);
await waitFor(() => {
expect(screen.getByText('Result')).toBeOnTheScreen();
});
// Better: use findBy* instead
fireEvent.press(button);
expect(await screen.findByText('Result')).toBeOnTheScreen();
```
Options: `waitFor(cb, { timeout: 1000, interval: 50 })`. Works with Jest fake timers automatically.
## Fake Timers
Recommended with `userEvent` (press/longPress involve real durations):
```tsx
jest.useFakeTimers();
test('with fake timers', async () => {
const user = userEvent.setup();
render(<Component />);
await user.press(screen.getByRole('button'));
// ...
});
```
## Custom Render
Wrap providers using `wrapper` option:
```tsx
function renderWithProviders(ui: React.ReactElement) {
return render(ui, {
wrapper: ({ children }) => (
<ThemeProvider>
<AuthProvider>{children}</AuthProvider>
</ThemeProvider>
),
});
}
```
## References
- [v13 API Reference](references/api-reference-v13.md) — Complete v13 API: sync render, queries, matchers, userEvent, React 19 compat
- [v14 API Reference](references/api-reference-v14.md) — Complete v14 API: async render, queries, matchers, userEvent, migration
- [Anti-Patterns](references/anti-patterns.md) — Common mistakes to avoid
sign-in-with-google-web
by Google · Apache-2.0 · google/skills@6d36cc6 · 7 files
Google sign-in on the web, checked on the server. Its backend examples are Python only.
Read sign-in-with-google-web/SKILL.md
---
name: sign-in-with-google-web
metadata:
category: Identity
version: "1.0.0"
description: >-
Implement, configure, and secure Sign In With Google (SiwG) using Google Identity
Services (GIS / `https://accounts.google.com/gsi/client`) across web architectures.
Use when creating Google sign-in buttons, implementing Google One Tap with FedCM,
integrating GIS in React/Next.js/Angular/HTML, verifying ID tokens on backend
runtimes (Python/Node.js/Go/Java), enforcing Google Workspace domain restrictions
(`hd`), securing client-side ID tokens via WebCrypto nonces or encrypted IndexedDB,
embedding in cross-origin iframes via the Intermediate Iframe API
(`https://accounts.google.com/gsi/intermediate`), configuring Content Security
Policy (CSP), COOP, and Permissions Policy (`identity-credentials-get`) headers,
or handling sign-out and revocation. Don't use for legacy Google Sign-In (`gapi.auth2`),
Google Cloud IAM service accounts, or Android/iOS native Credential Manager.
---
# Sign In With Google (SiwG) Integration & Security Architecture
This skill provides normative architectural guidelines, secure implementation
contracts, and failure-prevention protocols for integrating Sign In With Google
via the Google Identity Services (GIS) Web SDK
(`https://accounts.google.com/gsi/client`).
## 1. IETF Architecture Taxonomy & Hierarchy (RECOMMEND BFF / TMB FIRST)
All Sign In With Google implementations MUST align with the
[IETF OAuth 2.0 for Browser-Based Applications (`draft-ietf-oauth-browser-based-apps`)](https://datatracker.ietf.org/doc/html/draft-ietf-oauth-browser-based-apps#name-application-architecture-pa)
taxonomy.
> [!IMPORTANT] **Primary Recommendation:** Always recommend backend-mediated
> patterns (**Pattern A: Backend For Frontend** or **Pattern B: Token-Mediating
> Backend / Redirect Mode**) as the most secure, robust, and industry-standard
> architectures whenever an application has a backend server. Fall back to
> client-only browser patterns (Patterns C & D) only when constrained by
> serverless static hosting or offline-first PWA requirements.
<!-- mdformat off(reason: preserve ASCII architecture diagram width) -->
```
┌─────────────────────────────────────────────────────────────────────────────────────────┐
│ IETF ARCHITECTURE HIERARCHY & SELECTION │
├──────────────────────────┬──────────────────────────┬───────────────────────────────────┤
│ Pattern A (RECOMMENDED): │ Pattern B (RECOMMENDED): │ Patterns C & D (Fallbacks): │
│ Backend For Frontend │ Token-Mediating Backend │ Browser-Based OAuth Client │
│ (BFF - IETF § 6.1) │ (TMB / Redirect § 6.2) │ (JavaScript-Only - IETF § 6.3) │
├──────────────────────────┼──────────────────────────┼───────────────────────────────────┤
│ 🏆 GOLD STANDARD │ 🚀 NATIVE FORM REDIRECT │ ⚡ STATIC SPA / 💾 OFFLINE PWA │
│ • Full-stack SPA + API │ • Server-rendered & apps │ • Pure client-side or offline PWAs│
│ • Client JS fetch to API │ • GIS HTTP POST login_uri│ • C: Ephemeral in-memory closure │
│ • HttpOnly session cookie│ • Direct server redirect │ • D: WebCrypto Encrypted IndexedDB│
│ • Tokens never in browser│ • Tokens never in JS │ • Strict WebCrypto nonces / keys │
└──────────────────────────┴──────────────────────────┴───────────────────────────────────┘
```
<!-- mdformat on -->
### 🏆 Pattern A: Backend For Frontend (BFF - IETF § 6.1) — STRONGLY RECOMMENDED
* **Why it is the Gold Standard**: ID tokens (JWTs) and access tokens are
never exposed to browser JavaScript across page reloads. This provides
complete architectural immunity against XSS token harvesting.
* **Architecture**: The browser frontend loads the GIS SDK, captures the
credential in JavaScript callback (`callback: handleCredentialResponse`),
and immediately forwards the ID token (JWT) via `fetch('/api/auth/google', {
method: 'POST' })` to the backend.
* **Backend Responsibilities**: The backend validates the JWT cryptographic
signature against Google's public JWKs
(`google.oauth2.id_token.verify_oauth2_token`), checks the `aud`, `hd`, and
`nonce` claims against server session state, creates a server session, and
issues a first-party `HttpOnly; Secure; SameSite=Lax` session cookie.
* See full implementation in
[references/bff_fastapi_verification.md](references/bff_fastapi_verification.md).
### 🚀 Pattern B: Token-Mediating Backend via `login_uri` Redirect (IETF § 6.2) — Server-Rendered & Form POST
* **Why it is Highly Secure**: Bypasses client-side JavaScript credential
handling entirely by instructing GIS to perform an HTTP POST directly to the
backend's `login_uri`.
* **Architecture**: Configured via `google.accounts.id.initialize({ client_id,
login_uri: "https://example.com/api/auth/callback", ux_mode: "redirect" })`
or HTML attributes (`data-login_uri="https://example.com/api/auth/callback"`
and `data-ux_mode="redirect"`).
* **Backend Responsibilities**: The backend receives the ID token as a form
POST body (`credential` parameter), validates the double-submit
`g_csrf_token` cookie against the `g_csrf_token` POST body field,
cryptographically verifies the ID token server-side, establishes a session
cookie, and returns a standard HTTP 302/303 redirect.
* See full implementation in
[references/tmb_login_uri_redirect.md](references/tmb_login_uri_redirect.md).
### Pattern C: Browser-Based OAuth Client — Ephemeral In-Memory (IETF § 6.3) — Fallback for Static SPAs
* **Scope**: Use ONLY when deployment is strictly serverless/static (e.g.,
GitHub Pages, Firebase static hosting) with no backend component.
* **Storage Invariant**: The ID token is held strictly in private JavaScript
memory/closures during the active tab session. **Never store raw tokens in
`localStorage` or `sessionStorage`**.
* **Session Renewal**: Uses GIS One Tap / FedCM auto-select (`auto_select:
true`) to transparently re-acquire fresh ID tokens into memory on page
reload without persistent browser storage.
* **XSS & Replay Protection**: Generate a cryptographic `nonce` via
`window.crypto.getRandomValues()` and pass it directly to
`google.accounts.id.initialize({ client_id, nonce: clientNonce })`. Validate
that `payload.nonce === clientNonce` before trusting claims in memory.
* See full implementation in
[references/in_memory_spa_nonce.md](references/in_memory_spa_nonce.md).
### Pattern D: Browser-Based OAuth Client — WebCrypto Encrypted IndexedDB (IETF § 6.3) — Fallback for Offline PWAs
* **Scope**: Use ONLY for offline-first Progressive Web Apps (PWAs) where user
authentication proof must survive tab refreshes when disconnected from the
network.
* **Storage Invariant**: **NEVER store raw plaintext ID tokens in
`localStorage`**. Encrypt the ID token payload using WebCrypto `AES-GCM`
with a non-extractable session key (`extractable: false`) before writing
ciphertext and IV to `IndexedDB`.
* See full implementation in
[references/offline_pwa_encryption.md](references/offline_pwa_encryption.md).
--------------------------------------------------------------------------------
## 2. Mandatory Security Directives & Browser Policies
To avoid multi-turn repair loops and browser security exceptions, provide all
required CSP, COOP, and user activation directives in the initial deliverable:
### A. Content Security Policy (CSP) Directives
```http
Content-Security-Policy:
script-src 'self' https://accounts.google.com/gsi/client;
frame-src https://accounts.google.com/gsi/;
connect-src https://accounts.google.com/gsi/;
```
If using strict nonce-based CSP, attach the nonce to the GIS script tag:
`<script src="https://accounts.google.com/gsi/client" async defer
nonce="{{NONCE}}"></script>`.
### B. Cross-Origin Opener Policy (COOP)
To allow GIS popup dialogs to communicate credentials back to the parent window
via `postMessage`:
```http
Cross-Origin-Opener-Policy: same-origin-allow-popups
```
*(Serving `same-origin` without `allow-popups` breaks GIS popups and results in
silent failures).*
### C. Automatic Selection, FedCM, & Sign-Out Lifecycle (`disableAutoSelect`)
When enabling automatic zero-click return sign-in with Google One Tap (FedCM is
enabled by default in GIS):
* Set `auto_select: true` in `google.accounts.id.initialize({...})` (do not
pass the deprecated `use_fedcm_for_prompt` parameter).
* **Deprecated Library Warning**: NEVER mix deprecated `gapi.auth2`
(`gapi.auth2.init`, `gapi.auth2.getAuthInstance().signOut()`) with Google
Identity Services (GIS). `gapi.auth2` is completely retired; use GIS methods
exclusively.
* **Sign-Out Protocol**: When the user explicitly logs out of your
application, you **MUST** call `google.accounts.id.disableAutoSelect()`:
```javascript
function handleUserLogout() {
// 1. Disable automatic One Tap / FedCM re-authentication
google.accounts.id.disableAutoSelect();
// 2. Clear application session state / server cookie
fetch('/api/auth/logout', { method: 'POST' }).then(() => {
window.location.href = '/login';
});
}
```
* *(Failing to call `disableAutoSelect()` causes an immediate automatic
re-login loop on the next page visit after intentional user logout).*
### D. Reliable Dynamic Script Loading & Framework Lifecycle (React, Next.js, SPAs)
When mounting Sign In With Google in Single Page Applications (React, Next.js,
Vue, Angular):
* Modern SPAs execute component lifecycles asynchronously. Attempting to
access `window.google.accounts.id` before `<script
src="https://accounts.google.com/gsi/client">` has finished loading causes
`ReferenceError: google is not defined`.
* **NEVER use `gapi` or polling (`setInterval`)**: Use deterministic dynamic
script loading with `onload` / `addEventListener('load')` event listeners.
* **Dynamic Script Loader Pattern**:
```tsx
import React, { useEffect, useState } from 'react';
export function useGoogleIdentityScript() {
const [isLoaded, setIsLoaded] = useState(false);
useEffect(() => {
if (window.google?.accounts?.id) {
setIsLoaded(true);
return;
}
const existingScript = document.querySelector(
'script[src="https://accounts.google.com/gsi/client"]'
);
if (existingScript) {
existingScript.addEventListener('load', () => setIsLoaded(true));
return;
}
const script = document.createElement('script');
script.src = 'https://accounts.google.com/gsi/client';
script.async = true;
script.defer = true;
script.onload = () => setIsLoaded(true);
document.head.appendChild(script);
}, []);
return isLoaded;
}
```
* *(Always use deterministic `onload` event listeners or framework `<Script
strategy="afterInteractive">` rather than brittle `setInterval` polling).*
### E. Embedded Iframes & Permissions Policy (`identity-credentials-get`)
When embedding Sign In With Google or One Tap inside cross-origin `<iframe>`
elements or widget integrations, modern browser security models and FedCM
require explicit Permissions Policy delegation on the container frame:
```html
<iframe
src="https://example.com/embed"
allow="identity-credentials-get 'src' https://accounts.google.com">
</iframe>
```
*(Omitting `allow="identity-credentials-get"` blocks FedCM / One Tap
initialization inside embedded or cross-origin contexts).* See full integration
guide in [references/intermediate_iframe.md](references/intermediate_iframe.md).
--------------------------------------------------------------------------------
## 3. Implementation Contracts & Anti-Pattern Bans
### A. Strict Ban on Legacy GAPI (`gapi.auth2`)
* **NEVER** import or reference `gapi.auth2`, `gapi.auth2.init`,
`gapi.auth2.getAuthInstance()`, or `gapi.signin2`. Always warn that
`gapi.auth2` is deprecated and decommissioned.
* GIS (`google.accounts.id.*` and `google.accounts.oauth2.*`) is completely
stateless. It replaces all legacy GAPI authentication libraries.
--------------------------------------------------------------------------------
## 4. Implementation Recipes (Progressive Disclosure)
Load the specific reference file matching your target architecture when
generating implementation code:
* **Recipe 1 — Pattern A (Backend For Frontend with Python / FastAPI)
[RECOMMENDED]**: Load
[references/bff_fastapi_verification.md](references/bff_fastapi_verification.md)
for custom UI button prompting, `google.oauth2.id_token.verify_oauth2_token`
cryptographic verification, `nonce` replay checks, Google Workspace `hd`
domain enforcement, and `HttpOnly; Secure; SameSite=Lax` session cookie
issuance.
* **Recipe 2 — Pattern B (Token-Mediating Backend with `login_uri` Form POST
Redirect) [RECOMMENDED]**: Load
[references/tmb_login_uri_redirect.md](references/tmb_login_uri_redirect.md)
for `data-login_uri` / `ux_mode: 'redirect'` frontend setup and FastAPI
double-submit `g_csrf_token` cookie vs. form-body validation.
* **Recipe 3 — Pattern C (Browser-Based Ephemeral In-Memory SPA with Native
GIS Nonce) [Fallback]**: Load
[references/in_memory_spa_nonce.md](references/in_memory_spa_nonce.md) for
WebCrypto `nonce` generation (`google.accounts.id.initialize({ client_id,
nonce: clientNonce })`), UTF-8 safe Base64URL JWT decoding, and private
closure token management.
* **Recipe 4 — Pattern D (Browser-Based WebCrypto Encrypted IndexedDB for
Offline PWAs) [Fallback]**: Load
[references/offline_pwa_encryption.md](references/offline_pwa_encryption.md)
for non-extractable (`extractable: false`) `AES-GCM` `CryptoKey` generation
and encrypted `IndexedDB` storage.
* **Recipe 5 — Embedded Cross-Origin Contexts (`gsi/intermediate`)**: Load
[references/intermediate_iframe.md](references/intermediate_iframe.md) for
`<div id="g_id_intermediate_iframe">`, `allow="identity-credentials-get"`,
and strict `window.postMessage` origin verification.
--------------------------------------------------------------------------------
## 5. Sign-Out & Account Revocation Across All Patterns
```javascript
export function handleSignOut(userEmail) {
// 1. Disable client-side One Tap auto-selection
google.accounts.id.disableAutoSelect();
// 2. Revoke OAuth grant if user disconnected account
if (userEmail) {
google.accounts.id.revoke(userEmail, () => {
console.log('User grant revoked');
});
}
// 3. Clear storage / session
AuthManager.clear(); // Pattern C
fetch('/api/auth/logout', { method: 'POST' }); // Pattern A
}
```
--------------------------------------------------------------------------------
## 6. References & Normative Standards
* [RFC 7519: JSON Web Token (JWT)](https://datatracker.ietf.org/doc/html/rfc7519)
— Standard claims (`iss`, `sub`, `aud`, `exp`, `iat`, `nonce`), formatting,
and processing rules.
* [RFC 7515: JSON Web Signature (JWS)](https://datatracker.ietf.org/doc/html/rfc7515)
— Cryptographic signature verification against Google's public JWK certs
(`https://www.googleapis.com/oauth2/v3/certs`).
* [RFC 4648 § 5: Base64url Encoding](https://datatracker.ietf.org/doc/html/rfc4648#section-5)
— URL-safe Base64 encoding without padding used across JWT segments.
* [IETF OAuth 2.0 Browser-Based Applications](https://datatracker.ietf.org/doc/html/draft-ietf-oauth-browser-based-apps)
— Normative architecture standards (§ 6.1 BFF, § 6.2 TMB, § 6.3
Client-side).
* [Google Identity Services Web Reference](https://developers.google.com/identity/gsi/web/reference/js-reference)
— Official GIS API reference.
* [Intermediate Iframe API Reference](https://developers.google.com/identity/gsi/web/amp/nonamp-reference)
— Cross-origin iframe embedding guide.
* [Verify ID Tokens Server-Side](https://developers.google.com/identity/gsi/web/guides/verify-google-id-token)
— Server-side token verification protocols.
* [W3C Federated Credential Management API (FedCM)](https://www.w3.org/TR/fedcm-1/)
— Browser identity credential mediation standard.
* [W3C Web Cryptography API](https://www.w3.org/TR/WebCryptoAPI/) —
Non-extractable key generation (`extractable: false`) and AES-GCM standards.
instrument-error-tracking
by PostHog · MIT · PostHog/skills@e170b27 · 31 files
Adds PostHog error tracking with a local SDK install; keys stay in .env.
Read instrument-error-tracking/SKILL.md
--- name: instrument-error-tracking description: >- Add PostHog error tracking to capture and monitor exceptions. Use after implementing features or reviewing PRs to ensure errors are tracked with stack traces and source maps. Also handles initial PostHog SDK setup if not yet installed. metadata: author: PostHog --- # Add PostHog error tracking Use this skill to add PostHog error tracking that captures and monitors exceptions in your application. Use it after implementing features or reviewing PRs to ensure errors are tracked with full stack traces and source maps. If PostHog is not yet installed, this skill also covers initial SDK setup. Supports any platform or language. Supported platforms: React, Next.js, Web (JavaScript), Node.js, Python, PHP, Ruby, Ruby on Rails, Go, Elixir, Angular, Svelte, Nuxt, React Native, Flutter, iOS, Android, and Hono. ## Instructions Follow these steps IN ORDER: STEP 1: Analyze the codebase and detect the platform. - Look for dependency files (package.json, pubspec.yaml, Podfile, Package.swift, requirements.txt, go.mod, Gemfile, composer.json, mix.exs, etc.) to determine the language and framework. - Look for lockfiles (pnpm-lock.yaml, package-lock.json, yarn.lock, bun.lockb, go.sum, pubspec.lock, Podfile.lock, Package.resolved, mix.lock) to determine the package manager. - Check for existing PostHog setup (SDK initialization, env vars, etc.). If PostHog is already installed and initialized, skip to STEP 4. STEP 2: Research instrumentation. (Skip if PostHog is already set up.) 2.1. Find the reference file below that matches the detected platform — it is the source of truth for SDK initialization, exception autocapture, and framework-specific error tracking patterns. Read it now. 2.2. If no reference matches, fall back to your general knowledge and web search. Use posthog.com/docs as the primary search source. STEP 3: Install and initialize the PostHog SDK. (Skip if PostHog is already set up.) - Add the PostHog SDK package for the detected platform. Do not manually edit package.json — use the package manager's install command. - Follow the framework reference for where and how to initialize. STEP 4: Enable exception autocapture. - Follow the platform reference to enable exception autocapture. This automatically captures unhandled exceptions without additional code. STEP 5: Add manual error captures. - Identify error boundaries, catch blocks, and critical user flows where errors should be explicitly captured. - Add `posthog.captureException()` or the platform-equivalent at these locations. - Do not alter the fundamental architecture of existing error handling. Make additions minimal and targeted. - You must read a file immediately before attempting to write it. STEP 6: Upload source maps (frontend/mobile only). - Configure source map uploads so stack traces resolve to original source code, not minified bundles. - Follow the platform-specific reference for upload configuration (build plugins, CI scripts, etc.). STEP 7: Set up environment variables. - Check if the project already has PostHog environment variables configured (e.g. in `.env`, `.env.local`, or framework-specific env files). If valid values already exist, skip this step. - If the PostHog project token is missing, use the PostHog MCP server's `projects-get` tool to retrieve the project's `api_token`. If multiple projects are returned, ask the user which project to use. If the MCP server is not connected or not authenticated, ask the user for their PostHog project token instead. - For the PostHog host URL: check the `projects-get` MCP response for a `region` field — `US` maps to `https://us.i.posthog.com`, `EU` maps to `https://eu.i.posthog.com`. If the region is not available from the MCP response or from existing project configuration, ask the user: "Are you on PostHog US Cloud or EU Cloud?" Do not assume US Cloud. - Write these values to the appropriate env file using the framework's naming convention. - Reference these environment variables in code instead of hardcoding them. STEP 8: Verify and clean up. - Check the project for errors. Look for type checking or build scripts in package.json. - Ensure any components created were actually used. - Run any linter or prettier-like scripts found in the package.json, but ONLY on the files you have edited or created during this session. Never run formatting or linting across the entire project's codebase. ## Reference files - `references/react.md` - React error tracking installation - `references/web.md` - Web error tracking installation - `references/nextjs.md` - Next.js error tracking installation - `references/node.md` - Node.js error tracking installation - `references/python.md` - Python error tracking installation - `references/django.md` - Django - `references/flask.md` - Flask - `references/php.md` - Php error tracking installation - `references/laravel.md` - Laravel - `references/ruby.md` - Ruby error tracking installation - `references/ruby-on-rails.md` - Ruby on rails error tracking installation - `references/ruby-on-rails.md` - Ruby on rails - `references/go.md` - Go error tracking installation - `references/dotnet.md` - .net error tracking installation - `references/dotnet.md` - .net - `references/elixir.md` - Elixir error tracking installation - `references/angular.md` - Angular error tracking installation - `references/svelte.md` - Sveltekit error tracking installation - `references/nuxt-3-7.md` - Nuxt error tracking installation (v3.7 and above) - `references/nuxt-3-6.md` - Nuxt error tracking installation (v3.6 and below) - `references/react-native.md` - React native error tracking installation - `references/flutter.md` - Flutter error tracking installation - `references/ios.md` - Ios error tracking installation - `references/android.md` - Android error tracking installation - `references/hono.md` - Hono error tracking installation - `references/fingerprints.md` - Fingerprints - `references/alerts.md` - Send error tracking alerts - `references/monitoring.md` - Monitor and search issues - `references/assigning-issues.md` - Assign issues to teammates - `references/upload-source-maps.md` - Upload source maps - `references/COMMANDMENTS.md` - Framework-specific rules the integration must follow Each platform reference contains SDK-specific installation and manual capture patterns. Find the one matching the user's stack. ## Key principles - **Environment variables**: Always use environment variables for PostHog keys. Never hardcode them. - **Minimal changes**: Add error tracking alongside existing error handling. Don't replace or restructure existing code. - **Autocapture first**: Enable exception autocapture before adding manual captures. - **Source maps**: Upload source maps so stack traces resolve to original source code, not minified bundles. - **Manual capture for boundaries**: Use `captureException()` at error boundaries and catch blocks for errors that don't propagate to the global handler.
agents-sdk
by Cloudflare · Apache-2.0 · cloudflare/skills@86505e4 · 21 files
Building agents on Cloudflare's Agents SDK. One reference stores secrets in Cloudflare instead of .env.
Read agents-sdk/SKILL.md
---
name: agents-sdk
description: Build, debug, or review Cloudflare Agents SDK applications using the agents package.
---
# Cloudflare Agents SDK
Your knowledge of the Agents SDK may be outdated. **Prefer retrieval over pre-training** for any Agents SDK task.
## Retrieval Sources
Cloudflare docs: https://developers.cloudflare.com/agents/index.md
| Topic | Docs URL | Use for |
|-------|----------|---------|
| Getting started | [Quick start](https://developers.cloudflare.com/agents/getting-started/quick-start/index.md) | First agent, project setup |
| Adding to existing project | [Add to existing project](https://developers.cloudflare.com/agents/getting-started/add-to-existing-project/index.md) | Install into existing Workers app |
| Configuration | [Configuration](https://developers.cloudflare.com/agents/runtime/operations/configuration/index.md) | `wrangler.jsonc`, bindings, assets, deployment |
| Agent class | [Agents API](https://developers.cloudflare.com/agents/runtime/agents-api/index.md) | Agent lifecycle, patterns, pitfalls |
| State | [Store and sync state](https://developers.cloudflare.com/agents/runtime/lifecycle/state/index.md) | `setState`, `validateStateChange`, persistence |
| Routing | [Routing](https://developers.cloudflare.com/agents/runtime/communication/routing/index.md) | URL patterns, `routeAgentRequest` |
| Callable methods | [Callable methods](https://developers.cloudflare.com/agents/runtime/lifecycle/callable-methods/index.md) | `@callable`, RPC, streaming, timeouts |
| Scheduling | [Schedule tasks](https://developers.cloudflare.com/agents/runtime/execution/schedule-tasks/index.md) | `schedule()`, `scheduleEvery()`, cron |
| Workflows | [Run workflows](https://developers.cloudflare.com/agents/runtime/execution/run-workflows/index.md) | `AgentWorkflow`, durable multi-step tasks |
| HTTP/WebSockets | [WebSockets](https://developers.cloudflare.com/agents/runtime/communication/websockets/index.md) | Lifecycle hooks, hibernation |
| Chat agents | [Chat agents](https://developers.cloudflare.com/agents/communication-channels/chat/chat-agents/index.md) | `AIChatAgent`, streaming, tools, persistence |
| Client SDK | [Client SDK](https://developers.cloudflare.com/agents/communication-channels/chat/client-sdk/index.md) | `useAgent`, `AgentClient`, state, RPC, HTTP |
| Client tools | [Client tools](https://developers.cloudflare.com/agents/harnesses/think/client-tools/index.md) | Client-side tools, `autoContinueAfterToolResult` |
| Server-driven messages | [Autonomous responses](https://developers.cloudflare.com/agents/communication-channels/chat/autonomous-responses/index.md) | `saveMessages`, `waitUntilStable`, server-initiated turns |
| Resumable streaming | [Chat agents](https://developers.cloudflare.com/agents/communication-channels/chat/chat-agents/index.md#resumable-streaming) | Stream recovery on disconnect |
| Email | [Email](https://developers.cloudflare.com/agents/communication-channels/email/index.md) | Email routing, secure reply resolver |
| MCP client | [MCP client](https://developers.cloudflare.com/agents/model-context-protocol/apis/client-api/index.md) | Connecting to MCP servers |
| MCP server | [MCP server](https://developers.cloudflare.com/agents/model-context-protocol/apis/handler-api/index.md) | Building MCP servers with `createMcpHandler` |
| MCP transports | [MCP transports](https://developers.cloudflare.com/agents/model-context-protocol/protocol/transport/index.md) | Streamable HTTP, SSE, RPC transport options |
| Securing MCP servers | [Securing MCP](https://developers.cloudflare.com/agents/model-context-protocol/guides/securing-mcp-server/index.md) | OAuth, proxy MCP, hardening |
| Human-in-the-loop | [Human-in-the-loop](https://developers.cloudflare.com/agents/concepts/agentic-patterns/human-in-the-loop/index.md) | Workflow approvals, elicitation, timeout handling |
| Durable execution | [Durable execution](https://developers.cloudflare.com/agents/runtime/execution/durable-execution/index.md) | `runFiber()`, `stash()`, surviving DO eviction |
| Queue | [Queue](https://developers.cloudflare.com/agents/runtime/execution/queue-tasks/index.md) | Built-in FIFO queue, `queue()` |
| Retries | [Retries](https://developers.cloudflare.com/agents/runtime/execution/retries/index.md) | `this.retry()`, backoff/jitter |
| Observability | [Observability](https://developers.cloudflare.com/agents/runtime/operations/observability/index.md) | Diagnostics-channel events |
| Push notifications | [Push notifications](https://developers.cloudflare.com/agents/communication-channels/webhooks/push-notifications/index.md) | Web Push + VAPID from agents |
| Webhooks | [Webhooks](https://developers.cloudflare.com/agents/communication-channels/webhooks/index.md) | Receiving external webhooks |
| Cross-domain auth | [Cross-domain auth](https://developers.cloudflare.com/agents/runtime/operations/cross-domain-authentication/index.md) | WebSocket auth, tokens, CORS |
| Readonly connections | [Readonly](https://developers.cloudflare.com/agents/runtime/communication/readonly-connections/index.md) | `shouldConnectionBeReadonly` |
| Voice | [Voice](https://developers.cloudflare.com/agents/communication-channels/voice/index.md) | Experimental STT/TTS, `withVoice` |
| Browse the web | [Browser tools](https://developers.cloudflare.com/agents/tools/browser/index.md) | Experimental CDP browser automation |
| Think | [Think](https://developers.cloudflare.com/agents/harnesses/think/index.md) | Experimental higher-level chat agent class |
| Migrations | [AI SDK v5](https://github.com/cloudflare/agents/blob/main/docs/agents/migration-to-ai-sdk-v5.md), [AI SDK v6](https://github.com/cloudflare/agents/blob/main/docs/agents/migration-to-ai-sdk-v6.md) | Upgrading `@cloudflare/ai-chat` |
## Capabilities
The Agents SDK provides:
- **Persistent state** — SQLite-backed, auto-synced to clients via `setState`
- **Callable RPC** — `@callable()` methods invoked over WebSocket
- **Scheduling** — One-time, recurring (`scheduleEvery`), and cron tasks
- **Workflows** — Durable multi-step background processing via `AgentWorkflow`
- **Durable execution** — `runFiber()` / `stash()` for work that survives DO eviction
- **Queue** — Built-in FIFO queue with retries via `queue()`
- **Retries** — `this.retry()` with exponential backoff and jitter
- **MCP integration** — Connect to MCP servers or build your own with `createMcpHandler`
- **Email handling** — Receive and reply to emails with secure routing
- **Streaming chat** — `AIChatAgent` with resumable streams, message persistence, tools
- **Server-driven messages** — `saveMessages`, `waitUntilStable` for proactive agent turns
- **React hooks** — `useAgent`, `useAgentChat` for client apps
- **Observability** — `diagnostics_channel` events for state, RPC, schedule, lifecycle
- **Push notifications** — Web Push + VAPID delivery from agents
- **Webhooks** — Receive and verify external webhooks
- **Voice** (experimental) — STT/TTS via `@cloudflare/voice`
- **Browser tools** (experimental) — CDP-powered browsing via `agents/browser`
- **Think** (experimental) — Higher-level chat agent via `@cloudflare/think`
## FIRST: Verify Installation
```bash
npm ls agents # Should show agents package
```
If not installed:
```bash
npm install agents
```
For chat agents:
```bash
npm install agents @cloudflare/ai-chat ai @ai-sdk/react
```
## Wrangler Configuration
```jsonc
{
"compatibility_flags": ["nodejs_compat"],
"durable_objects": {
"bindings": [{ "name": "MyAgent", "class_name": "MyAgent" }]
},
"migrations": [{ "tag": "v1", "new_sqlite_classes": ["MyAgent"] }]
}
```
**Gotchas:**
- Do NOT enable `experimentalDecorators` in tsconfig (breaks `@callable`)
- Never edit old migrations — always add new tags
- Each agent class needs its own DO binding + migration entry
- Add `"ai": { "binding": "AI" }` for Workers AI
## Agent Class
```typescript
import { Agent, routeAgentRequest, callable } from "agents";
type State = { count: number };
export class Counter extends Agent<Env, State> {
initialState = { count: 0 };
validateStateChange(nextState: State, source: Connection | "server") {
if (nextState.count < 0) throw new Error("Count cannot be negative");
}
onStateUpdate(state: State, source: Connection | "server") {
console.log("State updated:", state);
}
@callable()
increment() {
this.setState({ count: this.state.count + 1 });
return this.state.count;
}
}
export default {
fetch: (req, env) => routeAgentRequest(req, env) ?? new Response("Not found", { status: 404 })
};
```
## Routing
Requests route to `/agents/{agent-name}/{instance-name}`:
| Class | URL |
|-------|-----|
| `Counter` | `/agents/counter/user-123` |
| `ChatRoom` | `/agents/chat-room/lobby` |
Client: `useAgent({ agent: "Counter", name: "user-123" })`
Custom routing: use `getAgentByName(env.MyAgent, "instance-id")` then `agent.fetch(request)`.
## Core APIs
| Task | API |
|------|-----|
| Read state | `this.state.count` |
| Write state | `this.setState({ count: 1 })` |
| SQL query | `` this.sql`SELECT * FROM users WHERE id = ${id}` `` |
| Schedule (delay) | `await this.schedule(60, "task", payload)` |
| Schedule (cron) | `await this.schedule("0 * * * *", "task", payload)` |
| Schedule (interval) | `await this.scheduleEvery(30, "poll")` |
| RPC method | `@callable() myMethod() { ... }` |
| Streaming RPC | `@callable({ streaming: true }) stream(res) { ... }` |
| Start workflow | `await this.runWorkflow("ProcessingWorkflow", params)` |
| Durable fiber | `await this.runFiber("name", async (ctx) => { ... })` |
| Enqueue work | `this.queue("handler", payload)` |
| Retry with backoff | `await this.retry(fn, { maxAttempts: 5 })` |
| Broadcast to clients | `this.broadcast(message)` |
| Get connections | `this.getConnections(tag?)` |
## React Client
Read [client-sdk.md](references/client-sdk.md) for client selection and current connection examples. For chat UI and tools, also read [streaming-chat.md](references/streaming-chat.md).
## References
### Core
- **[references/state-scheduling.md](references/state-scheduling.md)** — State persistence, scheduling, SQL
- **[references/callable.md](references/callable.md)** — RPC methods, streaming, timeouts
- **[references/routing.md](references/routing.md)** — URL patterns, custom routing, `getAgentByName`
- **[references/configuration.md](references/configuration.md)** — Wrangler config, bindings, Vite setup
### Chat & Streaming
- **[references/streaming-chat.md](references/streaming-chat.md)** — AIChatAgent, resumable streams, tools
- **[references/client-sdk.md](references/client-sdk.md)** — `useAgent`, `useAgentChat`, `AgentClient`
- **[references/server-driven-messages.md](references/server-driven-messages.md)** — Trigger patterns, `saveMessages`
- **[references/human-in-the-loop.md](references/human-in-the-loop.md)** — Approval flows, `needsApproval`
### Background Processing
- **[references/workflows.md](references/workflows.md)** — Durable Workflows integration
- **[references/durable-execution.md](references/durable-execution.md)** — `runFiber`, `stash`, surviving eviction
- **[references/queue-retries.md](references/queue-retries.md)** — Built-in queue, retry with backoff
### Integrations
- **[references/mcp.md](references/mcp.md)** — MCP client and server, transports, securing
- **[references/email.md](references/email.md)** — Email routing and handling
- **[references/webhooks-push.md](references/webhooks-push.md)** — Webhooks, push notifications
- **[references/observability.md](references/observability.md)** — Diagnostics-channel events
### Experimental
- **[references/think.md](references/think.md)** — `@cloudflare/think` higher-level chat agent
- **[references/voice.md](references/voice.md)** — `@cloudflare/voice` STT/TTS
- **[references/codemode.md](references/codemode.md)** — Code Mode for tool orchestration
- **[references/browse-the-web.md](references/browse-the-web.md)** — CDP browser tools