<objective Defense-in-depth protection system for Claude Code. Uses PreToolUse hooks to intercept and validate tool calls before execution, blocking dangerous commands and protecting sensitive files. </objective <protection levels | Level | Read | Write | Edit | Delete | Use Case | |-------|------|-------|------|--------|----------| | zeroAccessPaths | No | No | No | No | Secrets, credentials, .env files | | readOnlyPaths | Yes | No | No | No | System configs, lock files, build artifacts | | noDeletePaths | Yes | Yes | Yes | No | Important project files, .git/, LICENSE | </protection levels <…

\n reason: Bare git push blocked — specify remote and branch explicitly (e.g. git push origin feature-branch)\n\n - pattern: '\\bgit\\s+stash\\s+clear\\b'\n reason: git stash clear (deletes ALL stashes)\n\n - pattern: '\\bgit\\s+reflog\\s+expire\\b'\n reason: git reflog expire (destroys recovery mechanism)\n\n - pattern: '\\bgit\\s+gc\\s+.*--prune=now'\n reason: git gc --prune=now (can lose dangling commits)\n\n - pattern: '\\bgit\\s+filter-branch\\b'\n reason: git filter-branch (rewrites entire history)\n\n # ---------------------------------------------------------------------------\n # GIT OPERATIONS REQUIRING CONFIRMATION (ask: true)\n # ---------------------------------------------------------------------------\n - pattern: '\\bgit\\s+checkout\\s+--\\s*\\.'\n reason: Discards all uncommitted changes\n ask: true\n\n - pattern: '\\bgit\\s+restore\\s+\\.'\n reason: Discards all uncommitted changes\n ask: true\n\n - pattern: '\\bgit\\s+stash\\s+drop\\b'\n reason: Permanently deletes a stash\n ask: true\n\n - pattern: '\\bgit\\s+branch\\s+(-[^\\s]*)*-D'\n reason: Force deletes branch (even if unmerged)\n ask: true\n\n - pattern: '\\bgit\\s+push\\s+\\S+\\s+--delete\\b'\n reason: Deletes remote branch\n ask: true\n\n - pattern: '\\bgit\\s+push\\s+\\S+\\s+:\\S+'\n reason: Deletes remote branch (old syntax)\n ask: true\n\n # ---------------------------------------------------------------------------\n # SYSTEM-LEVEL DESTRUCTION\n # ---------------------------------------------------------------------------\n - pattern: '\\bmkfs\\.'\n reason: filesystem format command\n\n - pattern: '\\bdd\\s+.*of=/dev/'\n reason: dd writing to device\n\n # ---------------------------------------------------------------------------\n # PROCESS DESTRUCTION\n # ---------------------------------------------------------------------------\n - pattern: '\\bkill\\s+-9\\s+-1\\b'\n reason: kill all processes\n\n - pattern: '\\bkillall\\s+-9\\b'\n reason: killall -9\n\n - pattern: '\\bpkill\\s+-9\\b'\n reason: pkill -9\n\n # ---------------------------------------------------------------------------\n # HISTORY/SHELL MANIPULATION\n # ---------------------------------------------------------------------------\n - pattern: '\\bhistory\\s+-c\\b'\n reason: clearing shell history\n\n # ---------------------------------------------------------------------------\n # ENVIRONMENT VARIABLE EXPOSURE (blocks reading secrets from env)\n # ---------------------------------------------------------------------------\n - pattern: '\\bprintenv\\b'\n reason: printenv exposes environment variables (may contain secrets)\n\n - pattern: '\\benv\\b(?!\\s+\\S+=)'\n reason: env command exposes environment variables (may contain secrets)\n\n - pattern: '\\bexport\\s+-p\\b'\n reason: export -p exposes all exported variables\n\n - pattern: '\\bexport\\s*

<objective Defense-in-depth protection system for Claude Code. Uses PreToolUse hooks to intercept and validate tool calls before execution, blocking dangerous commands and protecting sensitive files. </objective <protection levels | Level | Read | Write | Edit | Delete | Use Case | |-------|------|-------|------|--------|----------| | zeroAccessPaths | No | No | No | No | Secrets, credentials, .env files | | readOnlyPaths | Yes | No | No | No | System configs, lock files, build artifacts | | noDeletePaths | Yes | Yes | Yes | No | Important project files, .git/, LICENSE | </protection levels <…

\n reason: export without args exposes all exported variables\n\n - pattern: '\\bdeclare\\s+-x\\b'\n reason: declare -x exposes exported variables\n\n - pattern: '\\bset\\s*

<objective Defense-in-depth protection system for Claude Code. Uses PreToolUse hooks to intercept and validate tool calls before execution, blocking dangerous commands and protecting sensitive files. </objective <protection levels | Level | Read | Write | Edit | Delete | Use Case | |-------|------|-------|------|--------|----------| | zeroAccessPaths | No | No | No | No | Secrets, credentials, .env files | | readOnlyPaths | Yes | No | No | No | System configs, lock files, build artifacts | | noDeletePaths | Yes | Yes | Yes | No | Important project files, .git/, LICENSE | </protection levels <…

\n reason: set without args exposes shell variables\n\n - pattern: '\\bcompgen\\s+-e\\b'\n reason: compgen -e lists environment variable names\n\n - pattern: '\\becho\\s+\\$\\{?\\w*[A-Z_]+\\w*\\}?'\n reason: echo with env variable (may expose secrets)\n ask: true\n\n # ---------------------------------------------------------------------------\n # AWS CLI DESTRUCTIVE OPERATIONS\n # ---------------------------------------------------------------------------\n - pattern: '\\baws\\s+s3\\s+rm\\s+.*--recursive'\n reason: aws s3 rm --recursive (deletes all objects)\n\n - pattern: '\\baws\\s+s3\\s+rb\\s+.*--force'\n reason: aws s3 rb --force (force removes bucket)\n\n - pattern: '\\baws\\s+ec2\\s+terminate-instances\\b'\n reason: aws ec2 terminate-instances\n\n - pattern: '\\baws\\s+rds\\s+delete-db-instance\\b'\n reason: aws rds delete-db-instance\n\n - pattern: '\\baws\\s+cloudformation\\s+delete-stack\\b'\n reason: aws cloudformation delete-stack (deletes infrastructure)\n\n - pattern: '\\baws\\s+dynamodb\\s+delete-table\\b'\n reason: aws dynamodb delete-table\n\n - pattern: '\\baws\\s+eks\\s+delete-cluster\\b'\n reason: aws eks delete-cluster\n\n - pattern: '\\baws\\s+lambda\\s+delete-function\\b'\n reason: aws lambda delete-function\n\n - pattern: '\\baws\\s+iam\\s+delete-role\\b'\n reason: aws iam delete-role\n\n - pattern: '\\baws\\s+iam\\s+delete-user\\b'\n reason: aws iam delete-user\n\n # ---------------------------------------------------------------------------\n # GCP (gcloud) DESTRUCTIVE OPERATIONS\n # ---------------------------------------------------------------------------\n - pattern: '\\bgcloud\\s+projects\\s+delete\\b'\n reason: gcloud projects delete (DELETES ENTIRE PROJECT)\n\n - pattern: '\\bgcloud\\s+compute\\s+instances\\s+delete\\b'\n reason: gcloud compute instances delete\n\n - pattern: '\\bgcloud\\s+sql\\s+instances\\s+delete\\b'\n reason: gcloud sql instances delete\n\n - pattern: '\\bgcloud\\s+container\\s+clusters\\s+delete\\b'\n reason: gcloud container clusters delete (GKE)\n\n - pattern: '\\bgcloud\\s+storage\\s+rm\\s+.*-r'\n reason: gcloud storage rm -r (recursive delete)\n\n - pattern: '\\bgcloud\\s+functions\\s+delete\\b'\n reason: gcloud functions delete\n\n - pattern: '\\bgcloud\\s+iam\\s+service-accounts\\s+delete\\b'\n reason: gcloud iam service-accounts delete\n\n # ---------------------------------------------------------------------------\n # FIREBASE DESTRUCTIVE OPERATIONS\n # ---------------------------------------------------------------------------\n - pattern: '\\bfirebase\\s+projects:delete\\b'\n reason: firebase projects:delete (deletes entire project)\n\n - pattern: '\\bfirebase\\s+firestore:delete\\s+.*--all-collections'\n reason: firebase firestore:delete --all-collections (wipes all data)\n\n - pattern: '\\bfirebase\\s+database:remove\\b'\n reason: firebase database:remove (wipes Realtime DB)\n\n - pattern: '\\bfirebase\\s+hosting:disable\\b'\n reason: firebase hosting:disable\n\n - pattern: '\\bfirebase\\s+functions:delete\\b'\n reason: firebase functions:delete\n\n # ---------------------------------------------------------------------------\n # VERCEL DESTRUCTIVE OPERATIONS\n # ---------------------------------------------------------------------------\n - pattern: '\\bvercel\\s+remove\\s+.*--yes'\n reason: vercel remove --yes (removes deployment)\n\n - pattern: '\\bvercel\\s+projects\\s+rm\\b'\n reason: vercel projects rm (deletes project)\n\n - pattern: '\\bvercel\\s+env\\s+rm\\s+.*--yes'\n reason: vercel env rm --yes (removes env variables)\n\n # ---------------------------------------------------------------------------\n # NETLIFY DESTRUCTIVE OPERATIONS\n # ---------------------------------------------------------------------------\n - pattern: '\\bnetlify\\s+sites:delete\\b'\n reason: netlify sites:delete (deletes entire site)\n\n - pattern: '\\bnetlify\\s+functions:delete\\b'\n reason: netlify functions:delete\n\n # ---------------------------------------------------------------------------\n # CLOUDFLARE (wrangler) DESTRUCTIVE OPERATIONS\n # ---------------------------------------------------------------------------\n - pattern: '\\bwrangler\\s+delete\\b'\n reason: wrangler delete (deletes Worker)\n\n - pattern: '\\bwrangler\\s+r2\\s+bucket\\s+delete\\b'\n reason: wrangler r2 bucket delete\n\n - pattern: '\\bwrangler\\s+kv:namespace\\s+delete\\b'\n reason: wrangler kv:namespace delete\n\n - pattern: '\\bwrangler\\s+d1\\s+delete\\b'\n reason: wrangler d1 delete (deletes database)\n\n - pattern: '\\bwrangler\\s+queues\\s+delete\\b'\n reason: wrangler queues delete\n\n # ---------------------------------------------------------------------------\n # DOCKER DESTRUCTIVE OPERATIONS\n # ---------------------------------------------------------------------------\n - pattern: '\\bdocker\\s+system\\s+prune\\s+.*-a'\n reason: docker system prune -a (removes all unused data)\n\n - pattern: '\\bdocker\\s+rm\\s+.*-f.*\\$\\(docker\\s+ps'\n reason: docker rm -f $(docker ps) (force removes containers)\n\n - pattern: '\\bdocker\\s+rmi\\s+.*-f'\n reason: docker rmi -f (force removes images)\n\n - pattern: '\\bdocker\\s+volume\\s+rm\\b'\n reason: docker volume rm (data loss)\n\n - pattern: '\\bdocker\\s+volume\\s+prune\\b'\n reason: docker volume prune (removes unused volumes)\n\n # ---------------------------------------------------------------------------\n # KUBERNETES (kubectl) DESTRUCTIVE OPERATIONS\n # ---------------------------------------------------------------------------\n - pattern: '\\bkubectl\\s+delete\\s+namespace\\b'\n reason: kubectl delete namespace\n\n - pattern: '\\bkubectl\\s+delete\\s+all\\s+--all'\n reason: kubectl delete all --all\n\n - pattern: '\\bkubectl\\s+delete\\s+.*--all\\s+--all-namespaces'\n reason: kubectl delete across all namespaces\n\n - pattern: '\\bhelm\\s+uninstall\\b'\n reason: helm uninstall (removes release)\n\n # ---------------------------------------------------------------------------\n # DATABASE CLI DESTRUCTIVE OPERATIONS\n # ---------------------------------------------------------------------------\n - pattern: '\\bredis-cli\\s+FLUSHALL'\n reason: redis-cli FLUSHALL (wipes ALL data)\n\n - pattern: '\\bredis-cli\\s+FLUSHDB'\n reason: redis-cli FLUSHDB (wipes database)\n\n - pattern: '\\bmongosh.*dropDatabase'\n reason: MongoDB dropDatabase\n\n - pattern: '\\bmongo.*dropDatabase'\n reason: MongoDB dropDatabase\n\n - pattern: '\\bdropdb\\b'\n reason: PostgreSQL dropdb\n\n - pattern: '\\bmysqladmin\\s+drop\\b'\n reason: MySQL drop database\n\n # ---------------------------------------------------------------------------\n # INFRASTRUCTURE AS CODE DESTRUCTIVE OPERATIONS\n # ---------------------------------------------------------------------------\n - pattern: '\\bterraform\\s+destroy\\b'\n reason: terraform destroy (destroys all infrastructure)\n\n - pattern: '\\bpulumi\\s+destroy\\b'\n reason: pulumi destroy (destroys all resources)\n\n - pattern: '\\bserverless\\s+remove\\b'\n reason: serverless remove (removes stack)\n\n - pattern: '\\bsls\\s+remove\\b'\n reason: sls remove (removes stack)\n\n - pattern: '\\bsam\\s+delete\\b'\n reason: sam delete (deletes SAM application)\n\n # ---------------------------------------------------------------------------\n # HEROKU DESTRUCTIVE OPERATIONS\n # ---------------------------------------------------------------------------\n - pattern: '\\bheroku\\s+apps:destroy\\b'\n reason: heroku apps:destroy\n\n - pattern: '\\bheroku\\s+pg:reset\\b'\n reason: heroku pg:reset (resets database)\n\n # ---------------------------------------------------------------------------\n # OTHER CLOUD PLATFORMS DESTRUCTIVE OPERATIONS\n # ---------------------------------------------------------------------------\n - pattern: '\\bfly\\s+apps\\s+destroy\\b'\n reason: fly apps destroy (Fly.io)\n\n - pattern: '\\bfly\\s+destroy\\b'\n reason: fly destroy (Fly.io)\n\n - pattern: '\\bdoctl\\s+compute\\s+droplet\\s+delete\\b'\n reason: doctl droplet delete (DigitalOcean)\n\n - pattern: '\\bdoctl\\s+databases\\s+delete\\b'\n reason: doctl databases delete (DigitalOcean)\n\n - pattern: '\\bsupabase\\s+db\\s+reset\\b'\n reason: supabase db reset\n\n # ---------------------------------------------------------------------------\n # GITHUB CLI DESTRUCTIVE OPERATIONS\n # ---------------------------------------------------------------------------\n - pattern: '\\bgh\\s+repo\\s+delete\\b'\n reason: gh repo delete (deletes repository)\n\n # ---------------------------------------------------------------------------\n # PACKAGE REGISTRY DESTRUCTIVE OPERATIONS\n # ---------------------------------------------------------------------------\n - pattern: '\\bnpm\\s+unpublish\\b'\n reason: npm unpublish (removes package from registry)\n\n # ---------------------------------------------------------------------------\n # SQL DESTRUCTIVE OPERATIONS (catastrophic - no WHERE clause)\n # ---------------------------------------------------------------------------\n - pattern: 'DELETE\\s+FROM\\s+\\w+\\s*;'\n reason: DELETE without WHERE clause (will delete ALL rows)\n\n - pattern: 'DELETE\\s+FROM\\s+\\w+\\s*

<objective Defense-in-depth protection system for Claude Code. Uses PreToolUse hooks to intercept and validate tool calls before execution, blocking dangerous commands and protecting sensitive files. </objective <protection levels | Level | Read | Write | Edit | Delete | Use Case | |-------|------|-------|------|--------|----------| | zeroAccessPaths | No | No | No | No | Secrets, credentials, .env files | | readOnlyPaths | Yes | No | No | No | System configs, lock files, build artifacts | | noDeletePaths | Yes | Yes | Yes | No | Important project files, .git/, LICENSE | </protection levels <…

\n reason: DELETE without WHERE clause (will delete ALL rows)\n\n - pattern: 'DELETE\\s+\\*\\s+FROM'\n reason: DELETE * (will delete ALL rows)\n\n - pattern: '\\bTRUNCATE\\s+TABLE\\b'\n reason: TRUNCATE TABLE (will delete ALL rows)\n\n - pattern: '\\bDROP\\s+TABLE\\b'\n reason: DROP TABLE\n\n - pattern: '\\bDROP\\s+DATABASE\\b'\n reason: DROP DATABASE\n\n # ---------------------------------------------------------------------------\n # SQL OPERATIONS REQUIRING CONFIRMATION (ask: true)\n # ---------------------------------------------------------------------------\n - pattern: '\\bDELETE\\s+FROM\\s+\\w+\\s+WHERE\\b.*\\bid\\s*='\n reason: SQL DELETE with specific ID\n ask: true\n\n# ---------------------------------------------------------------------------\n# ZERO ACCESS PATHS - No read, write, or any access allowed\n# ---------------------------------------------------------------------------\n# These contain secrets/credentials - block ALL operations including reads\n# Enforced by: Bash, Edit, Write tools\n# Supports glob patterns: *.pem, .env*, *-credentials.json\nzeroAccessPaths:\n # ---------------------------------------------------------------------------\n # ENVIRONMENT FILES (HIGH RISK - contain secrets)\n # ---------------------------------------------------------------------------\n - \".env\"\n - \".env.*\"\n - \".env*.local\"\n - \"*.env\"\n\n # ---------------------------------------------------------------------------\n # SSH KEYS AND CONFIG\n # ---------------------------------------------------------------------------\n - \"~/.ssh/\"\n\n # ---------------------------------------------------------------------------\n # GPG KEYS\n # ---------------------------------------------------------------------------\n - \"~/.gnupg/\"\n\n # ---------------------------------------------------------------------------\n # CLOUD PROVIDER CREDENTIALS\n # ---------------------------------------------------------------------------\n # AWS\n - \"~/.aws/\"\n\n # GCP\n - \"~/.config/gcloud/\"\n - \"*-credentials.json\"\n - \"*serviceAccount*.json\"\n - \"*service-account*.json\"\n\n # Azure\n - \"~/.azure/\"\n\n # Kubernetes\n - \"kubeconfig\"\n - \"*-secret.yaml\"\n - \"secrets.yaml\"\n\n # Docker\n - \"~/.docker/\"\n\n # ---------------------------------------------------------------------------\n # SSL/TLS CERTIFICATES AND PRIVATE KEYS\n # ---------------------------------------------------------------------------\n - \"*.pem\"\n - \"*.key\"\n - \"*.p12\"\n - \"*.pfx\"\n\n # ---------------------------------------------------------------------------\n # TERRAFORM STATE (contains secrets in plaintext!)\n # ---------------------------------------------------------------------------\n - \"*.tfstate\"\n - \"*.tfstate.backup\"\n - \".terraform/\"\n\n # ---------------------------------------------------------------------------\n # PLATFORM TOKENS (Vercel, Netlify, etc.)\n # ---------------------------------------------------------------------------\n - \".vercel/\"\n - \".netlify/\"\n\n # ---------------------------------------------------------------------------\n # FIREBASE/SUPABASE\n # ---------------------------------------------------------------------------\n - \"firebase-adminsdk*.json\"\n - \"serviceAccountKey.json\"\n - \".supabase/\"\n\n # ---------------------------------------------------------------------------\n # PACKAGE MANAGER AUTH & CREDENTIALS\n # ---------------------------------------------------------------------------\n - \"~/.netrc\"\n - \"~/.npmrc\"\n - \"~/.pypirc\"\n - \"~/.git-credentials\"\n - \".git-credentials\"\n\n # ---------------------------------------------------------------------------\n # DATABASE DUMPS (may contain production data)\n # ---------------------------------------------------------------------------\n - \"dump.sql\"\n - \"backup.sql\"\n - \"*.dump\"\n\n# ---------------------------------------------------------------------------\n# READ-ONLY PATHS - Can read, but not write/edit/delete\n# ---------------------------------------------------------------------------\n# Safe to read but should never be modified by AI\n# Enforced by: Bash, Edit, Write tools\n# Supports glob patterns: *.lock, *.min.js\nreadOnlyPaths:\n # ---------------------------------------------------------------------------\n # SYSTEM DIRECTORIES\n # ---------------------------------------------------------------------------\n - /etc/\n - /usr/\n - /bin/\n - /sbin/\n - /boot/\n - /root/\n\n # ---------------------------------------------------------------------------\n # KUBERNETES CONFIG (read-only for kubectl get/describe)\n # ---------------------------------------------------------------------------\n - ~/.kube/\n\n # ---------------------------------------------------------------------------\n # SHELL HISTORY FILES\n # ---------------------------------------------------------------------------\n - ~/.bash_history\n - ~/.zsh_history\n - ~/.node_repl_history\n\n # ---------------------------------------------------------------------------\n # SHELL CONFIG FILES\n # ---------------------------------------------------------------------------\n - ~/.bashrc\n - ~/.zshrc\n - ~/.profile\n - ~/.bash_profile\n\n # ---------------------------------------------------------------------------\n # LOCK FILES - Never manually edit, use package managers\n # ---------------------------------------------------------------------------\n - \"package-lock.json\"\n - \"yarn.lock\"\n - \"pnpm-lock.yaml\"\n - \"Gemfile.lock\"\n - \"poetry.lock\"\n - \"Pipfile.lock\"\n - \"composer.lock\"\n - \"Cargo.lock\"\n - \"go.sum\"\n - \"flake.lock\"\n - \"bun.lockb\"\n - \"uv.lock\"\n - \"npm-shrinkwrap.json\"\n - \"*.lock\"\n - \"*.lockb\"\n\n # ---------------------------------------------------------------------------\n # MINIFIED/COMPILED FILES - Generated, don't edit\n # ---------------------------------------------------------------------------\n - \"*.min.js\"\n - \"*.min.css\"\n - \"*.bundle.js\"\n - \"*.chunk.js\"\n\n # ---------------------------------------------------------------------------\n # BUILD ARTIFACTS - Generated directories, don't edit\n # ---------------------------------------------------------------------------\n - dist/\n - build/\n - out/\n - .next/\n - .nuxt/\n - .output/\n - node_modules/\n - __pycache__/\n - .venv/\n - venv/\n - target/\n\n# ---------------------------------------------------------------------------\n# NO-DELETE PATHS - Can read/write/edit, but not delete\n# ---------------------------------------------------------------------------\n# Protect important files from accidental deletion\n# Enforced by: Bash tool only (Edit/Write don't delete files)\n# Supports glob patterns: *.md, LICENSE*\nnoDeletePaths:\n # ---------------------------------------------------------------------------\n # CLAUDE CODE CONFIGURATION\n # ---------------------------------------------------------------------------\n - ~/.claude/\n - CLAUDE.md\n\n # ---------------------------------------------------------------------------\n # LICENSE AND LEGAL FILES\n # ---------------------------------------------------------------------------\n - \"LICENSE\"\n - \"LICENSE.*\"\n - \"COPYING\"\n - \"COPYING.*\"\n - \"NOTICE\"\n - \"PATENTS\"\n\n # ---------------------------------------------------------------------------\n # PROJECT DOCUMENTATION\n # ---------------------------------------------------------------------------\n - \"README.md\"\n - \"README.*\"\n - \"CONTRIBUTING.md\"\n - \"CHANGELOG.md\"\n - \"CODE_OF_CONDUCT.md\"\n - \"SECURITY.md\"\n\n # ---------------------------------------------------------------------------\n # GIT DIRECTORY\n # ---------------------------------------------------------------------------\n - .git/\n - .gitignore\n - .gitattributes\n - .gitmodules\n\n # ---------------------------------------------------------------------------\n # CI/CD CONFIGURATION\n # ---------------------------------------------------------------------------\n - .github/\n - .gitlab-ci.yml\n - .circleci/\n - Jenkinsfile\n - .travis.yml\n - azure-pipelines.yml\n\n # ---------------------------------------------------------------------------\n # DOCKER CONFIGURATION\n # ---------------------------------------------------------------------------\n - Dockerfile\n - \"Dockerfile.*\"\n - docker-compose.yml\n - \"docker-compose.*.yml\"\n - .dockerignore\n\n # ---------------------------------------------------------------------------\n # COMMON PROJECT DIRECTORIES (uncomment to enable)\n # ---------------------------------------------------------------------------\n # - src/\n # - lib/\n # - app/\n # - tests/\n # - docs/\n","content_type":"application/yaml; charset=utf-8","language":"yaml","size":22540,"content_sha256":"4e1b29dd4f273470b9f8404876a42cc9d1fcff05f793e6197ecb19b66448fe7d"},{"filename":"scripts/read-tool-damage-control.py","content":"# /// script\n# requires-python = \">=3.8\"\n# dependencies = [\"pyyaml\"]\n# ///\n\"\"\"\nClaude Code Read Tool Damage Control\n=====================================\n\nBlocks reads from zero-access files via PreToolUse hook on Read tool.\nLoads zeroAccessPaths from patterns.yaml.\n\nNote: readOnlyPaths are NOT blocked - they allow reading but not writing.\n\nExit codes:\n 0 = Allow read\n 2 = Block read (stderr fed back to Claude)\n\"\"\"\n\nimport json\nimport sys\nimport os\nimport fnmatch\nfrom pathlib import Path\nfrom typing import Dict, Any, Tuple\n\nimport yaml\n\n\ndef is_glob_pattern(pattern: str) -> bool:\n \"\"\"Check if pattern contains glob wildcards.\"\"\"\n return '*' in pattern or '?' in pattern or '[' in pattern\n\n\ndef match_path(file_path: str, pattern: str) -> bool:\n \"\"\"Match file path against pattern, supporting both prefix and glob matching.\"\"\"\n expanded_pattern = os.path.expanduser(pattern)\n normalized = os.path.normpath(file_path)\n expanded_normalized = os.path.expanduser(normalized)\n\n if is_glob_pattern(pattern):\n # Glob pattern matching (case-insensitive for security)\n basename = os.path.basename(expanded_normalized)\n basename_lower = basename.lower()\n pattern_lower = pattern.lower()\n expanded_pattern_lower = expanded_pattern.lower()\n\n # Match against basename for patterns like *.pem, .env*\n if fnmatch.fnmatch(basename_lower, expanded_pattern_lower):\n return True\n if fnmatch.fnmatch(basename_lower, pattern_lower):\n return True\n # Also try full path match for patterns like /path/*.pem\n if fnmatch.fnmatch(expanded_normalized.lower(), expanded_pattern_lower):\n return True\n return False\n else:\n # Prefix matching (original behavior for directories)\n if expanded_normalized.startswith(expanded_pattern) or expanded_normalized == expanded_pattern.rstrip('/'):\n return True\n return False\n\n\ndef get_config_path() -> Path:\n \"\"\"Get path to patterns.yaml, checking multiple locations.\"\"\"\n # 1. Check project hooks directory (installed location)\n project_dir = os.environ.get(\"CLAUDE_PROJECT_DIR\")\n if project_dir:\n project_config = Path(project_dir) / \".claude\" / \"hooks\" / \"damage-control\" / \"patterns.yaml\"\n if project_config.exists():\n return project_config\n\n # 2. Check script's own directory (installed location)\n script_dir = Path(__file__).parent\n local_config = script_dir / \"patterns.yaml\"\n if local_config.exists():\n return local_config\n\n # 3. Check skill root directory (development location)\n skill_root = script_dir.parent.parent / \"patterns.yaml\"\n if skill_root.exists():\n return skill_root\n\n return local_config # Default, even if it doesn't exist\n\n\ndef load_config() -> Dict[str, Any]:\n \"\"\"Load config from YAML.\"\"\"\n config_path = get_config_path()\n\n if not config_path.exists():\n return {\"zeroAccessPaths\": []}\n\n with open(config_path, \"r\") as f:\n config = yaml.safe_load(f) or {}\n\n return config\n\n\ndef check_path(file_path: str, config: Dict[str, Any]) -> Tuple[bool, str]:\n \"\"\"Check if file_path is blocked for reading. Returns (blocked, reason).\"\"\"\n # Only check zero-access paths (completely blocked from all operations)\n # readOnlyPaths are allowed to be read - that's the point of \"read-only\"\n for zero_path in config.get(\"zeroAccessPaths\", []):\n if match_path(file_path, zero_path):\n return True, f\"zero-access path {zero_path} (no operations allowed)\"\n\n return False, \"\"\n\n\ndef main() -> None:\n config = load_config()\n\n try:\n input_data = json.load(sys.stdin)\n except json.JSONDecodeError as e:\n print(f\"Error: Invalid JSON input: {e}\", file=sys.stderr)\n sys.exit(1)\n\n tool_name = input_data.get(\"tool_name\", \"\")\n tool_input = input_data.get(\"tool_input\", {})\n\n # Only check Read tool\n if tool_name != \"Read\":\n sys.exit(0)\n\n file_path = tool_input.get(\"file_path\", \"\")\n if not file_path:\n sys.exit(0)\n\n blocked, reason = check_path(file_path, config)\n if blocked:\n print(f\"SECURITY: Blocked read from {reason}: {file_path}\", file=sys.stderr)\n sys.exit(2)\n\n sys.exit(0)\n\n\nif __name__ == \"__main__\":\n main()\n","content_type":"text/x-python; charset=utf-8","language":"python","size":4320,"content_sha256":"26a2cbc4a8505d8d5e0d9aa6f50b5ab57dd2014842bcdb102496f0c37b89c147"},{"filename":"scripts/settings-template.json","content":"{\n \"hooks\": {\n \"PreToolUse\": [\n {\n \"matcher\": \"Bash\",\n \"hooks\": [\n {\n \"type\": \"command\",\n \"command\": \"uv run ~/.claude/hooks/damage-control/bash-tool-damage-control.py\",\n \"timeout\": 5\n }\n ]\n },\n {\n \"matcher\": \"Edit\",\n \"hooks\": [\n {\n \"type\": \"command\",\n \"command\": \"uv run ~/.claude/hooks/damage-control/edit-tool-damage-control.py\",\n \"timeout\": 5\n }\n ]\n },\n {\n \"matcher\": \"Write\",\n \"hooks\": [\n {\n \"type\": \"command\",\n \"command\": \"uv run ~/.claude/hooks/damage-control/write-tool-damage-control.py\",\n \"timeout\": 5\n }\n ]\n },\n {\n \"matcher\": \"Read\",\n \"hooks\": [\n {\n \"type\": \"command\",\n \"command\": \"uv run ~/.claude/hooks/damage-control/read-tool-damage-control.py\",\n \"timeout\": 5\n }\n ]\n }\n ]\n },\n \"permissions\": {\n \"deny\": [\n \"Bash(rm -rf /*:*)\",\n \"Bash(rm -rf ~/*:*)\",\n \"Bash(sudo rm -rf:*)\",\n \"Bash(mkfs:*)\",\n \"Bash(dd if=* of=/dev/*:*)\"\n ],\n \"ask\": [\n \"Bash(git push --force:*)\",\n \"Bash(git reset --hard:*)\"\n ]\n }\n}\n","content_type":"application/json; charset=utf-8","language":"json","size":1299,"content_sha256":"19574fe6dbc0a1e9a2fe617e09ad8a6c06e5eb3307aa683d282200be963dd1ed"},{"filename":"scripts/test-damage-control.py","content":"# /// script\n# requires-python = \">=3.8\"\n# dependencies = [\"pyyaml\"]\n# ///\n\"\"\"\nDamage Control Test Runner - Python/UV\n=======================================\n\nTests damage control hooks via CLI or interactive mode.\n\nUsage:\n # Interactive mode - test Bash, Edit, Write hooks interactively\n uv run test-damage-control.py -i\n uv run test-damage-control.py --interactive\n\n # CLI mode - test a single command\n uv run test-damage-control.py \u003chook> \u003ctool_name> \u003ccommand_or_path> [--expect-blocked|--expect-allowed]\n\nExamples:\n # Interactive mode\n uv run test-damage-control.py -i\n\n # Test bash hook blocks rm -rf\n uv run test-damage-control.py bash Bash \"rm -rf /tmp\" --expect-blocked\n\n # Test edit hook blocks zero-access path\n uv run test-damage-control.py edit Edit \"~/.ssh/id_rsa\" --expect-blocked\n\n # Test bash allows safe command\n uv run test-damage-control.py bash Bash \"ls -la\" --expect-allowed\n\nExit codes:\n 0 = Test passed (expectation matched)\n 1 = Test failed (expectation not matched)\n\"\"\"\n\nimport subprocess\nimport json\nimport sys\nimport os\nimport re\nfrom pathlib import Path\nfrom typing import Dict, Any, List, Tuple, Optional\n\nimport yaml\n\n\n# Import patterns and utilities from the bash tool script (avoid duplication)\n# Using importlib to import from hyphenated filename\nimport importlib.util\nimport fnmatch\n\nspec = importlib.util.spec_from_file_location(\n \"bash_tool\",\n Path(__file__).parent / \"bash-tool-damage-control.py\"\n)\nbash_tool = importlib.util.module_from_spec(spec)\nspec.loader.exec_module(bash_tool)\n\nREAD_ONLY_BLOCKED = bash_tool.READ_ONLY_BLOCKED\nNO_DELETE_BLOCKED = bash_tool.NO_DELETE_BLOCKED\n\n\ndef is_glob_pattern(pattern: str) -> bool:\n \"\"\"Check if pattern contains glob wildcards.\"\"\"\n return '*' in pattern or '?' in pattern or '[' in pattern\n\n\ndef match_path(file_path: str, pattern: str) -> bool:\n \"\"\"Match file path against pattern, supporting both prefix and glob matching.\"\"\"\n expanded_pattern = os.path.expanduser(pattern)\n normalized = os.path.normpath(file_path)\n expanded_normalized = os.path.expanduser(normalized)\n\n if is_glob_pattern(pattern):\n # Glob pattern matching (case-insensitive for security)\n basename = os.path.basename(expanded_normalized)\n basename_lower = basename.lower()\n pattern_lower = pattern.lower()\n expanded_pattern_lower = expanded_pattern.lower()\n\n # Match against basename for patterns like *.pem, .env*\n if fnmatch.fnmatch(basename_lower, expanded_pattern_lower):\n return True\n if fnmatch.fnmatch(basename_lower, pattern_lower):\n return True\n # Also try full path match for patterns like /path/*.pem\n if fnmatch.fnmatch(expanded_normalized.lower(), expanded_pattern_lower):\n return True\n return False\n else:\n # Prefix matching (original behavior for directories)\n if expanded_normalized.startswith(expanded_pattern) or expanded_normalized == expanded_pattern.rstrip('/'):\n return True\n return False\n\n\ndef glob_to_regex(glob_pattern: str) -> str:\n \"\"\"Convert a glob pattern to a regex pattern for matching in commands.\"\"\"\n result = \"\"\n for char in glob_pattern:\n if char == '*':\n result += r'[^\\s/]*' # Match any chars except whitespace and path sep\n elif char == '?':\n result += r'[^\\s/]' # Match single char except whitespace and path sep\n elif char in r'\\.^$+{}[]|()':\n result += '\\\\' + char\n else:\n result += char\n return result\n\n\n# ============================================================================\n# CONFIG LOADING\n# ============================================================================\n\ndef get_script_dir() -> Path:\n return Path(__file__).parent\n\n\ndef get_config_path() -> Path:\n \"\"\"Get path to patterns.yaml, checking multiple locations.\"\"\"\n script_dir = get_script_dir()\n\n # 1. Check script's own directory (installed location)\n local_config = script_dir / \"patterns.yaml\"\n if local_config.exists():\n return local_config\n\n # 2. Check skill root directory (development location)\n skill_root = script_dir.parent.parent / \"patterns.yaml\"\n if skill_root.exists():\n return skill_root\n\n return local_config # Default, even if it doesn't exist\n\n\ndef load_config() -> Dict[str, Any]:\n \"\"\"Load patterns from YAML config file.\"\"\"\n config_path = get_config_path()\n\n if not config_path.exists():\n return {\"bashToolPatterns\": [], \"zeroAccessPaths\": [], \"readOnlyPaths\": [], \"noDeletePaths\": []}\n\n with open(config_path, \"r\") as f:\n return yaml.safe_load(f) or {}\n\n\n# ============================================================================\n# DIRECT CHECKING (for interactive mode - no subprocess needed)\n# ============================================================================\n\ndef check_bash_command(command: str, config: Dict[str, Any]) -> Tuple[bool, List[str]]:\n \"\"\"Check bash command against patterns. Returns (blocked, list of reasons).\"\"\"\n reasons = []\n\n # 1. Check bashToolPatterns\n for item in config.get(\"bashToolPatterns\", []):\n pattern = item.get(\"pattern\", \"\")\n reason = item.get(\"reason\", \"Blocked by pattern\")\n try:\n if re.search(pattern, command, re.IGNORECASE):\n reasons.append(reason)\n except re.error:\n continue\n\n # 2. Check zeroAccessPaths (any access blocked) - supports glob patterns\n for zero_path in config.get(\"zeroAccessPaths\", []):\n if is_glob_pattern(zero_path):\n # Convert glob to regex for command matching\n glob_regex = glob_to_regex(zero_path)\n try:\n if re.search(glob_regex, command, re.IGNORECASE):\n reasons.append(f\"zero-access pattern: {zero_path}\")\n except re.error:\n continue\n else:\n # Original literal path matching\n expanded = os.path.expanduser(zero_path)\n escaped = re.escape(expanded)\n if re.search(escaped, command) or re.search(re.escape(zero_path), command):\n reasons.append(f\"zero-access path: {zero_path}\")\n\n # 3. Check readOnlyPaths (modifications blocked)\n for readonly in config.get(\"readOnlyPaths\", []):\n expanded = os.path.expanduser(readonly)\n escaped = re.escape(expanded)\n for pattern_template, operation in READ_ONLY_BLOCKED:\n pattern = pattern_template.replace(\"{path}\", escaped)\n try:\n if re.search(pattern, command):\n reasons.append(f\"{operation} on read-only path: {readonly}\")\n except re.error:\n continue\n\n # 4. Check noDeletePaths (deletions blocked)\n for no_delete in config.get(\"noDeletePaths\", []):\n expanded = os.path.expanduser(no_delete)\n escaped = re.escape(expanded)\n for pattern_template, operation in NO_DELETE_BLOCKED:\n pattern = pattern_template.replace(\"{path}\", escaped)\n try:\n if re.search(pattern, command):\n reasons.append(f\"{operation} on no-delete path: {no_delete}\")\n except re.error:\n continue\n\n return len(reasons) > 0, reasons\n\n\ndef check_file_path(file_path: str, config: Dict[str, Any]) -> Tuple[bool, List[str]]:\n \"\"\"Check file path for Edit/Write tools. Returns (blocked, list of reasons).\"\"\"\n reasons = []\n\n # Check zeroAccessPaths - supports glob patterns\n for zero_path in config.get(\"zeroAccessPaths\", []):\n if match_path(file_path, zero_path):\n reasons.append(f\"zero-access path: {zero_path}\")\n\n # Check readOnlyPaths - supports glob patterns\n for readonly in config.get(\"readOnlyPaths\", []):\n if match_path(file_path, readonly):\n reasons.append(f\"read-only path: {readonly}\")\n\n return len(reasons) > 0, reasons\n\n\n# ============================================================================\n# INTERACTIVE MODE\n# ============================================================================\n\ndef print_banner():\n \"\"\"Print interactive mode banner.\"\"\"\n print(\"\\n\" + \"=\" * 60)\n print(\" Damage Control Interactive Tester\")\n print(\"=\" * 60)\n print(\" Test commands and paths against security patterns.\")\n print(\" Type 'quit' or 'q' to exit.\")\n print(\"=\" * 60 + \"\\n\")\n\n\ndef prompt_tool_selection() -> Optional[str]:\n \"\"\"Prompt user to select which tool to test.\"\"\"\n print(\"Select tool to test:\")\n print(\" [1] Bash - Test shell commands\")\n print(\" [2] Edit - Test file paths for edit operations\")\n print(\" [3] Write - Test file paths for write operations\")\n print(\" [q] Quit\")\n print()\n\n while True:\n choice = input(\"Tool [1/2/3/q]> \").strip().lower()\n\n if choice in ('q', 'quit'):\n return None\n elif choice == '1' or choice == 'bash':\n return 'Bash'\n elif choice == '2' or choice == 'edit':\n return 'Edit'\n elif choice == '3' or choice == 'write':\n return 'Write'\n else:\n print(\"Invalid choice. Enter 1, 2, 3, or q.\")\n\n\ndef run_interactive_mode():\n \"\"\"Run interactive testing mode.\"\"\"\n config = load_config()\n print_banner()\n\n # Show loaded config summary\n bash_patterns = len(config.get(\"bashToolPatterns\", []))\n zero_paths = len(config.get(\"zeroAccessPaths\", []))\n readonly_paths = len(config.get(\"readOnlyPaths\", []))\n nodelete_paths = len(config.get(\"noDeletePaths\", []))\n print(f\"Loaded: {bash_patterns} bash patterns, {zero_paths} zero-access, {readonly_paths} read-only, {nodelete_paths} no-delete paths\\n\")\n\n while True:\n tool = prompt_tool_selection()\n if tool is None:\n print(\"\\nGoodbye!\")\n break\n\n print()\n if tool == 'Bash':\n prompt_text = \"Command> \"\n else:\n prompt_text = \"Path> \"\n\n # Get input\n try:\n user_input = input(prompt_text).strip()\n except (EOFError, KeyboardInterrupt):\n print(\"\\nGoodbye!\")\n break\n\n if not user_input or user_input.lower() in ('q', 'quit'):\n print(\"\\nGoodbye!\")\n break\n\n # Test the input\n if tool == 'Bash':\n blocked, reasons = check_bash_command(user_input, config)\n else:\n blocked, reasons = check_file_path(user_input, config)\n\n # Print result\n print()\n if blocked:\n print(f\"\\033[91mBLOCKED\\033[0m - {len(reasons)} pattern(s) matched:\")\n for reason in reasons:\n print(f\" - {reason}\")\n else:\n print(f\"\\033[92mALLOWED\\033[0m - No dangerous patterns matched\")\n print()\n\n\n# ============================================================================\n# CLI MODE HELPERS\n# ============================================================================\n\ndef get_hook_path(hook_type: str) -> Path:\n \"\"\"Get path to hook script.\"\"\"\n hooks = {\n \"bash\": \"bash-tool-damage-control.py\",\n \"edit\": \"edit-tool-damage-control.py\",\n \"write\": \"write-tool-damage-control.py\",\n }\n if hook_type not in hooks:\n print(f\"Error: Unknown hook type '{hook_type}'. Use: {list(hooks.keys())}\")\n sys.exit(1)\n return get_script_dir() / hooks[hook_type]\n\n\ndef build_tool_input(tool_name: str, value: str) -> dict:\n \"\"\"Build tool_input based on tool type.\"\"\"\n if tool_name == \"Bash\":\n return {\"command\": value}\n elif tool_name in (\"Edit\", \"Write\"):\n # Expand ~ for paths\n return {\"file_path\": os.path.expanduser(value)}\n else:\n return {\"command\": value}\n\n\ndef run_test(hook_type: str, tool_name: str, value: str, expectation: str) -> bool:\n \"\"\"Run a single test and return True if passed.\n\n expectation can be: \"blocked\" or \"allowed\" (exit code based)\n \"\"\"\n hook_path = get_hook_path(hook_type)\n tool_input = build_tool_input(tool_name, value)\n\n input_json = json.dumps({\n \"tool_name\": tool_name,\n \"tool_input\": tool_input\n })\n\n try:\n result = subprocess.run(\n [\"uv\", \"run\", str(hook_path)],\n input=input_json,\n capture_output=True,\n text=True,\n timeout=10\n )\n exit_code = result.returncode\n stdout = result.stdout.strip()\n stderr = result.stderr.strip()\n except subprocess.TimeoutExpired:\n print(\"TIMEOUT\")\n return False\n except Exception as e:\n print(f\"ERROR: {e}\")\n return False\n\n # Handle PreToolUse hooks (exit code based)\n blocked = exit_code == 2\n expect_blocked = expectation == \"blocked\"\n passed = blocked == expect_blocked\n\n expected = \"BLOCKED\" if expect_blocked else \"ALLOWED\"\n actual = \"BLOCKED\" if blocked else \"ALLOWED\"\n\n if passed:\n print(f\"PASS: {expected} - {value}\")\n else:\n print(f\"FAIL: Expected {expected}, got {actual} - {value}\")\n if stderr:\n print(f\" stderr: {stderr[:200]}\")\n\n return passed\n\n\ndef main():\n # Check for interactive mode\n if len(sys.argv) >= 2 and sys.argv[1].lower() in ('-i', '--interactive'):\n run_interactive_mode()\n sys.exit(0)\n\n # CLI mode requires at least 4 args\n if len(sys.argv) \u003c 4:\n print(__doc__)\n sys.exit(1)\n\n hook_type = sys.argv[1].lower()\n tool_name = sys.argv[2]\n value = sys.argv[3]\n\n # Default expectation\n expectation = \"blocked\"\n\n if len(sys.argv) > 4:\n flag = sys.argv[4].lower()\n if flag == \"--expect-allowed\":\n expectation = \"allowed\"\n elif flag == \"--expect-blocked\":\n expectation = \"blocked\"\n\n passed = run_test(hook_type, tool_name, value, expectation)\n sys.exit(0 if passed else 1)\n\n\nif __name__ == \"__main__\":\n main()\n","content_type":"text/x-python; charset=utf-8","language":"python","size":13939,"content_sha256":"34b1b1020baa1f54900e621882f2271ef35c94e24170bfb46f56517263fc1538"},{"filename":"scripts/write-tool-damage-control.py","content":"# /// script\n# requires-python = \">=3.8\"\n# dependencies = [\"pyyaml\"]\n# ///\n\"\"\"\nClaude Code Write Tool Damage Control\n======================================\n\nBlocks writes to protected files via PreToolUse hook on Write tool.\nLoads zeroAccessPaths and readOnlyPaths from patterns.yaml.\n\nExit codes:\n 0 = Allow write\n 2 = Block write (stderr fed back to Claude)\n\"\"\"\n\nimport json\nimport sys\nimport os\nimport fnmatch\nfrom pathlib import Path\nfrom typing import Dict, Any, List, Tuple\n\nimport yaml\n\n\ndef is_glob_pattern(pattern: str) -> bool:\n \"\"\"Check if pattern contains glob wildcards.\"\"\"\n return '*' in pattern or '?' in pattern or '[' in pattern\n\n\ndef match_path(file_path: str, pattern: str) -> bool:\n \"\"\"Match file path against pattern, supporting both prefix and glob matching.\"\"\"\n expanded_pattern = os.path.expanduser(pattern)\n normalized = os.path.normpath(file_path)\n expanded_normalized = os.path.expanduser(normalized)\n\n if is_glob_pattern(pattern):\n # Glob pattern matching (case-insensitive for security)\n basename = os.path.basename(expanded_normalized)\n basename_lower = basename.lower()\n pattern_lower = pattern.lower()\n expanded_pattern_lower = expanded_pattern.lower()\n\n # Match against basename for patterns like *.pem, .env*\n if fnmatch.fnmatch(basename_lower, expanded_pattern_lower):\n return True\n if fnmatch.fnmatch(basename_lower, pattern_lower):\n return True\n # Also try full path match for patterns like /path/*.pem\n if fnmatch.fnmatch(expanded_normalized.lower(), expanded_pattern_lower):\n return True\n return False\n else:\n # Prefix matching (original behavior for directories)\n if expanded_normalized.startswith(expanded_pattern) or expanded_normalized == expanded_pattern.rstrip('/'):\n return True\n return False\n\n\ndef get_config_path() -> Path:\n \"\"\"Get path to patterns.yaml, checking multiple locations.\"\"\"\n # 1. Check project hooks directory (installed location)\n project_dir = os.environ.get(\"CLAUDE_PROJECT_DIR\")\n if project_dir:\n project_config = Path(project_dir) / \".claude\" / \"hooks\" / \"damage-control\" / \"patterns.yaml\"\n if project_config.exists():\n return project_config\n\n # 2. Check script's own directory (installed location)\n script_dir = Path(__file__).parent\n local_config = script_dir / \"patterns.yaml\"\n if local_config.exists():\n return local_config\n\n # 3. Check skill root directory (development location)\n skill_root = script_dir.parent.parent / \"patterns.yaml\"\n if skill_root.exists():\n return skill_root\n\n return local_config # Default, even if it doesn't exist\n\n\ndef load_config() -> Dict[str, Any]:\n \"\"\"Load config from YAML.\"\"\"\n config_path = get_config_path()\n\n if not config_path.exists():\n return {\"zeroAccessPaths\": [], \"readOnlyPaths\": []}\n\n with open(config_path, \"r\") as f:\n config = yaml.safe_load(f) or {}\n\n return config\n\n\ndef check_path(file_path: str, config: Dict[str, Any]) -> Tuple[bool, str]:\n \"\"\"Check if file_path is blocked. Returns (blocked, reason).\"\"\"\n # Check zero-access paths first (no access at all)\n for zero_path in config.get(\"zeroAccessPaths\", []):\n if match_path(file_path, zero_path):\n return True, f\"zero-access path {zero_path} (no operations allowed)\"\n\n # Check read-only paths (writes not allowed)\n for readonly in config.get(\"readOnlyPaths\", []):\n if match_path(file_path, readonly):\n return True, f\"read-only path {readonly}\"\n\n return False, \"\"\n\n\ndef main() -> None:\n config = load_config()\n\n try:\n input_data = json.load(sys.stdin)\n except json.JSONDecodeError as e:\n print(f\"Error: Invalid JSON input: {e}\", file=sys.stderr)\n sys.exit(1)\n\n tool_name = input_data.get(\"tool_name\", \"\")\n tool_input = input_data.get(\"tool_input\", {})\n\n # Only check Write tool\n if tool_name != \"Write\":\n sys.exit(0)\n\n file_path = tool_input.get(\"file_path\", \"\")\n if not file_path:\n sys.exit(0)\n\n blocked, reason = check_path(file_path, config)\n if blocked:\n print(f\"SECURITY: Blocked write to {reason}: {file_path}\", file=sys.stderr)\n sys.exit(2)\n\n sys.exit(0)\n\n\nif __name__ == \"__main__\":\n main()\n","content_type":"text/x-python; charset=utf-8","language":"python","size":4384,"content_sha256":"75e34d6bede0900d1903224af01f007d68e671220c206fd2bf465e323af1dec3"},{"filename":"workflows/install.md","content":"---\ndescription: Interactive workflow to install the Damage Control security hooks system\n---\n\n\u003cpurpose>\nGuide the user through installing the Damage Control security hooks system at their chosen settings level (global, project, or project personal). Uses interactive prompts to determine runtime preference and handle conflicts.\n\u003c/purpose>\n\n\u003cvariables>\nSKILL_DIR: skills/damage-control\nSCRIPTS_DIR: skills/damage-control/scripts\nGLOBAL_SETTINGS: ~/.claude/settings.json\nPROJECT_SETTINGS: .claude/settings.json\nLOCAL_SETTINGS: .claude/settings.local.json\n\u003c/variables>\n\n\u003cinstructions>\n- Use the AskUserQuestion tool at each decision point to guide the user\n- Check for existing settings before installation\n- Handle merge/overwrite conflicts gracefully\n- Copy the Python hook implementation (recommended)\n- Ensure the patterns.yaml file is included with the hooks\n- Verify installation by checking file existence after copy\n\u003c/instructions>\n\n\u003cworkflow>\n\n## Step 1: Determine Installation Level\n\n1. Use AskUserQuestion:\n```\nQuestion: \"Where would you like to install Damage Control?\"\nOptions:\n- Global (affects all projects) - ~/.claude/settings.json\n- Project (shared with team) - .claude/settings.json\n- Project Personal (just for you) - .claude/settings.local.json\n```\n\n2. Store the chosen path as TARGET_SETTINGS\n\n## Step 2: Check for Existing Settings\n\n3. Use the Read tool to check if TARGET_SETTINGS exists\n\n4. **If settings file does NOT exist**: Proceed to Step 3 (Fresh Install)\n\n5. **If settings file EXISTS**: Use AskUserQuestion:\n```\nQuestion: \"Existing settings found at [TARGET_SETTINGS]. How would you like to proceed?\"\nOptions:\n- Merge (combine existing hooks with damage-control)\n- Overwrite (replace with damage-control settings)\n- Stop (cancel installation)\n```\n\n6. Handle the response:\n - **Merge**: Read existing file, merge hooks arrays, write combined result\n - **Overwrite**: Proceed to Step 3 (Fresh Install)\n - **Stop**: Report \"Installation cancelled\" and exit workflow\n\n## Step 3: Install Hook Files\n\n7. Determine target hooks directory based on TARGET_SETTINGS:\n - Global: `~/.claude/hooks/damage-control/`\n - Project/Local: `.claude/hooks/damage-control/`\n\n8. Create target hooks directory:\n```bash\nmkdir -p [TARGET_HOOKS_DIR]\n```\n\n9. Copy Python hook scripts from skills directory:\n```bash\ncp [SCRIPTS_DIR]/*.py [TARGET_HOOKS_DIR]/\ncp [SCRIPTS_DIR]/patterns.yaml [TARGET_HOOKS_DIR]/\n```\n\n## Step 4: Install Settings Configuration\n\n10. Read the settings template from `[SCRIPTS_DIR]/settings-template.json`\n\n11. **For Fresh Install or Overwrite**:\n - Write the settings template to TARGET_SETTINGS\n - Update paths in settings to match TARGET_HOOKS_DIR\n\n12. **For Merge**:\n - Parse existing settings JSON\n - Parse template settings JSON\n - Use jq to deep merge:\n ```bash\n jq -s '\n def merge_hooks: (.[0].hooks.PreToolUse // []) + (.[1].hooks.PreToolUse // []) | unique_by(.matcher);\n def merge_permissions: {\n deny: ((.[0].permissions.deny // []) + (.[1].permissions.deny // []) | unique),\n ask: ((.[0].permissions.ask // []) + (.[1].permissions.ask // []) | unique)\n };\n .[0] * .[1] | .hooks.PreToolUse = (.[0] | merge_hooks) | .permissions = ([.[0], .[1]] | merge_permissions)\n ' [EXISTING_SETTINGS] [TEMPLATE] > merged.json && mv merged.json [TARGET_SETTINGS]\n ```\n - This merges both hooks.PreToolUse arrays AND permissions (deny/ask rules)\n\n## Step 5: Verify Installation\n\n13. Verify all files exist:\n```bash\nls -la [TARGET_HOOKS_DIR]/\n```\n\n14. Verify settings file was created/updated:\n```bash\ncat [TARGET_SETTINGS] | head -20\n```\n\n## Step 6: Check UV Runtime\n\n15. Check if UV is installed:\n```bash\nwhich uv || echo \"UV not installed\"\n```\n\n16. If UV is not installed, display install command:\n```\n# macOS/Linux\ncurl -LsSf https://astral.sh/uv/install.sh | sh\n\n# Windows (PowerShell)\npowershell -ExecutionPolicy ByPass -c \"irm https://astral.sh/uv/install.ps1 | iex\"\n```\n\n## Step 7: Restart Reminder\n\n17. **CRITICAL**: Tell the user:\n\n> **Restart your agent for these changes to take effect.**\n\nHooks are only loaded at agent startup.\n\n\u003c/workflow>\n\n\u003creport>\nPresent the installation summary:\n\n## Damage Control Installation Complete\n\n**Installation Level**: [Global/Project/Project Personal]\n**Settings File**: `[TARGET_SETTINGS]`\n**Hooks Directory**: `[TARGET_HOOKS_DIR]`\n\n### Files Installed\n- `bash-tool-damage-control.py` - Command pattern blocking\n- `edit-tool-damage-control.py` - Edit path protection\n- `write-tool-damage-control.py` - Write path protection\n- `test-damage-control.py` - Hook test runner\n- `patterns.yaml` - Security patterns and protected paths\n\n### Runtime\nEnsure UV is installed: `curl -LsSf https://astral.sh/uv/install.sh | sh`\n\n### IMPORTANT\n\n**Restart your agent for these changes to take effect.**\n\n### Next Steps\n1. Restart your Claude Code session\n2. Run `/hooks` to verify hooks are registered\n3. Test with: `rm -rf /tmp/test` (should be blocked)\n4. Customize `patterns.yaml` to add your own protected paths\n\u003c/report>\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":5078,"content_sha256":"527313f3252cc17baed051e985b207c1369d4e1e4e878056f334fbe6eef915b9"},{"filename":"workflows/list.md","content":"---\ndescription: List all Damage Control permissions across global, project, and personal levels\n---\n\n\u003cpurpose>\nDisplay a summary of all Damage Control security configurations across all settings levels (global, project, project personal).\n\u003c/purpose>\n\n\u003cvariables>\nGLOBAL_PATTERNS: ~/.claude/hooks/damage-control/patterns.yaml\nPROJECT_PATTERNS: .claude/hooks/damage-control/patterns.yaml\n\u003c/variables>\n\n\u003cinstructions>\n- Check each settings level for existence\n- Read patterns.yaml at each level if it exists\n- Present a consolidated view of all protections\n- Clearly indicate which levels are active vs not configured\n\u003c/instructions>\n\n\u003cworkflow>\n\n## Step 1: Check Installation Status\n\n1. Check which levels have Damage Control installed:\n\n```bash\n# Global\nls ~/.claude/hooks/damage-control/patterns.yaml 2>/dev/null && echo \"Global: INSTALLED\" || echo \"Global: NOT INSTALLED\"\n\n# Project\nls .claude/hooks/damage-control/patterns.yaml 2>/dev/null && echo \"Project: INSTALLED\" || echo \"Project: NOT INSTALLED\"\n```\n\n## Step 2: Read Configurations\n\n2. For each installed level, read the patterns.yaml and extract:\n - `bashToolPatterns` count and first few patterns\n - `zeroAccessPaths` list\n - `readOnlyPaths` list\n - `noDeletePaths` list\n\n## Step 3: Present Report\n\n3. Display the consolidated configuration summary\n\n\u003c/workflow>\n\n\u003creport>\n## Damage Control Configuration Summary\n\n### Global Level (`~/.claude/`)\n\n**Status**: [Installed / Not Configured]\n\n[If installed:]\n\n**Zero Access Paths** (no operations allowed):\n- [list paths or \"None configured\"]\n\n**Read Only Paths** (read allowed, no modifications):\n- [list paths or \"None configured\"]\n\n**No Delete Paths** (all operations except delete):\n- [list paths or \"None configured\"]\n\n**Blocked Command Patterns**: [count] patterns\n- [list first 5 patterns with reasons]\n- [if more than 5: \"... and [N] more\"]\n\n---\n\n### Project Level (`.claude/`)\n\n**Status**: [Installed / Not Configured]\n\n[Same format as Global]\n\n---\n\n### Protection Summary\n\n| Level | Zero Access | Read Only | No Delete | Command Patterns |\n|-------|-------------|-----------|-----------|------------------|\n| Global | [count] | [count] | [count] | [count] |\n| Project | [count] | [count] | [count] | [count] |\n\n---\n\n**Note**: Hooks at all levels run in parallel. If any level blocks an operation, it is blocked.\n\u003c/report>\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":2346,"content_sha256":"dde6435804e872aa99d5869d345990c59c90fc8bc2cb39c1552c38c26cafe973"},{"filename":"workflows/modify.md","content":"---\ndescription: Interactive workflow to modify existing Damage Control security settings\n---\n\n\u003cpurpose>\nGuide the user through modifying their Damage Control security configuration. Allows adding/removing protected paths, blocking new commands, and adjusting protection levels.\n\u003c/purpose>\n\n\u003cvariables>\nGLOBAL_PATTERNS: ~/.claude/hooks/damage-control/patterns.yaml\nPROJECT_PATTERNS: .claude/hooks/damage-control/patterns.yaml\n\u003c/variables>\n\n\u003cinstructions>\n- Use the AskUserQuestion tool at each decision point\n- Always verify settings exist before attempting modifications\n- If no settings found, redirect to install workflow\n- Validate YAML syntax after modifications\n- Show before/after comparison for user confirmation\n\u003c/instructions>\n\n\u003cworkflow>\n\n## Step 1: Determine Settings Level\n\n1. Use AskUserQuestion:\n```\nQuestion: \"Which settings level do you want to modify?\"\nOptions:\n- Global (all projects) - ~/.claude/\n- Project (this project) - .claude/\n```\n\n2. Store choice and set PATTERNS path accordingly\n\n## Step 2: Verify Installation Exists\n\n3. Use Read tool to check if PATTERNS file exists\n\n4. **If file doesn't exist**:\n - Report: \"Damage Control is not installed at this level.\"\n - Use AskUserQuestion:\n ```\n Question: \"Would you like to install Damage Control now?\"\n Options:\n - Yes, install it\n - No, cancel\n ```\n - If Yes: Read and execute [install.md](install.md)\n - If No: Exit workflow\n\n## Step 3: Determine Modification Type\n\n5. Use AskUserQuestion:\n```\nQuestion: \"What would you like to modify?\"\nOptions:\n- Add/Remove Protected Paths (restrict file/directory access)\n- Add/Remove Blocked Commands (block specific bash commands)\n- View Current Configuration\n```\n\n## Branch A: Modify Protected Paths\n\n6. **If \"Add/Remove Protected Paths\"**: Use AskUserQuestion:\n```\nQuestion: \"What action would you like to take?\"\nOptions:\n- Add a new protected path\n- Remove an existing protected path\n- List all protected paths\n```\n\n7. **Add new protected path**:\n a. Use AskUserQuestion:\n ```\n Question: \"What protection level should this path have?\"\n Options:\n - Zero Access (no operations allowed - for secrets/credentials)\n - Read Only (can read, cannot modify - for configs)\n - No Delete (can read/write/edit, cannot delete - for important files)\n ```\n\n b. Use AskUserQuestion (text input expected via \"Other\"):\n ```\n Question: \"Enter the path to protect:\"\n Options:\n - ~/.ssh/ (SSH keys)\n - ~/.aws/ (AWS credentials)\n - .env (environment file)\n - Other (enter custom path)\n ```\n\n c. Read current patterns.yaml\n d. Add path to appropriate section:\n - Zero Access → `zeroAccessPaths`\n - Read Only → `readOnlyPaths`\n - No Delete → `noDeletePaths`\n e. Write updated patterns.yaml\n f. Show confirmation\n\n8. **Remove protected path**:\n a. Read patterns.yaml and list all protected paths\n b. Use AskUserQuestion to select path to remove\n c. Remove path from appropriate section\n d. Write updated patterns.yaml\n\n## Branch B: Modify Blocked Commands\n\n9. **If \"Add/Remove Blocked Commands\"**: Use AskUserQuestion:\n```\nQuestion: \"What action would you like to take?\"\nOptions:\n- Add a new blocked command pattern\n- Remove an existing pattern\n- List all blocked patterns\n```\n\n10. **Add new blocked pattern**:\n a. Use AskUserQuestion:\n ```\n Question: \"Enter the command to block (I'll create the regex):\"\n Options:\n - npm publish (prevent accidental publishes)\n - docker push (prevent accidental pushes)\n - Other (enter custom command)\n ```\n\n b. Escape special regex characters\n c. Create pattern: `\\b[escaped_command]\\b`\n d. Ask for reason/description\n e. Read patterns.yaml\n f. Add to `bashToolPatterns`:\n ```yaml\n - pattern: '[generated_pattern]'\n reason: '[user_reason]'\n ```\n g. Write updated patterns.yaml\n\n## Branch C: View Configuration\n\n11. **If \"View Current Configuration\"**:\n a. Read patterns.yaml\n b. Display formatted configuration summary\n\n## Step 4: Restart Reminder\n\n12. **CRITICAL**: After any modifications, tell the user:\n\n> **Restart your agent for these changes to take effect.**\n\n\u003c/workflow>\n\n\u003creport>\n## Damage Control Configuration Updated\n\n**Settings Level**: [Global/Project]\n**Modification Type**: [Path Protection/Command Blocking]\n\n### Changes Made\n**Action**: Added/Removed\n**Item**: `[path or pattern]`\n**Category**: [Zero Access/Read Only/No Delete/Blocked Command]\n\n### IMPORTANT\n\n**Restart your agent for these changes to take effect.**\n\nRun `/hooks` after restart to verify the changes are active.\n\u003c/report>\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":4590,"content_sha256":"b13aca2f9db968058fe2d1512f2c7284c3ffcd30be2a5dc4b919b8d8a4ad19d5"},{"filename":"workflows/test.md","content":"---\ndescription: Test all Damage Control hooks by running the test script against patterns.yaml\n---\n\n\u003cpurpose>\nValidate that all Damage Control hooks are working correctly by reading patterns.yaml and running test cases against each configured pattern and protected path.\n\u003c/purpose>\n\n\u003cvariables>\nPROJECT_HOOKS: .claude/hooks/damage-control\nGLOBAL_HOOKS: ~/.claude/hooks/damage-control\n\u003c/variables>\n\n\u003cinstructions>\n- Determine which hooks directory to test (project or global)\n- Read patterns.yaml to get all configured patterns and paths\n- For each pattern/path, call the test script with appropriate arguments\n- The test script echoes JSON into the hooks - it does NOT run actual commands\n- Track pass/fail counts and report summary\n\n**IMPORTANT**: You are testing hooks by piping mock data. NO actual dangerous commands are executed.\n\u003c/instructions>\n\n\u003cworkflow>\n\n## Step 1: Locate Hooks\n\n1. Check if project hooks exist:\n```bash\nls .claude/hooks/damage-control/patterns.yaml 2>/dev/null\n```\n\n2. If not found, check global hooks:\n```bash\nls ~/.claude/hooks/damage-control/patterns.yaml 2>/dev/null\n```\n\n3. Set HOOKS_DIR to the found location\n\n## Step 2: Read Configuration\n\n4. Read `[HOOKS_DIR]/patterns.yaml`\n\n5. Extract:\n - `bashToolPatterns` - command patterns to block\n - `zeroAccessPaths` - paths with no access\n - `readOnlyPaths` - read-only paths\n - `noDeletePaths` - no-delete paths\n\n## Step 3: Test bashToolPatterns\n\n6. For each pattern, generate a matching test command and run:\n```bash\nuv run [HOOKS_DIR]/test-damage-control.py bash Bash \"[test_command]\" --expect-blocked\n```\n\n**Test cases:**\n| Pattern | Test Command |\n|---------|-------------|\n| `rm -rf` | `rm -rf /tmp/test` |\n| `git reset --hard` | `git reset --hard HEAD` |\n| `git push --force` | `git push --force origin main` |\n| `chmod 777` | `chmod 777 /tmp/test` |\n\n7. Test safe commands are allowed:\n```bash\nuv run [HOOKS_DIR]/test-damage-control.py bash Bash \"ls -la\" --expect-allowed\nuv run [HOOKS_DIR]/test-damage-control.py bash Bash \"git status\" --expect-allowed\n```\n\n## Step 4: Test zeroAccessPaths\n\n8. For each zero-access path, test ALL access is blocked:\n```bash\n# Bash access\nuv run [HOOKS_DIR]/test-damage-control.py bash Bash \"cat [path]/test\" --expect-blocked\n\n# Edit access\nuv run [HOOKS_DIR]/test-damage-control.py edit Edit \"[path]/test.txt\" --expect-blocked\n\n# Write access\nuv run [HOOKS_DIR]/test-damage-control.py write Write \"[path]/test.txt\" --expect-blocked\n```\n\n## Step 5: Test readOnlyPaths\n\n9. For each read-only path:\n```bash\n# Read - should be ALLOWED\nuv run [HOOKS_DIR]/test-damage-control.py bash Bash \"cat [path]\" --expect-allowed\n\n# Write - should be BLOCKED\nuv run [HOOKS_DIR]/test-damage-control.py bash Bash \"echo test > [path]/test\" --expect-blocked\n\n# Edit - should be BLOCKED\nuv run [HOOKS_DIR]/test-damage-control.py edit Edit \"[path]/test.txt\" --expect-blocked\n```\n\n## Step 6: Test noDeletePaths\n\n10. For each no-delete path:\n```bash\n# Delete - should be BLOCKED\nuv run [HOOKS_DIR]/test-damage-control.py bash Bash \"rm [path]/test.txt\" --expect-blocked\n\n# Write - should be ALLOWED\nuv run [HOOKS_DIR]/test-damage-control.py bash Bash \"echo test > [path]/test.txt\" --expect-allowed\n```\n\n## Step 7: Compile Results\n\n11. Count total passed and failed tests\n12. Present the summary report\n\n\u003c/workflow>\n\n\u003creport>\n## Damage Control Test Results\n\n### bashToolPatterns\n| Test | Command | Expected | Result |\n|------|---------|----------|--------|\n| 1 | `rm -rf /tmp` | BLOCKED | PASS/FAIL |\n| 2 | `git reset --hard` | BLOCKED | PASS/FAIL |\n| 3 | `ls -la` | ALLOWED | PASS/FAIL |\n\n### zeroAccessPaths\n| Path | Tool | Expected | Result |\n|------|------|----------|--------|\n| ~/.ssh/ | Bash | BLOCKED | PASS/FAIL |\n| ~/.ssh/ | Edit | BLOCKED | PASS/FAIL |\n| ~/.ssh/ | Write | BLOCKED | PASS/FAIL |\n\n### readOnlyPaths\n| Path | Operation | Expected | Result |\n|------|-----------|----------|--------|\n| /etc/ | Read | ALLOWED | PASS/FAIL |\n| /etc/ | Write | BLOCKED | PASS/FAIL |\n\n### noDeletePaths\n| Path | Operation | Expected | Result |\n|------|-----------|----------|--------|\n| .git/ | Delete | BLOCKED | PASS/FAIL |\n| .git/ | Write | ALLOWED | PASS/FAIL |\n\n---\n\n### Summary\n\n**Total Tests**: [count]\n**Passed**: [count]\n**Failed**: [count]\n\n[If all passed]\nAll Damage Control hooks are working correctly.\n\n[If any failed]\nSome tests failed. Review the failed tests and check hook implementations.\n\u003c/report>\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":4421,"content_sha256":"04a8c6465cf722e9213b47c69a8134758cb958bddc73aa168c910e4f33fda9aa"}],"content_json":{"type":"doc","content":[{"type":"paragraph","content":[{"text":"\u003cobjective> Defense-in-depth protection system for Claude Code. Uses PreToolUse hooks to intercept and validate tool calls before execution, blocking dangerous commands and protecting sensitive files. \u003c/objective>","type":"text"}]},{"type":"paragraph","content":[{"text":"\u003cprotection_levels>","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Level","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Read","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Write","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Edit","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Delete","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Use Case","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"zeroAccessPaths","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"No","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"No","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"No","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"No","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Secrets, credentials, .env files","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"readOnlyPaths","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Yes","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"No","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"No","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"No","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"System configs, lock files, build artifacts","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"noDeletePaths","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Yes","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Yes","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Yes","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"No","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Important project files, .git/, LICENSE","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"\u003c/protection_levels>","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph"}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph"}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph"}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph"}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph"}]}]}]},{"type":"paragraph","content":[{"text":"\u003chow_it_works> PreToolUse hooks intercept tool calls at three points:","type":"text"}]},{"type":"ordered_list","attrs":{"order":1,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Bash Hook","type":"text","marks":[{"type":"strong"}]},{"text":" - Evaluates commands against regex patterns and path restrictions","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Edit Hook","type":"text","marks":[{"type":"strong"}]},{"text":" - Validates file paths before modifications","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Write Hook","type":"text","marks":[{"type":"strong"}]},{"text":" - Checks paths before file creation","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"Exit codes:","type":"text","marks":[{"type":"strong"}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"0","type":"text","marks":[{"type":"code_inline"}]},{"text":" = Allow operation","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"0","type":"text","marks":[{"type":"code_inline"}]},{"text":" + JSON = Ask for confirmation (triggers dialog)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"2","type":"text","marks":[{"type":"code_inline"}]},{"text":" = Block operation (stderr fed back to Claude)","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"Ask patterns:","type":"text","marks":[{"type":"strong"}]},{"text":" Some operations trigger confirmation dialogs instead of blocking:","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"git checkout -- .","type":"text","marks":[{"type":"code_inline"}]},{"text":" (discards changes)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"git stash drop","type":"text","marks":[{"type":"code_inline"}]},{"text":" (deletes stash)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"DELETE FROM table WHERE id=X","type":"text","marks":[{"type":"code_inline"}]},{"text":" (SQL with specific ID) \u003c/how_it_works>","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"\u003cquick_start> ","type":"text"},{"text":"Interactive installation:","type":"text","marks":[{"type":"strong"}]}]},{"type":"code_block","attrs":{"wrap":false,"language":""},"content":[{"text":"/damage-control install","type":"text"}]},{"type":"paragraph","content":[{"text":"Or ask Claude:","type":"text","marks":[{"type":"strong"}]}]},{"type":"blockquote","content":[{"type":"paragraph","content":[{"text":"\"Install damage control security hooks\" \"Set up protection for my project\" \u003c/quick_start>","type":"text"}]}]},{"type":"paragraph","content":[{"text":"\u003cintake> What would you like to do?","type":"text"}]},{"type":"ordered_list","attrs":{"order":1,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Install","type":"text","marks":[{"type":"strong"}]},{"text":" - Set up damage control hooks (global, project, or personal)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Modify","type":"text","marks":[{"type":"strong"}]},{"text":" - Add/remove protected paths or blocked commands","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Test","type":"text","marks":[{"type":"strong"}]},{"text":" - Validate hooks are working correctly","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"List","type":"text","marks":[{"type":"strong"}]},{"text":" - View all active protections across all levels","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"Wait for response before proceeding.","type":"text","marks":[{"type":"strong"}]},{"text":" \u003c/intake>","type":"text"}]},{"type":"paragraph","content":[{"text":"\u003crouting>","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Response","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Workflow","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"1, \"install\", \"setup\", \"deploy\"","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"workflows/install.md","type":"text","marks":[{"type":"link","attrs":{"href":"workflows/install.md","title":null}}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"2, \"modify\", \"add\", \"remove\", \"change\"","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"workflows/modify.md","type":"text","marks":[{"type":"link","attrs":{"href":"workflows/modify.md","title":null}}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"3, \"test\", \"verify\", \"check\"","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"workflows/test.md","type":"text","marks":[{"type":"link","attrs":{"href":"workflows/test.md","title":null}}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"4, \"list\", \"view\", \"show\"","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"workflows/list.md","type":"text","marks":[{"type":"link","attrs":{"href":"workflows/list.md","title":null}}]}]}]}]}]},{"type":"paragraph","content":[{"text":"Direct command routing (skip menu):","type":"text","marks":[{"type":"strong"}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"\"add ~/.credentials to zero access\" → Execute directly, then restart reminder","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"\"block npm publish command\" → Execute directly, then restart reminder","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"\"protect /secrets folder\" → Execute directly, then restart reminder","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"After reading the workflow, follow it exactly.","type":"text","marks":[{"type":"strong"}]},{"text":" \u003c/routing>","type":"text"}]},{"type":"paragraph","content":[{"text":"\u003cblocked_commands_summary> ","type":"text"},{"text":"Destructive file operations:","type":"text","marks":[{"type":"strong"}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"rm -rf","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"rm --recursive","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"sudo rm","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"chmod 777","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"chown -R root","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"paragraph","content":[{"text":"Git destructive:","type":"text","marks":[{"type":"strong"}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"git reset --hard","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"git push --force","type":"text","marks":[{"type":"code_inline"}]},{"text":" (not --force-with-lease)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"git clean -fd","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"git stash clear","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"git filter-branch","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"paragraph","content":[{"text":"Cloud destructive:","type":"text","marks":[{"type":"strong"}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"AWS: ","type":"text"},{"text":"terminate-instances","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"delete-db-instance","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"delete-stack","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"GCP: ","type":"text"},{"text":"projects delete","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"instances delete","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"clusters delete","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Docker: ","type":"text"},{"text":"system prune -a","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"volume rm","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Kubernetes: ","type":"text"},{"text":"delete namespace","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"delete all --all","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"paragraph","content":[{"text":"Database destructive:","type":"text","marks":[{"type":"strong"}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"DELETE FROM table;","type":"text","marks":[{"type":"code_inline"}]},{"text":" (no WHERE clause)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"DROP TABLE","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"DROP DATABASE","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"TRUNCATE TABLE","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"redis-cli FLUSHALL","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"dropdb","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"paragraph","content":[{"text":"See ","type":"text"},{"text":"scripts/patterns.yaml","type":"text","marks":[{"type":"link","attrs":{"href":"scripts/patterns.yaml","title":null}}]},{"text":" for complete list. \u003c/blocked_commands_summary>","type":"text"}]},{"type":"paragraph","content":[{"text":"\u003csettings_locations>","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Level","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Settings Path","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Hooks Path","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Scope","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Global","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"~/.claude/settings.json","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"~/.claude/hooks/damage-control/","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"All projects","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Project","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":".claude/settings.json","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":".claude/hooks/damage-control/","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Team-shared","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Personal","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":".claude/settings.local.json","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":".claude/hooks/damage-control/","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Just you","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"\u003c/settings_locations>","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph"}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph"}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph"}]}]}]},{"type":"paragraph","content":[{"text":"\u003cruntime_requirements> ","type":"text"},{"text":"Python with UV (Recommended):","type":"text","marks":[{"type":"strong"}]}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"# macOS/Linux\ncurl -LsSf https://astral.sh/uv/install.sh | sh\n\n# Windows\npowershell -ExecutionPolicy ByPass -c \"irm https://astral.sh/uv/install.ps1 | iex\"","type":"text"}]},{"type":"paragraph","content":[{"text":"TypeScript with Bun (Alternative):","type":"text","marks":[{"type":"strong"}]}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"# macOS/Linux\ncurl -fsSL https://bun.sh/install | bash && bun add yaml\n\n# Windows\npowershell -c \"irm bun.sh/install.ps1 | iex\" && bun add yaml","type":"text"}]},{"type":"paragraph","content":[{"text":"\u003c/runtime_requirements>","type":"text"}]},{"type":"paragraph","content":[{"text":"\u003ccritical_reminder> ","type":"text"},{"text":"IMPORTANT:","type":"text","marks":[{"type":"strong"}]},{"text":" After any installation or modification:","type":"text"}]},{"type":"blockquote","content":[{"type":"paragraph","content":[{"text":"Restart your agent for changes to take effect.","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"paragraph","content":[{"text":"Hooks are only loaded at agent startup. Run ","type":"text"},{"text":"/hooks","type":"text","marks":[{"type":"code_inline"}]},{"text":" after restart to verify. \u003c/critical_reminder>","type":"text"}]},{"type":"paragraph","content":[{"text":"\u003cworkflows_index>","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Workflow","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Purpose","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"workflows/install.md","type":"text","marks":[{"type":"link","attrs":{"href":"workflows/install.md","title":null}}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Interactive installation at any settings level","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"workflows/modify.md","type":"text","marks":[{"type":"link","attrs":{"href":"workflows/modify.md","title":null}}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Add/remove protected paths and blocked commands","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"workflows/test.md","type":"text","marks":[{"type":"link","attrs":{"href":"workflows/test.md","title":null}}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Validate all hooks are working correctly","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"workflows/list.md","type":"text","marks":[{"type":"link","attrs":{"href":"workflows/list.md","title":null}}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"View all active protections","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"\u003c/workflows_index>","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph"}]}]}]},{"type":"paragraph","content":[{"text":"\u003cscripts_index>","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Script","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Purpose","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"scripts/bash-tool-damage-control.py","type":"text","marks":[{"type":"link","attrs":{"href":"scripts/bash-tool-damage-control.py","title":null}}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"PreToolUse hook for Bash commands","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"scripts/edit-tool-damage-control.py","type":"text","marks":[{"type":"link","attrs":{"href":"scripts/edit-tool-damage-control.py","title":null}}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"PreToolUse hook for Edit tool","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"scripts/write-tool-damage-control.py","type":"text","marks":[{"type":"link","attrs":{"href":"scripts/write-tool-damage-control.py","title":null}}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"PreToolUse hook for Write tool","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"scripts/test-damage-control.py","type":"text","marks":[{"type":"link","attrs":{"href":"scripts/test-damage-control.py","title":null}}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Test runner for hook validation","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"scripts/patterns.yaml","type":"text","marks":[{"type":"link","attrs":{"href":"scripts/patterns.yaml","title":null}}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Security patterns and protected paths","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"scripts/settings-template.json","type":"text","marks":[{"type":"link","attrs":{"href":"scripts/settings-template.json","title":null}}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Hook configuration template","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"\u003c/scripts_index>","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph"}]}]}]},{"type":"paragraph","content":[{"text":"\u003csuccess_criteria> A working damage-control installation has:","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Hooks installed at chosen level (global/project/personal)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"patterns.yaml","type":"text","marks":[{"type":"code_inline"}]},{"text":" copied alongside hook scripts","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"settings.json","type":"text","marks":[{"type":"code_inline"}]},{"text":" updated with PreToolUse hook configuration","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"UV (or Bun) runtime installed","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Agent restarted to load hooks","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Verified with ","type":"text"},{"text":"/hooks","type":"text","marks":[{"type":"code_inline"}]},{"text":" command showing damage-control hooks","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Tested with ","type":"text"},{"text":"rm -rf /tmp/test","type":"text","marks":[{"type":"code_inline"}]},{"text":" (should be blocked) \u003c/success_criteria>","type":"text"}]}]}]},{"type":"hr","attrs":{"markup":"---"}}]},"metadata":{"date":"2026-06-05","name":"damage-control","author":"@skillopedia","source":{"stars":17,"repo_name":"claude-code-toolkit","origin_url":"https://github.com/cfircoo/claude-code-toolkit/blob/HEAD/skills/damage-control/SKILL.md","repo_owner":"cfircoo","body_sha256":"d777598bfcd6c5521a334989f3b0394d9ee390713f3220d22c934031dcaf980c","cluster_key":"793ab3e8c730838da195771888c7b3f3f5f0018684b69ad353e9f210caf0156e","clean_bundle":{"format":"clean-skill-bundle-v1","source":"cfircoo/claude-code-toolkit/skills/damage-control/SKILL.md","attachments":[{"id":"0f7ba618-3c90-55f3-b8cd-b7d2cd899ad7","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/0f7ba618-3c90-55f3-b8cd-b7d2cd899ad7/attachment.py","path":"scripts/bash-tool-damage-control.py","size":11978,"sha256":"6c2e49f46a3f35f47c3ae9eb973eb62ff3c42e8de8195a7925e59b864f2f7db4","contentType":"text/x-python; charset=utf-8"},{"id":"b4c2bd20-c176-5721-a4ff-0c049da3a86c","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/b4c2bd20-c176-5721-a4ff-0c049da3a86c/attachment.py","path":"scripts/edit-tool-damage-control.py","size":4448,"sha256":"93ed102fa23fba3c28324ca457faa8f542383fdb242a181d1d234de93057e937","contentType":"text/x-python; charset=utf-8"},{"id":"8448ebb6-10d5-5c97-9140-17c030cd5faa","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/8448ebb6-10d5-5c97-9140-17c030cd5faa/attachment.yaml","path":"scripts/patterns.yaml","size":22540,"sha256":"4e1b29dd4f273470b9f8404876a42cc9d1fcff05f793e6197ecb19b66448fe7d","contentType":"application/yaml; charset=utf-8"},{"id":"a7114b6b-df5f-5ae9-ab4b-1badfe93789a","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/a7114b6b-df5f-5ae9-ab4b-1badfe93789a/attachment.py","path":"scripts/read-tool-damage-control.py","size":4320,"sha256":"26a2cbc4a8505d8d5e0d9aa6f50b5ab57dd2014842bcdb102496f0c37b89c147","contentType":"text/x-python; charset=utf-8"},{"id":"bf43ff3a-d134-5a99-9115-f06fc88e7653","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/bf43ff3a-d134-5a99-9115-f06fc88e7653/attachment.json","path":"scripts/settings-template.json","size":1299,"sha256":"19574fe6dbc0a1e9a2fe617e09ad8a6c06e5eb3307aa683d282200be963dd1ed","contentType":"application/json; charset=utf-8"},{"id":"3693c377-a75c-5d0f-971b-e2f749124f6b","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/3693c377-a75c-5d0f-971b-e2f749124f6b/attachment.py","path":"scripts/test-damage-control.py","size":13939,"sha256":"34b1b1020baa1f54900e621882f2271ef35c94e24170bfb46f56517263fc1538","contentType":"text/x-python; charset=utf-8"},{"id":"fa371729-92ec-53a5-86b4-147c7aa9c72a","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/fa371729-92ec-53a5-86b4-147c7aa9c72a/attachment.py","path":"scripts/write-tool-damage-control.py","size":4384,"sha256":"75e34d6bede0900d1903224af01f007d68e671220c206fd2bf465e323af1dec3","contentType":"text/x-python; charset=utf-8"},{"id":"f3c96cc4-b46b-5032-8114-2b00cd9bc14e","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/f3c96cc4-b46b-5032-8114-2b00cd9bc14e/attachment.md","path":"workflows/install.md","size":5078,"sha256":"527313f3252cc17baed051e985b207c1369d4e1e4e878056f334fbe6eef915b9","contentType":"text/markdown; charset=utf-8"},{"id":"21284125-6770-5a28-8b4c-5cf8d5a63144","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/21284125-6770-5a28-8b4c-5cf8d5a63144/attachment.md","path":"workflows/list.md","size":2346,"sha256":"dde6435804e872aa99d5869d345990c59c90fc8bc2cb39c1552c38c26cafe973","contentType":"text/markdown; charset=utf-8"},{"id":"3fc2fa58-cb7a-5ffe-bdf1-bbe7d9b39fe7","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/3fc2fa58-cb7a-5ffe-bdf1-bbe7d9b39fe7/attachment.md","path":"workflows/modify.md","size":4590,"sha256":"b13aca2f9db968058fe2d1512f2c7284c3ffcd30be2a5dc4b919b8d8a4ad19d5","contentType":"text/markdown; charset=utf-8"},{"id":"fd151099-1ae8-5428-8254-7905cac780d0","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/fd151099-1ae8-5428-8254-7905cac780d0/attachment.md","path":"workflows/test.md","size":4421,"sha256":"04a8c6465cf722e9213b47c69a8134758cb958bddc73aa168c910e4f33fda9aa","contentType":"text/markdown; charset=utf-8"}],"bundle_sha256":"a39aefc1624d2786e109022b59ab49569a3dd3294e746a2d039a8be4d4b7c75c","attachment_count":11,"text_attachments":11,"attachment_storage":"skillopedia-attachments-v1","binary_attachments":0,"excluded_attachments":[]},"cluster_size":1,"skill_md_path":"skills/damage-control/SKILL.md","import_metadata":{"date":"2026-06-05","author":"@skillopedia","version":"v1","category":"security","category_label":"Security"},"exact_dupes_collapsed_into_this":0},"version":"v1","category":"security","import_tag":"clean-skills-v1","description":"Install, configure, and manage Claude Code security hooks that block dangerous commands and protect sensitive files. Use when setting up security protection, blocking destructive commands (rm -rf, git reset --hard), protecting sensitive paths (.env, credentials), or managing PreToolUse hooks."}},"renderedAt":1782993823498}

<objective Defense-in-depth protection system for Claude Code. Uses PreToolUse hooks to intercept and validate tool calls before execution, blocking dangerous commands and protecting sensitive files. </objective <protection levels | Level | Read | Write | Edit | Delete | Use Case | |-------|------|-------|------|--------|----------| | zeroAccessPaths | No | No | No | No | Secrets, credentials, .env files | | readOnlyPaths | Yes | No | No | No | System configs, lock files, build artifacts | | noDeletePaths | Yes | Yes | Yes | No | Important project files, .git/, LICENSE | </protection levels <…