In short
- CLAUDE.md is context, not enforcement. Hard limits belong in settings.json permission rules, hooks and the sandbox.
- Deny .env and state files with Read rules, then enable the sandbox, because Read rules do not cover every shell command.
- Plan mode, a PreToolUse guard for terraform apply and kubectl delete, and /usage habits keep infra sessions safe and cheap.
On this page
- Install and verify
- Sign in with the account you mean to bill
- CLAUDE.md: user, project and local
- settings.json: allow, ask and deny
- Plan mode for anything near state
- Hooks: guardrails that do not depend on the model
- Keep secrets out of context
- MCP servers
- Subagents
- Skills and slash commands
- Plugins and marketplaces
- Cost and usage
- Setup checklist
Pointing Claude Code at Terraform, Ansible, Kubernetes manifests and CI pipelines is one thing; giving it a path to production is another. What follows is a baseline setup in the order you would build it: install, sign-in, instruction files, permission rules, plan mode, hooks, secret handling, MCP, subagents, skills, plugins and cost control, with config you can paste.
The opinions come from running production systems. I am a cloud infrastructure and security engineer with more than eight years on AWS, Azure, Google Cloud and Oracle Cloud, and I use Claude Code and Codex daily in client delivery. Every product detail below was checked against Anthropic’s documentation on 11 November 2026, when the latest Claude Code release on GitHub was v2.1.322.
Install and verify
# macOS, Linux, WSL: native installer, updates itself in the background
curl -fsSL https://claude.ai/install.sh | bash
# Homebrew: claude-code tracks the stable channel, claude-code@latest tracks latest
brew install --cask claude-code
# Windows
winget install Anthropic.ClaudeCode
# Confirm the binary and check settings files for errors
claude --version
claude doctor
Native installs auto-update; Homebrew and WinGet installs do not, so upgrade those yourself. The npm package (@anthropic-ai/claude-code, Node.js 22 or later) installs the same native binary; never install it with sudo.
For bastions, build hosts and golden images, Anthropic publishes signed apt, dnf and apk repositories. If you manage machines with Ansible, those are a cleaner fit than a piped install script. On shared machines, set "autoUpdatesChannel": "stable", which runs about a week behind and skips releases with major regressions.
Sign in with the account you mean to bill
Claude Code needs a Pro, Max, Ultra, Team, Enterprise or Console account. The Free plan does not include it. Run claude and follow the browser login, or point it at Amazon Bedrock, Google Cloud’s Agent Platform or Microsoft Foundry with CLAUDE_CODE_USE_BEDROCK, CLAUDE_CODE_USE_VERTEX or CLAUDE_CODE_USE_FOUNDRY.
Watch for one trap. If ANTHROPIC_API_KEY is exported in your shell and you approve it at the prompt, Claude Code uses that key instead of your subscription. Run unset ANTHROPIC_API_KEY and check /status to see which credential is active. For CI, claude setup-token generates a long-lived token you pass as CLAUDE_CODE_OAUTH_TOKEN. For short-lived credentials from a vault, apiKeyHelper runs your own command and caches the result for five minutes by default.
Subscription prices, checked on 11 November 2026:
| Plan | Price (USD) | Usage |
|---|---|---|
| Pro | $17/month billed annually ($200 up front), or $20 monthly | Baseline |
| Max | $100/month | 5x Pro, every 5 hours and every week |
| Ultra | $200/month | 10x Pro weekly, no 5-hour limit for verified accounts |
| Team Standard | $20/seat/month annually, $25 monthly | More than Pro |
| Team Premium | $100/seat/month annually, $125 monthly | 5x Standard |
CLAUDE.md: user, project and local
| Scope | Location | What belongs there |
|---|---|---|
| User | ~/.claude/CLAUDE.md |
Your preferences across every project |
| Project | ./CLAUDE.md or ./.claude/CLAUDE.md |
Commands, layout and conventions; commit it |
| Local | ./CLAUDE.local.md |
Your notes for one repo; add it to .gitignore |
| Managed | /etc/claude-code/CLAUDE.md on Linux |
Organisation policy deployed by IT |
Run /init to generate a starting file, then cut it down. Anthropic’s guidance is under 200 lines per file, with concrete, checkable instructions. @path imports help you organise a long file (up to four hops deep) but do not reduce its context cost. Instructions that only matter for some files go in .claude/rules/ with a paths frontmatter, so they load only when Claude touches matching files. If a repo already has an AGENTS.md and no CLAUDE.md, Claude Code v2.1.277 and later reads the AGENTS.md; the Claude Code vs Codex CLI comparison covers sharing one file between tools.
The point that matters most: Claude treats CLAUDE.md as context, not enforced configuration. Anything that must never happen goes in permission rules or hooks, covered next.
A project file for a Terraform repo can stay this short:
# Infrastructure repo
## Layout
- modules/: reusable Terraform modules, one per directory
- envs/<name>/: root modules, one per environment, each with its own backend
- ansible/: playbooks and roles for host configuration
## Commands
- Format: terraform fmt -recursive
- Validate: terraform validate (inside a root module)
- Plan: terraform plan -out=tfplan (ask first, it uses live credentials)
## Rules
- Never run terraform apply, terraform destroy or kubectl delete. A human runs applies.
- Pin every provider and module version.
- Tag every resource with owner and environment.
And a path-scoped rule at .claude/rules/terraform.md:
---
paths:
- "**/*.tf"
---
# Terraform rules
- Prefer for_each over count when resources have a stable key.
- Mark outputs that carry secrets with sensitive = true.
settings.json: allow, ask and deny
Settings live in four places. ~/.claude/settings.json is yours across all projects. .claude/settings.json is the team file you commit. .claude/settings.local.json is your per-repo override, which Claude Code keeps out of git when it creates the file. Managed settings come from your organisation and override everything. List keys such as permissions.allow merge across files rather than replacing each other.
Rules are evaluated deny first, then ask, then allow, and the first match decides. A specific allow rule cannot carve an exception out of a broad deny, and deny rules apply in every mode, including bypassPermissions. This is a sensible starting .claude/settings.json for an infrastructure repo:
{
"$schema": "https://json.schemastore.org/claude-code-settings.json",
"permissions": {
"defaultMode": "default",
"allow": [
"Bash(terraform fmt *)",
"Bash(terraform validate)",
"Bash(git diff *)",
"Bash(git log *)",
"Bash(kubectl get *)",
"WebFetch(domain:registry.terraform.io)"
],
"ask": [
"Bash(terraform init *)",
"Bash(terraform plan *)",
"Bash(git push *)"
],
"deny": [
"Bash(terraform apply *)",
"Bash(terraform destroy *)",
"Bash(kubectl delete *)",
"Read(./.env)",
"Read(./.env.*)",
"Read(**/*.tfstate)",
"Read(**/*.tfstate.backup)",
"Read(~/.aws/credentials)",
"Read(~/.ssh/**)"
]
}
}
Since v2.1.283, interactive sessions start in auto mode unless you say otherwise, with a background classifier reviewing actions instead of you. "defaultMode": "default" starts infra repos in manual mode, so you raise autonomy deliberately. Note that auto and bypassPermissions cannot be set from project or local files at all.
Three details catch people out:
- Wildcard position. Put the
*after the subcommand.Bash(git log *)allows onlygit log;Bash(git * main)also matchesgit -c core.fsmonitor=<script> diff main. - Rules match command text, not programs.
Bash(rm *)stopsrm -rf build/but not/bin/rm -rf build/orbash -c 'rm -rf build/'. Bash deny rules are guard rails for the usual invocation, not a security boundary. - Read rules have edges. Read and Edit deny rules cover Claude’s file tools, recognised commands such as
cat,head,tail,sedandtee, and redirections. They do not covergrep -racross a directory or a script that opens files itself. That gap is what the sandbox is for.
Run /permissions to see every active rule and the file it came from.
Plan mode for anything near state
Plan mode lets Claude read files and run read-only commands, then propose a plan without editing anything. Enter it three ways: press Shift+Tab to cycle through modes (manual, accept edits, plan), prefix one prompt with /plan, or start with claude --permission-mode plan. When the plan is ready you choose to approve with auto mode, approve and review each edit, or keep planning. Ctrl+G opens the plan in your editor first.
Use it for module refactors, provider upgrades and anything that could cause a resource replacement. The opusplan model alias uses Opus while planning and switches to Sonnet to execute, which suits this pattern.
Hooks: guardrails that do not depend on the model
Hooks are shell commands Claude Code runs at lifecycle events. PreToolUse fires before a tool call and can block it; PostToolUse fires after one succeeds. The hook receives JSON on stdin: tool_name, plus tool_input, where Bash commands arrive as tool_input.command and file edits as tool_input.file_path. Exit code 2 blocks the call and sends your stderr to Claude as feedback. Exit 0 means no decision, so the normal permission flow still applies.
A hook sees the full command string, so it catches wrapped forms that permission rules miss. Save this as .claude/hooks/guard-infra.sh:
#!/bin/bash
# Block destructive infrastructure commands, including wrapped or flagged forms.
CMD=$(jq -r '.tool_input.command // empty')
if echo "$CMD" | grep -Eq 'terraform.*[[:space:]](apply|destroy)([[:space:]]|$)|kubectl.*[[:space:]]delete([[:space:]]|$)'; then
echo "Blocked: destructive infrastructure command. Propose it for a human to run." >&2
exit 2
fi
exit 0
It matches terraform -chdir=envs/prod apply and bash -c 'kubectl -n prod delete pod x', and errs towards blocking: a commit message mentioning terraform apply is stopped too. Add a formatter as .claude/hooks/tf-fmt.sh:
#!/bin/bash
# Run terraform fmt on Terraform files after Claude edits them.
FILE=$(jq -r '.tool_input.file_path // empty')
case "$FILE" in
*.tf|*.tfvars) terraform fmt "$FILE" >/dev/null ;;
esac
exit 0
Register both in .claude/settings.json:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{ "type": "command", "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/guard-infra.sh" }
]
}
],
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{ "type": "command", "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/tf-fmt.sh" }
]
}
]
}
}
Run chmod +x .claude/hooks/*.sh, then /hooks to confirm both are registered. When several hooks match, they run in parallel and the most restrictive decision wins. Hooks execute with your account’s access, so read the hooks in any repo you clone before you trust the folder.
Keep secrets out of context
Treat this as layers, since no single control covers everything.
- Read deny rules. The
denylist above stops Claude’s file tools from reading.envfiles, state and credentials, removes matches from file discovery and search results, and blocks edits to those paths. A.claudeignorefile has no effect; move its entries into Read deny rules. - The sandbox. It is off by default. Turn it on with
/sandboxorsandbox.enabled. Sandboxed commands can write only to the working directory, a temp directory and added directories, and network traffic goes through a proxy whose allowed domains start empty. Reads still cover most of the machine, including~/.sshand~/.aws/credentials, until you deny them. On Linux and WSL2 it needsbubblewrapandsocat; native Windows is not supported. - Credential scrubbing.
CLAUDE_CODE_SUBPROCESS_ENV_SCRUB=1strips credentials from the environment of Bash commands, hooks and stdio MCP servers, while Claude Code keeps its own. - No literal tokens in MCP config. Use
${VAR}expansion, shown in the next section.
The sandbox’s credentials block protects files and environment variables from sandboxed commands:
{
"sandbox": {
"enabled": true,
"credentials": {
"files": [
{ "path": "~/.aws/credentials", "mode": "deny" },
{ "path": "~/.ssh", "mode": "deny" }
],
"envVars": [
{ "name": "GITHUB_TOKEN", "mode": "deny" },
{ "name": "NPM_TOKEN", "mode": "deny" }
]
}
}
}
There is no built-in credential deny list, so only what you list is protected. Denying ~/.aws/credentials also means sandboxed commands cannot use it, which for terraform plan is usually what you want.
MCP servers
# Remote HTTP server, local scope (default): only you, only this project
claude mcp add --transport http notion https://mcp.notion.com/mcp
# Shared with the team: written to .mcp.json in the repo
claude mcp add --transport http shared-server --scope project https://example.com/mcp
# Local stdio server: everything after -- is the server's own command
claude mcp add --transport stdio myserver -- npx server
There are three scopes: local (the default, stored in ~/.claude.json), project (.mcp.json, committed) and user (~/.claude.json, every project). In .mcp.json, reference secrets from the environment instead of writing them down:
{
"mcpServers": {
"api-server": {
"type": "http",
"url": "${API_BASE_URL:-https://api.example.com}/mcp",
"headers": { "Authorization": "Bearer ${API_KEY}" }
}
}
}
Claude Code asks before using project servers from a cloned .mcp.json; /mcp shows status and handles OAuth. Verify every server you connect, since servers that fetch external content expose you to prompt injection. Tool definitions are deferred by default, but the docs still recommend CLI tools such as gh, aws and gcloud where they exist. I built a multi-model routing MCP server that sends tasks across Claude, Codex, Gemini, Cloudflare Workers AI and local LM Studio models; a server like that, tied to no single repo, belongs at user scope.
Subagents
Subagents are Markdown files with YAML frontmatter in .claude/agents/ (project) or ~/.claude/agents/ (personal). Each runs in its own context window with its own tools and returns a summary, which keeps plan output and logs out of your main conversation. Built-in ones include Explore, Plan and a general-purpose agent. A read-only reviewer for Terraform changes:
---
name: tf-plan-reviewer
description: Reviews Terraform diffs and plan output for destroys, replacements, version changes and missing tags. Use after changes under modules/ or envs/.
tools: Read, Grep, Glob
model: sonnet
---
You review Terraform changes. Read the diff and any plan output you are given.
Report resources that will be destroyed or replaced, provider and module version
changes, missing owner or environment tags, and secrets in plain text.
Do not edit files. Return findings ordered by risk.
Skills and slash commands
A skill is a directory with a SKILL.md, in .claude/skills/<name>/ or ~/.claude/skills/<name>/. Only its description sits in context until it is invoked, by Claude when relevant or by you with /name. Custom commands have merged into skills, and existing .claude/commands/ files keep working. Skills follow the open Agent Skills standard, so the same format works in other agents, Codex included.
---
name: drift-summary
description: Summarise uncommitted Terraform changes and flag risky ones before a plan.
disable-model-invocation: true
---
## Changed Terraform files
!`git diff HEAD -- '*.tf' '*.tfvars'`
## Instructions
List each changed resource or module call, say whether it is likely to replace
or destroy anything, and suggest which root module to plan next.
If the diff is empty, say there are no changes.
disable-model-invocation: true keeps it manual. The !`command` line runs first and its output replaces the line before Claude reads the skill.
Built-in commands worth learning on day one: /init, /memory, /permissions, /hooks, /mcp, /sandbox, /context, /compact, /clear, /usage, /code-review (alias /review) and /security-review, which checks your branch’s diff for injection, auth and data-exposure issues. For more on review tooling, see security review skills for AI coding agents.
Plugins and marketplaces
Plugins bundle skills, agents, hooks and MCP servers. Inside a session:
/plugin install commit-commands@claude-plugins-official
/plugin marketplace add your-org/plugins
From a shell or setup script:
claude plugin install formatter@your-org --scope project
claude plugin details commit-commands
Anthropic’s official marketplace registers itself on your first interactive session. The install pane lists what a plugin adds (commands, agents, skills, hooks, MCP and LSP servers) and, for official plugins, its context cost; read it, because plugins can run hooks and MCP servers. Project scope commits the enable entry, but each collaborator still installs once per clone. Auto-update is on by default for official marketplaces and off for third-party ones. claude plugin details shows the always-on token cost. I run two third-party plugins, covered in my write-ups of Everything Claude Code and oh-my-claudecode.
Cost and usage
/usage (aliases /cost and /stats) shows session cost for API users and, for subscribers, plan usage bars with a breakdown of what consumed them and suggested fixes. Anthropic’s own figures, checked on 11 November 2026: across enterprise deployments the average is about $13 per developer per active day and $150 to $250 per developer per month, with 90% of users under $30 per active day.
Habits that cut spend, all from Anthropic’s guidance:
/clearbetween unrelated tasks; it costs nothing, while compacting a large context is itself a large request.- Sonnet for most coding, Opus for architecture and multi-step reasoning, Haiku for simple subagents.
/contextto see what fills the window, and/effortto lower reasoning on simple work.- Keep CLAUDE.md under 200 lines and move workflows into skills, which load only on use.
- Prefer CLI tools to MCP servers where both exist.
- In print mode, cap runs with
claude -p --max-budget-usd 5.00 "...".
When an app built this way is ready for real users, how to launch a vibe-coded app securely covers the review, deploy and monitoring steps.
Setup checklist
- Install natively, run
claude doctor, use thestablechannel on shared machines. - Sign in with the intended account and
unset ANTHROPIC_API_KEYif it should not win. - Keep CLAUDE.md short; move file-specific rules into
.claude/rules/. - Commit
.claude/settings.jsonwith allow, ask and deny lists and"defaultMode": "default". - Deny
.env, state files,~/.aws/credentialsand~/.sshwith Read rules. - Add a PreToolUse guard and a PostToolUse formatter.
- Enable the sandbox with a
credentialsblock and setCLAUDE_CODE_SUBPROCESS_ENV_SCRUB=1. - Plan first for refactors and anything near state.
- Add MCP servers at the narrowest scope, with
${VAR}for secrets. - Read every plugin’s install pane before installing.
- Check
/usageregularly and/clearbetween tasks.
Sources
- Advanced setup (Claude Code Docs) code.claude.com
- Authentication (Claude Code Docs) code.claude.com
- Settings files and precedence (Claude Code Docs) code.claude.com
- All settings (Claude Code Docs) code.claude.com
- Configure permissions (Claude Code Docs) code.claude.com
- Permission modes (Claude Code Docs) code.claude.com
- How Claude remembers your project (Claude Code Docs) code.claude.com
- Automate actions with hooks (Claude Code Docs) code.claude.com
- Configure the sandboxed Bash tool (Claude Code Docs) code.claude.com
- Environment variables (Claude Code Docs) code.claude.com
- Connect Claude Code to tools via MCP (Claude Code Docs) code.claude.com
- Create custom subagents (Claude Code Docs) code.claude.com
- Extend Claude with skills (Claude Code Docs) code.claude.com
- Install and manage plugins (Claude Code Docs) code.claude.com
- Commands (Claude Code Docs) code.claude.com
- Model configuration (Claude Code Docs) code.claude.com
- Manage costs effectively (Claude Code Docs) code.claude.com
- Plans & pricing claude.com
- anthropics/claude-code releases on GitHub github.com
- Agent Skills Overview agentskills.io
- Build skills (OpenAI Codex docs) learn.chatgpt.com
- terraform fmt command reference developer.hashicorp.com