Use this page to configure Claude Code (or a similar coding agent) for SRE repos: IaC, CI templates, runbooks and automation scripts. The agent operating rules are the policy; this page is how to enforce it in the tool.
Use it only on machines and with data your organization has approved for AI tools.
Two ways to use it
| Mode | Command | Good for |
|---|---|---|
| Interactive | claude in the repo |
Writing a Terraform module, porting a pipeline, reviewing a diff, drafting a runbook |
| Headless | claude -p "<prompt>" |
Scheduled, repeatable text jobs: classify tickets, summarise a plan, draft a report |
Write a CLAUDE.md in every repo
Claude reads CLAUDE.md at the repo root on start. Keep it short and specific.
# CLAUDE.md
## What this repo is
Terraform for <component> across dev, staging and prod. One state per env under envs/<env>.
## Ground rules
- Read-only by default. Never run terraform apply, aws write calls, git push to main, or force-push.
- Changes are proposed as a branch and a draft MR. A human merges.
- Use the `<account-alias>-ro` AWS profiles only. Always pass --profile and --region.
- Never print or paste secrets, tokens, account IDs, hostnames or customer data.
- When unsure, stop and ask; write the question in the MR description.
## How to check your work
- terraform fmt -recursive && terraform validate
- tflint --recursive
- ./scripts/plan.sh <env> # read-only plan
## Workflows
### port-pipeline
1. Read the old CI file. 2. Generate the new CI file from templates/. 3. List every TODO. 4. Open a draft MR.
Add personal, machine-specific notes in ~/.claude/CLAUDE.md, not in the repo.
Lock down permissions
Project settings live in .claude/settings.json (shared) and .claude/settings.local.json (yours, git-ignored).
{
"permissions": {
"defaultMode": "plan",
"allow": [
"Bash(terraform fmt:*)",
"Bash(terraform validate:*)",
"Bash(terraform plan:*)",
"Bash(tflint:*)",
"Bash(git status:*)",
"Bash(git diff:*)",
"Bash(git log:*)",
"Bash(glab mr view:*)",
"Bash(glab ci lint:*)"
],
"deny": [
"Bash(terraform apply:*)",
"Bash(terraform destroy:*)",
"Bash(git push --force:*)",
"Bash(git push -f:*)",
"Bash(aws secretsmanager get-secret-value:*)",
"Read(./**/*.tfstate)",
"Read(./**/.env)",
"Read(~/.aws/credentials)"
]
}
}
-
planmode means Claude proposes and you approve each edit or command. - The strongest guard is outside the tool: give the session read-only cloud credentials, so even an allowed command cannot write.
- Never run with the skip-permissions flag on a machine that holds production credentials.
Add a guard hook
A PreToolUse hook runs before every tool call and can block it (exit code 2).
{
"hooks": {
"PreToolUse": [
{ "matcher": "Bash", "hooks": [ { "type": "command", "command": "~/.claude/hooks/guard.sh" } ] }
]
}
}
#!/usr/bin/env bash
# ~/.claude/hooks/guard.sh: block mutating cloud and git commands
cmd="$(jq -r '.tool_input.command // ""')"
if grep -Eq '(^|[ ;&|])(terraform (apply|destroy)|kubectl (apply|delete)|git push (-f|--force))' <<<"$cmd" \
|| grep -Eq 'aws .* (delete|put|update|create|terminate|modify)-' <<<"$cmd"; then
echo "blocked by guard.sh: mutating command needs a human" >&2
exit 2
fi
exit 0
Run headless jobs safely
redact() {
sed -E \
-e 's/AKIA[0-9A-Z]{16}/<aws-key-id>/g' \
-e 's/\b[0-9]{12}\b/<account-id>/g' \
-e 's/\b[0-9]{13,19}\b/<number>/g' \
-e 's/[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}/<email>/g' \
-e 's/\b([0-9]{1,3}\.){3}[0-9]{1,3}\b/<ip>/g' \
-e 's/(token|secret|password|passwd|api[_-]?key)([" :=]+)[^" ,]+/\1\2<redacted>/Ig'
}
redact < tickets.jsonl | claude -p "$(cat prompts/classify.md)" \
--output-format json \
--max-turns 1 \
--disallowedTools Bash Edit Write WebFetch WebSearch \
| jq -r '.result' > state/classified.json
- Filter every byte before it reaches the model. Add org-specific patterns (internal domains, project names) from a local, git-ignored file.
- Disable tools for pure text transforms. The job reads input and writes an answer, nothing more.
- Validate output: parse the JSON, check labels are from the allowed set, and treat anything else as "needs a human".
- Cap cost with
--max-turnsand, where available,--max-budget-usd.
Changes only through merge requests
- Claude works on a branch, never the default branch.
- It opens a draft MR (
glab mr create --draft) or leaves the branch for you to push. - CI runs plan and tests; a human reviews and merges.
- MR descriptions state that an agent drafted the change.
Pitfalls
- A long CLAUDE.md nobody maintains. Keep it under a page; link to docs for the rest.
- Pasting log excerpts with secrets into an interactive session. Redact first, even when it feels urgent.
- Trusting a plan summary instead of the plan. Read the real
terraform planoutput.