How to Set Up Guardrails for Claude Code and AI Coding Tools
I watched in horror as my AI coding assistant casually executed git push --force to the main branch. No confirmation, no warning, just a destructive action that wiped out my teammate’s work. That was the moment I realized: AI coding tools need guardrails, not just clever prompts.
The Problem: AI Agents Have Too Much Power
Modern AI coding assistants like Claude Code, Cursor, and GitHub Copilot can execute terminal commands, modify files, push to git repositories, and even deploy to production. This power is incredibly useful but also dangerous. Without proper constraints, a misunderstanding or hallucination can lead to:
- Force-pushing to protected branches
- Deleting critical files or databases
- Exposing secrets in commits
- Deploying unreviewed code to production
- Running destructive commands like
kubectl deletewithout approval
The solution isn’t to avoid AI tools—it’s to implement multi-layered defenses that catch mistakes before they happen.
Layer 1: Hooks as Hard Blockers
Hooks are your first line of defense. They run before or after tool execution and can block dangerous actions. In Claude Code, you configure hooks in ~/.claude/settings.json:
{ "hooks": { "PreToolUse": [ { "matcher": "Bash", "hooks": [ { "type": "command", "command": "echo 'Blocking destructive git operations'" } ] } ] }}The key principle: use hooks as hard blockers for destructive or unwanted actions. Don’t just log warnings—actually prevent the action from executing.
Here’s a more sophisticated example that blocks force pushes:
#!/bin/bash
# Check if command contains force pushif echo "$CLAude_CODE_COMMAND" | grep -qE "git\s+push.*--force|git\s+push.*-f"; then if echo "$CLAUDE_CODE_COMMAND" | grep -qE "main|master"; then echo "BLOCKED: Force push to main/master is not allowed" exit 1 fifiexit 0Layer 2: Allowlists to Constrain Access
Constraining which paths and tools the agent can access is more effective than catching mistakes after the fact. Allowlists limit the blast radius before any action is taken.
For file system access, define allowed paths:
allowedPaths: - /Users/username/projects/my-app - /Users/username/projects/my-app/src - /Users/username/projects/my-app/tests
# Explicitly deny sensitive pathsdeniedPaths: - /Users/username/.ssh - /Users/username/.aws - /Users/username/.envFor tool access, specify which MCP (Model Context Protocol) servers the agent can use:
{ "mcpServers": { "filesystem": { "command": "npx", "args": ["-y", "@modelcontextprotocol/server-filesystem", "/allowed/path"], "disabled": false }, "dangerous-admin-tools": { "disabled": true } }}As one developer noted: “More useful upfront: constrain which paths and tools the agent can access—allowlists limit blast radius better than catching mistakes after the fact.”
Layer 3: Least-Privilege Cloud Permissions
If you’re giving AI tools access to cloud resources, apply the principle of least privilege rigorously. A common mistake is providing admin-level credentials just for convenience.
For AWS, this means:
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "s3:GetObject", "s3:ListBucket" ], "Resource": [ "arn:aws:s3:::my-bucket", "arn:aws:s3:::my-bucket/*" ] } ]}The guidance is clear: “If you’re going to give it AWS SSO, give it read only, or heavily scoped IAMs.” Never grant write, delete, or admin permissions unless absolutely necessary—and then only for specific resources.
For Kubernetes access, be equally careful:
users:- name: ai-assistant user: token: <limited-scope-token># This token should only have read access to specific namespacesLayer 4: Manual Approval for Sensitive Operations
Some operations should always require human approval, regardless of how smart your AI assistant is. Terminal commands that affect production infrastructure fall into this category.
Set up approval requirements for commands like:
kubectl delete- Could delete production resourceskubectl apply- Could modify running infrastructure- Database migrations - Could cause data loss
git push --force- Could destroy commit history
In Claude Code, you can configure this:
{ "permissions": { "requireApproval": [ "Bash:kubectl*", "Bash:*delete*", "Bash:*drop*", "Bash:*truncate*", "Bash:git push*--force*" ] }}The rule is simple: “Any terminal execution of kubectl commands needs to be manually approved.”
Layer 5: Skills, Rules, and Iterative Refinement
Guardrails aren’t set-and-forget. They require ongoing refinement as you discover edge cases and learn from near-misses.
The recommended approach:
- Set up your skills, rules, and access to protect yourself
- Start with strict permissions
- Use
--dangerously-skip-permissionsonly when you trust your setup - Prompt well with clear constraints
- Refine your rules over time as issues arise
- Build more skills for repetitive tasks
Your CLAUDE.md file should document project-specific constraints:
# Project Constraints
## Never Do These Things- Never run migrations without approval- Never commit to main branch directly- Never push to remote without reviewing diff- Never delete files matching pattern *.env*
## Required Approvals- Any kubectl command- Any npm publish command- Any git push with --force flagA Complete Guardrails Configuration Example
Here’s how a comprehensive setup might look:
+---------------------------+| User Prompt |+---------------------------+ | v+---------------------------+| PreToolUse Hooks | <-- Block destructive patterns| - Check command intent || - Validate paths || - Require approval |+---------------------------+ | v+---------------------------+| Allowlist Filter | <-- Constrain accessible tools/paths| - Allowed MCP servers || - Allowed file paths || - Denied sensitive dirs |+---------------------------+ | v+---------------------------+| Least-Privilege Creds | <-- Minimal cloud permissions| - Read-only AWS IAM || - Scoped k8s tokens || - No admin access |+---------------------------+ | v+---------------------------+| Manual Approval Gate | <-- Human in the loop| - kubectl commands || - Database operations || - Force pushes |+---------------------------+ | v+---------------------------+| Safe Execution |+---------------------------+Testing Your Guardrails
Before trusting your setup, test it:
# This should be blockedecho "Testing force push block..."claude-code "force push to main" # Should fail or require approval
# This should be blockedecho "Testing kubectl access..."claude-code "delete all pods in production" # Should require approval
# This should workecho "Testing safe operation..."claude-code "read the README file" # Should succeedDocument your guardrails and review them periodically. As your AI tools get smarter, your defenses should too.
Common Guardrail Mistakes to Avoid
- Over-reliance on prompts alone - Prompts can be misunderstood; code-level constraints cannot
- Granting admin credentials for convenience - Always use minimal permissions
- Skipping hooks during development - Test with the same restrictions you’ll use in production
- Not logging blocked actions - You need visibility into what the AI tried to do
- Forgetting to update rules - New tools and commands require new constraints
Summary
Setting up guardrails for AI coding tools requires a multi-layered approach:
- Hooks as hard blockers for destructive actions
- Allowlists to constrain accessible paths and tools
- Least-privilege permissions for cloud resources
- Manual approval for sensitive operations
- Iterative refinement based on real-world usage
The goal isn’t to limit AI capabilities but to ensure that mistakes are caught before they cause damage. Your AI assistant can still be powerful—just safely powerful.
Final Words + More Resources
My intention with this article was to help others share my knowledge and experience. If you want to contact me, you can contact by email: Email me
Here are also the most important links from this article along with some further resources that will help you in this scope:
Oh, and if you found these resources useful, don’t forget to support me by starring the repo on GitHub!
Comments