Claude Code Skills for Infrastructure Automation

2026-01-24 - 13 min read
Daniel Young
Daniel Young
Founder, DRYCodeWorks

Runbooks go stale and nobody reads them. Encode your Terraform, migration and deploy procedures as Claude Code skills the agent follows step by step.

A pile of handwritten notes becomes a deck of punched cards that drives a small machine running three server racks

You've probably experienced this: a new team member asks how to run database migrations for the staging environment. You point them to a Confluence page that was last updated eighteen months ago. Half the commands are wrong. The environment variables have different names now. They spend two hours debugging something that should take five minutes.

Documentation rots. Tribal knowledge lives in Slack threads and people's heads. And every time someone leaves the team, you lose a little more institutional memory.

What if instead of writing documentation that goes stale, you could encode your team's workflows as executable instructions that an AI assistant follows step-by-step? That's the promise of Claude Code skills—reusable markdown files that turn your procedures into guided automation.

What Are Claude Code Skills?

  • Skill: A directory with a SKILL.md file that gives Claude Code domain-specific instructions for completing a task. Project skills live at .claude/skills/<skill-name>/SKILL.md and run as /<skill-name> (e.g., /deploy-staging). Claude can also load a skill on its own when your request matches the skill's description.
  • Agentic Workflow: A multi-step process where Claude Code executes commands, reads output, makes decisions, and continues autonomously until the task is complete or requires human input.
  • CLAUDE.md: A project-level configuration file that provides persistent context to Claude Code about your codebase, conventions, and workflows.

Skills differ from simple prompts in a crucial way: they're procedural. A skill doesn't just describe what you want—it specifies the exact steps, decision points, error handling, and verification criteria for a workflow. Claude Code follows the skill like a runbook, but with the intelligence to adapt when things go wrong.

If you've written custom slash commands, you already know most of this. Claude Code merged custom commands into skills: a file at .claude/commands/deploy.md and a skill at .claude/skills/deploy/SKILL.md both create /deploy. Existing command files keep working. Skills add a directory for supporting files and frontmatter that controls whether you, Claude, or both can invoke them.

Invoking Skills

A skill's command comes from its directory. A skill at .claude/skills/deploy-staging/SKILL.md runs when you type:

text
/deploy-staging

The frontmatter name field is optional, and without it the directory name is the command. You don't always have to type it: Claude reads each skill's description and loads the skill on its own when your request matches. Claude runs skills through its Skill tool, which is also how one skill's instructions can tell Claude to run another.

Project skill names are flat; you never write a colon in one. Colons appear when Claude Code adds a prefix:

  • Plugin skills - Claude Code namespaces them by plugin, so review in a plugin named team-tools runs as /team-tools:review. Running a Private Claude Code Plugin Marketplace covers packaging skills that way.
  • Nested skill directories - when a skill in a subdirectory's .claude/skills/ has the same name as another skill, the nested one runs under a directory-qualified name, such as /apps/web:deploy.
  • Command files in subfolders - the older .claude/commands/frontend/component.md format runs as /frontend:component.

You can pass arguments after the skill name:

text
/deploy staging
/postgres-backup production --skip-verification

Claude Code substitutes them into the skill wherever it says $ARGUMENTS. Pattern 5 below covers argument handling.

Anatomy of a Skill File

Each skill is a directory containing a SKILL.md file: YAML frontmatter between --- markers, then markdown instructions. Every frontmatter field is optional. These are the ones that matter for infrastructure work:

  • name: The command name. Defaults to the directory name, so most skills leave it out.
  • description: What the skill does and when to use it. Claude uses it to decide when to load the skill automatically, so put the key use case first. If you leave it out, Claude Code uses the first non-empty line of the instructions.
  • disable-model-invocation: Set to true so the skill runs only when you type /name. Use it for workflows with side effects, like deploys and migrations: you don't want Claude deciding to deploy because your code looks ready.
  • allowed-tools: Tools Claude can use without asking during the turn that invokes the skill, such as Bash(npm test). It pre-approves; it doesn't restrict. Every other tool stays available under your normal permission settings.
  • argument-hint: The hint shown during autocomplete for the arguments the skill expects, such as [environment].

The frontmatter stays small. Skills are primarily defined by their markdown content: the intelligence comes from how you write the instructions, not from metadata flags.

Here's a complete example:

.claude/skills/deploy-staging/SKILL.mdmarkdown
---
description: Deploy the current branch to staging environment with verification
disable-model-invocation: true
allowed-tools: Bash(npm test) Bash(npm run build)
---

# Deploy to Staging

**Announce at start:** "I'm using deploy-staging to deploy your changes."

## Prerequisites

Before deploying, verify:
- Current branch has no uncommitted changes
- All tests pass locally
- You're authenticated to AWS

## Workflow

### Step 1: Run Tests

```bash
npm test
```

If tests fail, stop and report the failures.

### Step 2: Build for Production

```bash
npm run build
```

### Step 3: Deploy

```bash
serverless deploy --stage staging
```

### Step 4: Verify

After deployment, run smoke tests:

```bash
curl https://staging.example.com/health
```

Report the deployment status and health check results.

The structure matters. Claude Code reads the skill and follows it sequentially, executing commands and checking results at each step. The more explicit you are about decision points and success criteria, the better the automation works. The frontmatter keeps Claude from starting a deploy on its own and pre-approves the test and build commands, so the deploy command still goes through your normal permission prompt.

What Execution Looks Like

When you invoke /deploy-staging, Claude Code shows its progress:

text
> /deploy-staging

I'm using deploy-staging to deploy your changes.

Checking prerequisites...

$ git status
On branch feature/user-auth
nothing to commit, working tree clean

✓ No uncommitted changes

$ npm test
PASS  src/auth.test.ts
PASS  src/api.test.ts
Test Suites: 2 passed, 2 total

✓ All tests pass

$ npm run build
Build completed successfully.

✓ Production build ready

$ serverless deploy --stage staging
Deploying to staging...
Service deployed to: https://staging.example.com

$ curl https://staging.example.com/health
{"status": "healthy", "version": "1.2.3"}

✓ Health check passed

**Deployment complete.** Your changes are live at https://staging.example.com

Each step shows the command, its output, and a status indicator. When something fails, Claude Code stops at that step and reports the issue before asking how to proceed.

Building Your First Infrastructure Skill

Let's build a real skill: running ClickHouse database migrations safely. This workflow has several steps that are easy to get wrong:

  • Verify you're targeting the correct environment
  • Run migrations in the proper order
  • Validate the schema after migration
  • Handle rollback if something fails

Here's how to encode this as a skill:

.claude/skills/clickhouse-migrate/SKILL.mdmarkdown
---
description: Run ClickHouse migrations safely with validation and rollback support
disable-model-invocation: true
allowed-tools: Bash(alembic -c alembic-clickhouse.ini current) Bash(alembic -c alembic-clickhouse.ini history *)
---

# ClickHouse Migration

**Announce at start:** "I'm using clickhouse-migrate to run database migrations."

## Prerequisites

Verify environment before proceeding:

```bash
echo "Target: $CLICKHOUSE_HOST"
```

Ask user to confirm this is the correct environment.

## Workflow

### Step 1: Check Current State

```bash
alembic -c alembic-clickhouse.ini current
```

Report the current migration version.

### Step 2: Show Pending Migrations

```bash
alembic -c alembic-clickhouse.ini history --indicate-current
```

List all pending migrations and ask user to confirm.

### Step 3: Run Migration

```bash
alembic -c alembic-clickhouse.ini upgrade head
```

If migration fails:
1. Report the error
2. Ask user: "Should I attempt rollback?"
3. If yes, run: `alembic -c alembic-clickhouse.ini downgrade -1`

### Step 4: Validate Schema

```bash
clickhouse-client --query "DESCRIBE TABLE logs"
```

Compare output to expected schema. Report any discrepancies.

### Step 5: Verify Data Integrity

```bash
clickhouse-client --query "SELECT count() FROM logs"
```

Report row count to confirm data is accessible.

Notice the decision points: "Ask user to confirm," "If migration fails." These create natural breakpoints where Claude Code pauses for human input rather than charging ahead blindly. The frontmatter backs them up: allowed-tools pre-approves only the two read-only alembic commands, so upgrade and downgrade still go through your normal permission prompt.

Skill Design Patterns

After building dozens of skills across infrastructure, deployment, and data pipelines, patterns emerge for what works well.

Pattern 1: Announce-Verify-Execute-Confirm

Every skill should follow this rhythm:

  1. Announce - Tell the user what's about to happen
  2. Verify - Check prerequisites and current state
  3. Execute - Run the actual commands
  4. Confirm - Validate the outcome and report results

This pattern prevents surprises and creates audit trails. When something goes wrong three weeks from now, you'll have Claude Code's output showing exactly what commands ran and what the state was at each step.

AnnounceVerifyExecuteConfirmTell user what'shappeningCheckprerequisitesRuncommandsValidate &report

Pattern 2: Explicit Decision Trees

Don't leave decisions implicit. If a command might fail in different ways, enumerate them:

markdown
### Handle Terraform Plan Output

After running `terraform plan`:

**If no changes:** Report "No infrastructure changes needed" and exit.

**If only additions:** Show the additions and ask "Proceed with apply?"

**If modifications or deletions:**
1. Highlight the destructive changes in a warning
2. Ask user to type "confirm" to proceed
3. Do NOT proceed without explicit confirmation

Pattern 3: Checkpoints for Long Workflows

For workflows that take more than a few minutes, add explicit checkpoints:

markdown
### Checkpoint: Database Backup Complete

✅ Backup created: `backup-2026-01-24-staging.sql`
✅ Backup verified: 2.3GB, checksum matches
✅ Uploaded to S3: s3://backups/staging/

**Continue with migration?** (The backup can be restored if needed)

This prevents the frustration of a workflow failing 80% through with no way to resume.

Pattern 4: Tool Integration

Skills can invoke other skills for modularity:

markdown
### Step 3: Create Backup

Invoke **backup-database** skill before proceeding with destructive operations.

This lets you compose complex workflows from simpler, tested components. A skill you call this way can't set disable-model-invocation: true, because that setting stops Claude from running it.

Pattern 5: Handling Arguments

Skills can accept arguments passed after the skill name. Claude Code replaces $ARGUMENTS in the skill with everything you typed after the name, and $0, $1, and so on with individual arguments:

.claude/skills/deploy/SKILL.mdmarkdown
---
description: Deploy to a specified environment (staging, production)
disable-model-invocation: true
argument-hint: "[environment]"
---

# Deploy

**Target environment:** $ARGUMENTS

If no environment is provided, ask the user which environment to deploy to.

## Validation

Valid environments: staging, production

If the provided environment is not in this list, report the error and exit.

## Workflow

### For Staging

```bash
serverless deploy --stage staging
```

### For Production

Production deployments require additional verification:

1. Confirm all staging tests have passed
2. Ask user to type "deploy production" to confirm
3. Run: `serverless deploy --stage production`

Running /deploy staging makes the first line read "Target environment: staging." If a skill has no placeholder at all, Claude Code appends what you typed to the end of the skill as ARGUMENTS: <value>, so Claude still sees it. Either way, Claude reads the result as natural language: /deploy staging and /deploy to production both work, and the validation section still decides what counts as a valid environment.

Organizing Skills for Teams

As your skill library grows, organization becomes important. Project skills sit one level deep, each in its own directory, and the directory name is the command:

text
.claude/
├── skills/
│   ├── terraform-plan/
│   │   └── SKILL.md          # /terraform-plan
│   ├── terraform-apply/
│   │   └── SKILL.md          # /terraform-apply
│   ├── rotate-secrets/
│   │   └── SKILL.md          # /rotate-secrets
│   ├── clickhouse-migrate/
│   │   ├── SKILL.md          # /clickhouse-migrate
│   │   └── rollback.md       # supporting file, read when needed
│   ├── postgres-backup/
│   │   └── SKILL.md          # /postgres-backup
│   └── deploy-staging/
│       └── SKILL.md          # /deploy-staging
└── CLAUDE.md

Commit .claude/skills/ and everyone who works in the repository gets the same commands. A shared prefix such as terraform- or postgres- keeps related skills easy to find without nesting. The skill's directory is also where supporting files go: keep SKILL.md focused and move long reference material, like a rollback runbook, into a file beside it that the skill links to. Personal skills follow the same layout under ~/.claude/skills/ and load in every project on your machine.

When the library outgrows one repository, package it as a plugin. Plugin skills live at skills/<skill-name>/SKILL.md inside the plugin and run as /plugin-name:skill-name, which is where colon namespacing comes from. Running a Private Claude Code Plugin Marketplace covers packaging and rollout. Keep your CLAUDE.md file focused on project-wide context: coding standards, architectural decisions, and common patterns. Skills handle specific workflows.

Testing and Iteration

Skills benefit from the same iterative refinement as code. Here's how to debug when things go wrong.

Watch the Execution

When Claude Code runs a skill, it shows each step in real-time. Watch for:

  • Skipped steps - Claude Code interpreted your instructions differently than intended
  • Wrong commands - Ambiguous phrasing led to incorrect command construction
  • Missing confirmations - Decision points that should pause but didn't

Common Failure Modes

"Claude Code ran the wrong command"

Your instruction was ambiguous. Instead of:

markdown
Run the tests.

Be explicit:

markdown
```bash
npm test
```

Run this exact command. Do not substitute with yarn, pnpm, or other alternatives.

"Claude Code didn't stop when it should have"

Decision points need explicit stop instructions:

markdown
If the health check fails:
1. Report the failure with the HTTP status code
2. **STOP and ask the user** whether to proceed or rollback
3. Do NOT continue to the next step without explicit confirmation

"Claude Code asked too many questions"

You added too many confirmation points. Reserve confirmations for destructive operations or genuine decision points—not every step.

Test Systematically

Run your skill in these scenarios:

  1. Happy path - Everything works as expected
  2. Missing prerequisites - What happens when AWS credentials are missing?
  3. Command failures - Does it handle non-zero exit codes correctly?
  4. Ambiguous input - What if the user provides unexpected arguments?

A well-tuned skill feels like pair programming with someone who knows your infrastructure. A poorly-written skill feels like giving directions to a city you've never visited—technically correct words that lead somewhere unexpected. The difference is specificity.

When Skills Beat Traditional Automation

Skills aren't a replacement for proper CI/CD pipelines or infrastructure-as-code. They excel in specific scenarios:

  • Infrequent operations - Tasks you run monthly don't justify a full automation pipeline
  • Judgment-required workflows - Operations where human review is needed mid-process
  • Debugging and investigation - Following a systematic troubleshooting process
  • Onboarding acceleration - New team members can execute complex workflows immediately

The meta-benefit is that writing a skill forces you to articulate your workflow precisely. That precision is valuable whether Claude Code runs it or a human follows it manually.

Quick Reference

Skill File Location

text
.claude/skills/<skill-name>/SKILL.md      # project: commit it for your team
~/.claude/skills/<skill-name>/SKILL.md    # personal: every project on your machine

Frontmatter

yaml
---
description: What it does and when to use it; drives automatic invocation
disable-model-invocation: true   # optional: only you can run it
allowed-tools: Bash(npm test)    # optional: pre-approved for the invoking turn
argument-hint: "[environment]"   # optional: autocomplete hint
---

name is optional and defaults to the directory name.

Invocation

text
/skill-name
/skill-name argument1 argument2     # $ARGUMENTS, or $0 and $1
/plugin-name:skill-name             # a skill from a plugin

Essential Patterns

  • Announce - Start with "I'm using [skill] to [action]"
  • Explicit commands - Use fenced code blocks for exact commands
  • Decision points - Say "STOP and ask" for destructive operations
  • Validation - End with verification commands and success criteria

Common Phrases

IntentPhrase
Require confirmation"Ask user to confirm before proceeding"
Hard stop"STOP and ask the user"
Conditional"If [condition], then [action]. Otherwise, [alternative]."
Report"Report [metric] to the user"
Invoke another skill"Invoke other-skill before proceeding"

Getting Started

If you're new to Claude Code skills, start small:

  1. Pick one workflow your team runs weekly
  2. Write out the steps as you'd explain them to a new team member
  3. Convert those steps into a skill file with explicit commands
  4. Run it with Claude Code and note where it deviates from your intent
  5. Refine until it works reliably

The first skill takes an hour to get right. The tenth skill takes ten minutes. The investment compounds as your library grows and your team's tribal knowledge becomes executable infrastructure.

Your documentation doesn't have to rot. Your procedures don't have to live in people's heads. With Claude Code skills, you can encode your team's expertise in a format that stays current and executes reliably—because Claude Code follows the instructions every time, exactly as written.