agentleFS
mehdiozdemirmehdiozdemir/awesome-agent-skills/skills/security-scanner/SKILL.md

security-scanner

Skill2 starsChanged 10 months agoMITView on GitHub

Analyzes code for security vulnerabilities, misconfigurations, and potential attack vectors. Use when auditing codebases for OWASP Top 10 vulnerabilities, reviewing authentication/authorization implementations, checking for secret exposure, validating cryptographic practices, or performing security-focused code reviews.

  • Reads credentials
  • Deletes or force-pushes

14 other projects use a version of this.

Adopted by

Most recently taken up by

The file

We split this skill into the rules it gives an agent

7 rules. 0 are common, 7 are distinctive, and 0 are very specific to this project.

  • 0

    Common

    Most of the 11 edited versions we read keep these.

  • 7

    Distinctive

    This author's own choices. Worth a look.

  • 0

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    Check for existing security controls

    line 60
  2. Distinctive:

    When performing a security scan, provide:

    line 794
  3. Distinctive:

    Always prioritize findings by exploitability and impact

    line 886
  4. Distinctive:

    Consider the context (internal app vs public-facing)

    line 888
  5. Distinctive:

    Check for security through obscurity (security theater)

    line 889
  6. Distinctive:

    Verify fixes don't introduce new vulnerabilities

    line 890
  7. Distinctive:

    Consider defense in depth - multiple layers of protection

    line 891

“Common” is measured: kept by at least 6 in 10 of the 11 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Security Scanner Skill

This skill identifies security vulnerabilities, misconfigurations, and potential attack vectors in code. Use this whenever you need to audit code for security issues, review sensitive implementations, or ensure compliance with security best practices.

Security Analysis Scope

1. OWASP Top 10 Vulnerabilities

The most critical web application security risks:

#VulnerabilityDescription
A01Broken Access ControlUnauthorized access to resources
A02Cryptographic FailuresWeak encryption, exposed sensitive data
A03InjectionSQL, NoSQL, OS, LDAP injection
A04Insecure DesignMissing security controls by design
A05Security MisconfigurationDefault configs, verbose errors
A06Vulnerable ComponentsOutdated dependencies with CVEs
A07Authentication FailuresWeak auth, credential stuffing
A08Data Integrity FailuresInsecure deserialization, CI/CD
A09Logging FailuresInsufficient logging/monitoring
A10SSRFServer-Side Request Forgery

2. CWE Categories

Common Weakness Enumeration patterns:

  • CWE-79: Cross-Site Scripting (XSS)
  • CWE-89: SQL Injection
  • CWE-22: Path Traversal
  • CWE-78: OS Command Injection
  • CWE-352: Cross-Site Request Forgery (CSRF)
  • CWE-434: Unrestricted File Upload
  • CWE-502: Deserialization of Untrusted Data
  • CWE-611: XML External Entity (XXE)
  • CWE-798: Hardcoded Credentials
  • CWE-918: Server-Side Request Forgery

3. Secret Detection

Exposed credentials and sensitive data:

  • API keys and tokens
  • Database passwords
  • Private keys and certificates
  • OAuth secrets
  • AWS/GCP/Azure credentials
  • JWT secrets
  • Encryption keys

Security Scan Process

Step 1: Initial Assessment

  1. Identify the application type (web, API, mobile, etc.)
  2. Determine the technology stack
  3. Identify security-sensitive areas (auth, payments, data)
  4. Review the architecture for attack surface
  5. Check for existing security controls

Step 2: Vulnerability Analysis

Scan code systematically for:

Injection Vulnerabilities:

  • SQL/NoSQL injection points
  • Command injection
  • LDAP injection
  • XPath injection
  • Template injection

Authentication Issues:

  • Weak password policies
  • Missing MFA
  • Session management flaws
  • Insecure password storage
  • Credential exposure in logs

Authorization Flaws:

  • Missing access controls
  • Privilege escalation paths
  • IDOR vulnerabilities
  • Insecure direct object references

Data Protection:

  • Unencrypted sensitive data
  • Weak cryptographic algorithms
  • Improper key management
  • PII exposure

Step 3: Severity Classification

🔴 CRITICAL (CVSS 9.0-10.0)

  • Remote code execution
  • Authentication bypass
  • SQL injection with data access
  • Exposed production credentials
  • Privilege escalation to admin

🟠 HIGH (CVSS 7.0-8.9)

  • XSS with session hijacking potential
  • CSRF on sensitive actions
  • Broken access control
  • Insecure deserialization
  • SSRF with internal access

🟡 MEDIUM (CVSS 4.0-6.9)

  • Information disclosure
  • Missing security headers
  • Verbose error messages
  • Weak cryptographic practices
  • Session fixation

🟢 LOW (CVSS 0.1-3.9)

  • Missing best practices
  • Non-sensitive information leak
  • Deprecated functions
  • Minor configuration issues

Vulnerability Patterns

SQL Injection

Vulnerable Code:

# ❌ VULNERABLE - Direct string concatenation
def get_user(username):
    query = f"SELECT * FROM users WHERE username = '{username}'"
    return db.execute(query)

# ❌ VULNERABLE - String formatting
def search_products(keyword):
    query = "SELECT * FROM products WHERE name LIKE '%{}%'".format(keyword)
    return db.execute(query)

Secure Code:

# ✅ SECURE - Parameterized queries
def get_user(username):
    query = "SELECT * FROM users WHERE username = %s"
    return db.execute(query, (username,))

# ✅ SECURE - ORM with proper escaping
def search_products(keyword):
    return Product.query.filter(Product.name.ilike(f"%{keyword}%")).all()

# ✅ SECURE - SQLAlchemy text binding
from sqlalchemy import text
def get_user(username):
    query = text("SELECT * FROM users WHERE username = :username")
    return db.execute(query, {"username": username})

Cross-Site Scripting (XSS)

Vulnerable Code:

// ❌ VULNERABLE - Direct HTML insertion
function displayMessage(message) {
    document.getElementById('output').innerHTML = message;
}

// ❌ VULNERABLE - Template without escaping
app.get('/profile', (req, res) => {
    res.send(`<h1>Welcome, ${req.query.name}</h1>`);
});

Secure Code:

// ✅ SECURE - Text content (no HTML parsing)
function displayMessage(message) {
    document.getElementById('output').textContent = message;
}

// ✅ SECURE - Proper escaping
import escape from 'escape-html';
app.get('/profile', (req, res) => {
    res.send(`<h1>Welcome, ${escape(req.query.name)}</h1>`);
});

// ✅ SECURE - React auto-escapes by default
function Profile({ name }) {
    return <h1>Welcome, {name}</h1>;  // Safe - auto-escaped
}

// ⚠️ DANGEROUS - React dangerouslySetInnerHTML
function Profile({ htmlContent }) {
    // Only use with sanitized content!
    return <div dangerouslySetInnerHTML={{ __html: sanitize(htmlContent) }} />;
}

Command Injection

Vulnerable Code:

# ❌ VULNERABLE - Shell command with user input
import os

def ping_host(host):
    os.system(f"ping -c 1 {host}")  # host = "google.com; rm -rf /"

# ❌ VULNERABLE - subprocess with shell=True
import subprocess

def list_files(directory):
    subprocess.call(f"ls -la {directory}", shell=True)

Secure Code:

# ✅ SECURE - Use subprocess with list arguments
import subprocess
import shlex

def ping_host(host):
    # Validate input first
    if not is_valid_hostname(host):
        raise ValueError("Invalid hostname")
    subprocess.run(["ping", "-c", "1", host], check=True)

# ✅ SECURE - Avoid shell entirely
def list_files(directory):
    # Validate path
    safe_path = os.path.realpath(directory)
    if not safe_path.startswith(ALLOWED_BASE_PATH):
        raise ValueError("Path traversal detected")
    subprocess.run(["ls", "-la", safe_path], check=True)

# ✅ SECURE - Use Python libraries instead of shell
import pathlib

def list_files(directory):
    path = pathlib.Path(directory).resolve()
    if not str(path).startswith(str(ALLOWED_BASE_PATH)):
        raise ValueError("Path traversal detected")
    return list(path.iterdir())

Path Traversal

Vulnerable Code:

# ❌ VULNERABLE - Direct path concatenation
def read_file(filename):
    with open(f"/var/uploads/{filename}", "r") as f:
        return f.read()  # filename = "../../../etc/passwd"

# ❌ VULNERABLE - Insufficient validation
def download(path):
    if ".." in path:
        raise ValueError("Invalid path")  # Bypass: "..%2f" or "..\"
    return send_file(f"/files/{path}")

Secure Code:

# ✅ SECURE - Resolve and verify path
import os

UPLOAD_DIR = "/var/uploads"

def read_file(filename):
    # Resolve the full path
    safe_path = os.path.realpath(os.path.join(UPLOAD_DIR, filename))
    
    # Verify it's within allowed directory
    if not safe_path.startswith(os.path.realpath(UPLOAD_DIR)):
        raise ValueError("Path traversal detected")
    
    with open(safe_path, "r") as f:
        return f.read()

# ✅ SECURE - Use pathlib for cleaner handling
from pathlib import Path

def read_file(filename):
    base = Path(UPLOAD_DIR).resolve()
    target = (base / filename).resolve()
    
    if not str(target).startswith(str(base)):
        raise ValueError("Path traversal detected")
    
    return target.read_text()

Insecure Authentication

Vulnerable Code:

# ❌ VULNERABLE - Plain text password storage
def create_user(username, password):
    db.execute(
        "INSERT INTO users (username, password) VALUES (%s, %s)",
        (username, password)  # Plain text!
    )

# ❌ VULNERABLE - Weak hashing (MD5/SHA1)
import hashlib

def hash_password(password):
    return hashlib.md5(password.encode()).hexdigest()

# ❌ VULNERABLE - Timing attack in comparison
def verify_password(stored, provided):
    return stored == provided  # Timing attack possible

Secure Code:

# ✅ SECURE - bcrypt with salt
import bcrypt

def hash_password(password: str) -> bytes:
    salt = bcrypt.gensalt(rounds=12)
    return bcrypt.hashpw(password.encode(), salt)

def verify_password(stored_hash: bytes, password: str) -> bool:
    return bcrypt.checkpw(password.encode(), stored_hash)

# ✅ SECURE - Argon2 (recommended)
from argon2 import PasswordHasher

ph = PasswordHasher()

def hash_password(password: str) -> str:
    return ph.hash(password)

def verify_password(stored_hash: str, password: str) -> bool:
    try:
        ph.verify(stored_hash, password)
        return True
    except Exception:
        return False

# ✅ SECURE - Constant-time comparison
import hmac

def verify_token(stored, provided):
    return hmac.compare_digest(stored, provided)

Insecure Session Management

Vulnerable Code:

# ❌ VULNERABLE - Predictable session ID
def create_session(user_id):
    session_id = f"session_{user_id}_{int(time.time())}"
    return session_id

# ❌ VULNERABLE - Session fixation
@app.route('/login', methods=['POST'])
def login():
    if authenticate(request.form):
        session['user'] = request.form['username']
        # Session ID not regenerated!
        return redirect('/dashboard')

# ❌ VULNERABLE - Missing secure flags
response.set_cookie('session', session_id)  # No secure, httpOnly

Secure Code:

# ✅ SECURE - Cryptographic random session ID
import secrets

def create_session():
    return secrets.token_urlsafe(32)

# ✅ SECURE - Regenerate session on login
from flask import session

@app.route('/login', methods=['POST'])
def login():
    if authenticate(request.form):
        session.clear()  # Clear old session
        session.regenerate()  # New session ID
        session['user'] = request.form['username']
        return redirect('/dashboard')

# ✅ SECURE - Proper cookie flags
response.set_cookie(
    'session',
    session_id,
    secure=True,      # HTTPS only
    httponly=True,    # No JavaScript access
    samesite='Lax',   # CSRF protection
    max_age=3600,     # 1 hour expiry
    path='/',
    domain='.example.com'
)

CSRF Vulnerabilities

Vulnerable Code:

# ❌ VULNERABLE - No CSRF protection
@app.route('/transfer', methods=['POST'])
def transfer_money():
    amount = request.form['amount']
    to_account = request.form['to_account']
    perform_transfer(amount, to_account)
    return "Transfer complete"

Secure Code:

# ✅ SECURE - Flask-WTF CSRF protection
from flask_wtf import FlaskForm, CSRFProtect
from wtforms import StringField, DecimalField

csrf = CSRFProtect(app)

class TransferForm(FlaskForm):
    amount = DecimalField('Amount')
    to_account = StringField('To Account')

@app.route('/transfer', methods=['POST'])
def transfer_money():
    form = TransferForm()
    if form.validate_on_submit():  # Validates CSRF token
        perform_transfer(form.amount.data, form.to_account.data)
        return "Transfer complete"
    return "Invalid request", 400

# ✅ SECURE - Manual CSRF token
@app.route('/transfer', methods=['POST'])
def transfer_money():
    token = request.headers.get('X-CSRF-Token')
    if not verify_csrf_token(token):
        return "Invalid CSRF token", 403
    # Process request...

Secret Exposure

Vulnerable Code:

# ❌ VULNERABLE - Hardcoded credentials
DATABASE_URL = "postgresql://admin:SuperSecret123@db.example.com/prod"
API_KEY = "sk_live_abc123def456ghi789"
JWT_SECRET = "my-super-secret-key"

# ❌ VULNERABLE - Secrets in logs
logger.info(f"Connecting with password: {password}")
logger.debug(f"API response: {response.text}")  # May contain tokens

# ❌ VULNERABLE - Secrets in error messages
except Exception as e:
    return f"Database connection failed: {connection_string}"

Secure Code:

# ✅ SECURE - Environment variables
import os

DATABASE_URL = os.environ["DATABASE_URL"]
API_KEY = os.environ["API_KEY"]
JWT_SECRET = os.environ["JWT_SECRET"]

# ✅ SECURE - Secret management service
from aws_secrets import get_secret

DATABASE_URL = get_secret("prod/database/url")

# ✅ SECURE - Sanitized logging
logger.info("Connecting to database...")  # No credentials
logger.debug(f"API response status: {response.status_code}")

# ✅ SECURE - Generic error messages
except Exception as e:
    logger.error(f"Database error: {e}")  # Internal log only
    return "Database connection failed"  # Generic to user

Insecure Deserialization

Vulnerable Code:

# ❌ VULNERABLE - pickle with untrusted data
import pickle

def load_user_data(data):
    return pickle.loads(base64.b64decode(data))

# ❌ VULNERABLE - yaml.load without safe loader
import yaml

def parse_config(config_str):
    return yaml.load(config_str)  # Can execute arbitrary code!

# ❌ VULNERABLE - eval with user input
def calculate(expression):
    return eval(expression)  # expression = "__import__('os').system('rm -rf /')"

Secure Code:

# ✅ SECURE - JSON for serialization
import json

def load_user_data(data):
    return json.loads(data)  # Safe - no code execution

# ✅ SECURE - yaml.safe_load
import yaml

def parse_config(config_str):
    return yaml.safe_load(config_str)

# ✅ SECURE - Restricted evaluation
import ast

def calculate(expression):
    # Only allow simple math expressions
    tree = ast.parse(expression, mode='eval')
    for node in ast.walk(tree):
        if not isinstance(node, (ast.Expression, ast.BinOp, ast.Num,
                                   ast.Add, ast.Sub, ast.Mult, ast.Div)):
            raise ValueError("Invalid expression")
    return eval(compile(tree, '<string>', 'eval'))

SSRF (Server-Side Request Forgery)

Vulnerable Code:

# ❌ VULNERABLE - No URL validation
import requests

@app.route('/fetch')
def fetch_url():
    url = request.args.get('url')
    response = requests.get(url)  # url = "http://169.254.169.254/..."
    return response.text

Secure Code:

# ✅ SECURE - URL validation and allowlist
from urllib.parse import urlparse
import ipaddress

ALLOWED_HOSTS = ['api.example.com', 'cdn.example.com']
BLOCKED_RANGES = [
    ipaddress.ip_network('10.0.0.0/8'),
    ipaddress.ip_network('172.16.0.0/12'),
    ipaddress.ip_network('192.168.0.0/16'),
    ipaddress.ip_network('169.254.0.0/16'),  # AWS metadata
    ipaddress.ip_network('127.0.0.0/8'),
]

def is_safe_url(url):
    parsed = urlparse(url)
    
    # Check protocol
    if parsed.scheme not in ('http', 'https'):
        return False
    
    # Check against allowlist
    if parsed.hostname not in ALLOWED_HOSTS:
        return False
    
    # Resolve and check IP
    try:
        ip = ipaddress.ip_address(socket.gethostbyname(parsed.hostname))
        for blocked in BLOCKED_RANGES:
            if ip in blocked:
                return False
    except Exception:
        return False
    
    return True

@app.route('/fetch')
def fetch_url():
    url = request.args.get('url')
    if not is_safe_url(url):
        return "URL not allowed", 403
    response = requests.get(url, timeout=5)
    return response.text

Secret Detection Patterns

Common Secret Patterns

# AWS Access Key
AKIA[0-9A-Z]{16}

# AWS Secret Key
[A-Za-z0-9/+=]{40}

# GitHub Token
gh[pousr]_[A-Za-z0-9_]{36,255}

# Google API Key
AIza[0-9A-Za-z\-_]{35}

# Stripe Keys
sk_live_[0-9a-zA-Z]{24,}
pk_live_[0-9a-zA-Z]{24,}

# JWT
eyJ[A-Za-z0-9-_]+\.eyJ[A-Za-z0-9-_]+\.[A-Za-z0-9-_.+/]*

# Private Keys
-----BEGIN (RSA|DSA|EC|OPENSSH) PRIVATE KEY-----

# Generic Password in URL
[a-zA-Z]+://[^:]+:[^@]+@

# Slack Webhook
https://hooks\.slack\.com/services/T[A-Z0-9]+/B[A-Z0-9]+/[a-zA-Z0-9]+

Scanning Code for Secrets

import re
from pathlib import Path

SECRET_PATTERNS = {
    'aws_access_key': r'AKIA[0-9A-Z]{16}',
    'aws_secret_key': r'(?<![A-Za-z0-9/+=])[A-Za-z0-9/+=]{40}(?![A-Za-z0-9/+=])',
    'github_token': r'gh[pousr]_[A-Za-z0-9_]{36,255}',
    'google_api_key': r'AIza[0-9A-Za-z\-_]{35}',
    'stripe_key': r'[sr]k_live_[0-9a-zA-Z]{24,}',
    'jwt_token': r'eyJ[A-Za-z0-9-_]+\.eyJ[A-Za-z0-9-_]+\.[A-Za-z0-9-_.+/]*',
    'private_key': r'-----BEGIN (RSA|DSA|EC|OPENSSH) PRIVATE KEY-----',
    'password_in_url': r'[a-zA-Z]+://[^:]+:[^@]+@',
    'generic_secret': r'(?i)(password|secret|token|apikey|api_key)\s*[=:]\s*["\'][^"\']+["\']',
}

def scan_file(filepath: Path) -> list[dict]:
    findings = []
    content = filepath.read_text()
    lines = content.split('\n')
    
    for pattern_name, pattern in SECRET_PATTERNS.items():
        for line_num, line in enumerate(lines, 1):
            matches = re.finditer(pattern, line)
            for match in matches:
                findings.append({
                    'file': str(filepath),
                    'line': line_num,
                    'type': pattern_name,
                    'match': match.group()[:20] + '...',  # Truncate
                    'severity': 'CRITICAL'
                })
    
    return findings

Security Headers Check

Required Headers

SECURITY_HEADERS = {
    'Strict-Transport-Security': 'max-age=31536000; includeSubDomains',
    'X-Content-Type-Options': 'nosniff',
    'X-Frame-Options': 'DENY',
    'X-XSS-Protection': '1; mode=block',
    'Content-Security-Policy': "default-src 'self'",
    'Referrer-Policy': 'strict-origin-when-cross-origin',
    'Permissions-Policy': 'geolocation=(), camera=(), microphone=()',
}

def check_security_headers(response):
    findings = []
    for header, expected in SECURITY_HEADERS.items():
        actual = response.headers.get(header)
        if not actual:
            findings.append({
                'header': header,
                'status': 'MISSING',
                'severity': 'MEDIUM',
                'recommendation': f"Add header: {header}: {expected}"
            })
        elif actual != expected:
            findings.append({
                'header': header,
                'status': 'WEAK',
                'severity': 'LOW',
                'actual': actual,
                'expected': expected
            })
    return findings

Dependency Security Check

Known Vulnerable Packages

# Check against security advisories
npm audit
pip-audit
safety check
snyk test

Checking Dependencies

# Python - using pip-audit
import subprocess
import json

def check_dependencies():
    result = subprocess.run(
        ['pip-audit', '--format', 'json'],
        capture_output=True,
        text=True
    )
    vulnerabilities = json.loads(result.stdout)
    
    critical = []
    for vuln in vulnerabilities:
        if vuln['severity'] in ('CRITICAL', 'HIGH'):
            critical.append({
                'package': vuln['name'],
                'version': vuln['version'],
                'vulnerability': vuln['id'],
                'severity': vuln['severity'],
                'fix': vuln.get('fix_versions', ['Update required'])
            })
    
    return critical

Security Scan Checklist

Authentication & Authorization

  • Passwords hashed with bcrypt/Argon2/scrypt
  • No hardcoded credentials
  • Session tokens cryptographically random
  • Session regeneration on login
  • Proper session expiration
  • MFA available for sensitive actions
  • Rate limiting on auth endpoints
  • Account lockout after failed attempts
  • Proper access control on all endpoints
  • No privilege escalation paths

Input Validation

  • All user input validated
  • Parameterized queries for databases
  • Output encoding for XSS prevention
  • File upload restrictions (type, size)
  • Path traversal prevention
  • Command injection prevention
  • XML/JSON parsing hardened

Data Protection

  • Sensitive data encrypted at rest
  • TLS 1.2+ for data in transit
  • Proper key management
  • PII minimization
  • Secure backup practices
  • Data retention policies

Security Configuration

  • Debug mode disabled in production
  • Verbose errors disabled
  • Security headers configured
  • CORS properly restricted
  • Cookie flags set correctly
  • No default credentials

Logging & Monitoring

  • Security events logged
  • No sensitive data in logs
  • Log injection prevented
  • Alerting configured
  • Audit trail maintained

Dependencies

  • No known vulnerable packages
  • Dependencies regularly updated
  • Minimal dependencies
  • Dependency integrity verified

Output Format

When performing a security scan, provide:

# Security Scan Report

## Summary

| Severity | Count |
|----------|-------|
| 🔴 Critical | X |
| 🟠 High | Y |
| 🟡 Medium | Z |
| 🟢 Low | W |

## Executive Summary
[Brief overview of security posture and key findings]

---

## 🔴 Critical Findings

### Finding 1: [Title]
**Location:** `file.py:42`
**CWE:** CWE-89 (SQL Injection)
**CVSS:** 9.8

**Description:**
[Detailed description of the vulnerability]

**Vulnerable Code:**
```python
[Code snippet showing the issue]

Proof of Concept: [How this could be exploited]

Remediation:

[Code snippet showing the fix]

References:

  • [OWASP Link]
  • [CWE Link]

🟠 High Findings

[Same format as Critical]


🟡 Medium Findings

[Same format, can be more concise]


🟢 Low Findings

[Brief descriptions with recommendations]


Recommendations

Immediate Actions (24-48 hours)

  1. [Action 1]
  2. [Action 2]

Short-term (1-2 weeks)

  1. [Action 1]
  2. [Action 2]

Long-term (1-3 months)

  1. [Action 1]
  2. [Action 2]

Appendix

Tools Used

  • [Tool 1]
  • [Tool 2]

Scope

  • [What was reviewed]
  • [What was excluded]

## Notes

- Always prioritize findings by exploitability and impact
- Provide actionable remediation steps
- Consider the context (internal app vs public-facing)
- Check for security through obscurity (security theater)
- Verify fixes don't introduce new vulnerabilities
- Consider defense in depth - multiple layers of protection
- Remember: security is a process, not a destination

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.