---
name: afx-iac-scaffold
description: Scaffold a fresh infra/ directory tree for a new project using the canonical Artifex IaC layout. Use this skill when the user wants to bootstrap infrastructure-as-code for a new project, reproduce the numen/xenia directory-per-environment Terraform pattern, or set up a local-compose stub for Docker-based development.
---

# Artifex IaC Scaffold Skill

**For Claude Code AI Assistant**

This skill scaffolds the canonical Artifex Infrastructure-as-Code directory layout for a new project. It reproduces the directory-per-environment Terraform pattern used in `numen/infra` and `xenia/pms/infra`, so users stop re-deriving it per project.

## What it produces

```
infra/
├── environments/
│   ├── local-compose/   # docker-compose.yml + README — local dev only, NOT Terraform
│   ├── dev/             # main.tf, variables.tf, outputs.tf, terraform.tfvars
│   ├── staging/         # ditto
│   ├── prod/            # ditto
│   └── shared/          # ditto — cross-env resources (DNS, shared databases, ECR, etc.)
├── modules/             # README placeholder for reusable Terraform modules
└── README.md
```

## Key design decisions

- **Directory-per-environment, not Terraform workspaces.** Each cloud environment (`dev`, `staging`, `prod`, `shared`) is its own Terraform root with its own state file. This matches the actual pattern in the user's projects despite earlier verbal description as "workspaces."
- **Commented-out S3 backend.** Each Terraform environment's `main.tf` includes a backend block that is commented out by default (matching the xenia pattern). The user uncomments it after bootstrapping the S3 bucket. The key is `<env>/terraform.tfstate` so each environment's state is isolated in the same bucket.
- **Default local backend works immediately.** `terraform init` in any cloud env directory succeeds without any edits (AC3).
- **`local-compose` is not Terraform.** Its README explicitly says it is for local development only and not Terraform-managed (AC5).
- **`--force` required to overwrite.** If `infra/` already exists, the skill refuses with a clear error unless `--force` is passed (AC4).

## Conversational Routing

| User phrasing | Action |
|---------------|--------|
| "scaffold infra/", "bootstrap my IaC layout", "set up Terraform directories", "create infra structure" | `init` |
| "scaffold into a different directory", "use `infrastructure/` instead of `infra/`" | `init --target=infrastructure` |
| "use us-east-1", "set my region to ca-central-1" | `init --region=<region>` |
| "preview what it will create", "show me without writing" | `init --dry-run` |
| "overwrite my existing infra/", "re-scaffold" | `init --force` |

If the user asks about workspaces, clarify: this skill uses directory isolation, not Terraform workspaces. The terms are often confused, but directory-per-env is the pattern the user's projects actually use.

## How to Run This Skill

### Scaffolding a new project (`init`)

1. Confirm the target directory. Default is `./infra` in the current project root; pass `--target=<path>` to override.
2. **Always preview with `--dry-run` first:**
   ```bash
   ~/.claude/skills/afx-iac-scaffold/afx-iac-scaffold.sh init --dry-run
   ```
   Show the user what will be created.
3. Confirm the region. Default options are `ca-central-1` (numen/xenia) and `us-east-1` (zoe). When running non-interactively, pass `--region=<region>` explicitly.
4. If they approve, run for real:
   ```bash
   ~/.claude/skills/afx-iac-scaffold/afx-iac-scaffold.sh init --project=myapp --region=ca-central-1
   ```
5. Point them at the next steps:
   - `cd infra/environments/dev && terraform init` to verify the local backend works.
   - Edit `main.tf` to add resources.
   - Uncomment the `backend "s3"` block when ready for remote state.

**Edge cases init handles:**

- **Target does not exist:** Creates it and all subdirectories.
- **Target exists:** Refuses with exit 1 unless `--force`. With `--force`, overwrites the existing files.
- **Non-interactive (no TTY or `--dry-run`):** Skips the region prompt and defaults to `ca-central-1`. Pass `--region=<region>` to override.

### After scaffolding

Walk the user through the immediate next steps in order:

1. **Verify the local backend works:**
   ```bash
   cd infra/environments/dev
   terraform init   # must succeed without edits
   ```
2. **Add resources** by editing `main.tf`.
3. **Enable remote state** when ready:
   - Create the S3 bucket: `aws s3 mb s3://<project>-terraform-state --region <region>`
   - Uncomment the `backend "s3"` block in each environment's `main.tf`
   - Re-run `terraform init` (it will prompt to migrate existing local state)

## Flags Reference

| Flag | Purpose |
|------|---------|
| `--project=<name>` | Project name embedded in template files (default: `basename $PWD`) |
| `--region=<region>` | AWS region for backend blocks and provider (prompted interactively if omitted) |
| `--target=<path>` | Target directory (default: `./infra`) |
| `--dry-run` | Preview only, writes nothing |
| `--force` | Overwrite an existing target directory |
| `--help` / `-h` | Usage |

## Version

1.0.0 (ticket 12.1 — init subcommand)
