Terraform and OpenTofu Guide
agentscope-ai/QwenPaw
Guidance for writing and testing Terraform and OpenTofu code: module structure, naming, test approaches, CI/CD workflows, state handling and security scanning.
Diagnoses and designs safe Terraform releases, provisioners (remote-exec/local-exec/file, cloud-init, Compose, Caddy), multi-environment isolation, and fresh-host bootstrap.
$ npx skills add daymade/claude-code-skills --skill terraform-skill -a claude-codeProject install by default; add -g for ~/.claude/skills/.
$ gh skill install daymade/claude-code-skills terraform-skill --agent claude-codeProject scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).
$ git clone --depth 1 https://github.com/daymade/claude-code-skills.git skills-src && mkdir -p .claude/skills && cp -r skills-src/terraform-skill .claude/skills/terraform-skill && rm -rf skills-srcUse ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.
Claude Code skills documentation · loads skills from .claude/skills/
Install the "terraform-skill" agent skill from https://github.com/daymade/claude-code-skills/tree/main/terraform-skill into .claude/skills/terraform-skill/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "terraform-skill", then confirm the skill loads.Claude Code copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$skill-installer install https://github.com/daymade/claude-code-skills/tree/main/terraform-skillType this inside Codex. $skill-installer <name> installs a curated skill from openai/skills. The installer writes to $CODEX_HOME/skills (default ~/.codex/skills). Restart Codex if the skill does not show up.
$ npx skills add daymade/claude-code-skills --skill terraform-skill -a codexProject install goes to .agents/skills/; add -g for ~/.codex/skills/.
$ gh skill install daymade/claude-code-skills terraform-skill --agent codexProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/daymade/claude-code-skills.git skills-src && mkdir -p .agents/skills && cp -r skills-src/terraform-skill .agents/skills/terraform-skill && rm -rf skills-srcUse ~/.agents/skills/ instead of .agents/skills for a personal install.
Codex skills documentation · loads skills from .agents/skills/
Install the "terraform-skill" agent skill from https://github.com/daymade/claude-code-skills/tree/main/terraform-skill into .agents/skills/terraform-skill/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "terraform-skill", then confirm the skill loads.Codex copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add daymade/claude-code-skills --skill terraform-skill -a cursorProject install goes to .agents/skills/; add -g for ~/.cursor/skills/.
$ gh skill install daymade/claude-code-skills terraform-skill --agent cursorProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/daymade/claude-code-skills.git skills-src && mkdir -p .cursor/skills && cp -r skills-src/terraform-skill .cursor/skills/terraform-skill && rm -rf skills-srcUse ~/.cursor/skills/ instead of .cursor/skills for a personal install.
Cursor skills documentation · loads skills from .cursor/skills/, .agents/skills/, .claude/skills/, .codex/skills/
Install the "terraform-skill" agent skill from https://github.com/daymade/claude-code-skills/tree/main/terraform-skill into .cursor/skills/terraform-skill/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "terraform-skill", then confirm the skill loads.Cursor copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gemini skills install https://github.com/daymade/claude-code-skills.git --path terraform-skill--scope user (default) or --scope workspace; --path is the subfolder of the repo that holds the skill; --consent skips the security confirmation prompt.
$ npx skills add daymade/claude-code-skills --skill terraform-skill -a gemini-cliProject install goes to .agents/skills/; add -g for ~/.gemini/skills/.
$ gh skill install daymade/claude-code-skills terraform-skill --agent gemini-cliProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/daymade/claude-code-skills.git skills-src && mkdir -p .gemini/skills && cp -r skills-src/terraform-skill .gemini/skills/terraform-skill && rm -rf skills-srcUse ~/.gemini/skills/ instead of .gemini/skills for a personal install, then run /skills reload.
Gemini CLI skills documentation · loads skills from .gemini/skills/, .agents/skills/
Install the "terraform-skill" agent skill from https://github.com/daymade/claude-code-skills/tree/main/terraform-skill into .gemini/skills/terraform-skill/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "terraform-skill", then confirm the skill loads.Gemini CLI copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gh skill install daymade/claude-code-skills terraform-skillInstalls for Copilot at project scope by default; add --scope user for a personal install. Preview a skill first with gh skill preview. Needs GitHub CLI 2.90.0 or later (public preview).
$ npx skills add daymade/claude-code-skills --skill terraform-skill -a github-copilotProject install goes to .agents/skills/; add -g for ~/.copilot/skills/.
$ git clone --depth 1 https://github.com/daymade/claude-code-skills.git skills-src && mkdir -p .github/skills && cp -r skills-src/terraform-skill .github/skills/terraform-skill && rm -rf skills-srcUse ~/.copilot/skills/ instead of .github/skills for a personal install. Commit .github/skills so cloud agent and code review can use it.
GitHub Copilot skills documentation · loads skills from .github/skills/, .claude/skills/, .agents/skills/
Install the "terraform-skill" agent skill from https://github.com/daymade/claude-code-skills/tree/main/terraform-skill into .github/skills/terraform-skill/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "terraform-skill", then confirm the skill loads.GitHub Copilot copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add daymade/claude-code-skills --skill terraform-skill -a opencodeOpenCode documents no install command of its own. Project install goes to .agents/skills/; add -g for ~/.config/opencode/skills/.
$ gh skill install daymade/claude-code-skills terraform-skill --agent opencodeProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/daymade/claude-code-skills.git skills-src && mkdir -p .opencode/skills && cp -r skills-src/terraform-skill .opencode/skills/terraform-skill && rm -rf skills-srcUse ~/.config/opencode/skills/ instead of .opencode/skills for a personal install.
OpenCode skills documentation · loads skills from .opencode/skills/, .claude/skills/, .agents/skills/
Install the "terraform-skill" agent skill from https://github.com/daymade/claude-code-skills/tree/main/terraform-skill into .opencode/skills/terraform-skill/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "terraform-skill", then confirm the skill loads.OpenCode copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
terraform-skillDiagnoses and designs safe Terraform releases, provisioners (remote-exec/local-exec/file, cloud-init, Compose, Caddy), multi-environment isolation, and fresh-host bootstrap.
Terraform Skill is an agent skill from daymade/claude-code-skills. Diagnoses and designs safe Terraform releases, provisioners (remote-exec/local-exec/file, cloud-init, Compose, Caddy), multi-environment isolation, and fresh-host bootstrap. Use when writing or reviewing plan/apply wrappers or provisioners; when staging/production config may differ; when a rollout can mutate a shared gateway; or debugging drift, TLS, container restarts, DNS duplication, or snapshot contamination.
Its SKILL.md is about 4.9k tokens, which your agent loads only when the skill is triggered. The skill folder holds 7 other files, including reference files (for example `references/multi-env-isolation.md`, `references/pre-deploy-validation.md` and `references/release-safety-and-environment-parity.md`).
It sits in DevOps & Cloud, covering Infrastructure as code. It works with Terraform. The repository describes itself as: Professional Claude Code skills marketplace featuring production-ready skills for enhanced development workflows. The licence is MIT.
8 steps, taken from the first numbered list in SKILL.md.
Read from SKILL.md and the folder at commit 91bed2b. It shows what the files ask for, not the result of running them.
Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.
From allowed-tools in the SKILL.md frontmatter.
Ships script files (Shell), which the agent can run.
Shell commands in SKILL.md call:
dockerterraformjqsshcurlrsyncapt-getFrom the folder's file list and the shell code blocks in SKILL.md.
Hosts in commands or code, which the agent is likely to contact:
api.cloudflare.comAlso links to:
developers.cloudflare.comFrom URLs in SKILL.md, links to its own repository left out.
Names these keys or tokens, usually read from environment variables:
CLOUDFLARE_API_TOKENFrom names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.
Terraform Skill loads about 4.9k tokens when it runs, and up to ~14k if it reads all its reference files. Until then it costs about 108 tokens; SKILL.md has 2,047 words of instructions outside code blocks.
Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.
The automated check noted patterns worth knowing about, such as sudo or a known installer.
ompose uses an unexpected value despite `.env`precedence than `--env-file` or project `.env`.docker compose --env-file .env config --environmentdocker compose --env-file .env config --format json > compose.rendered.jsonITH_PROXY_MODE docker compose --env-file .env buildAutomated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.
The full file from daymade/claude-code-skills at commit 91bed2b, republished under its MIT licence (© daymade). 2,047 words, ~4,925 tokens.
.claude/skills/terraform-skill/SKILL.md (or your agent's skills folder). This skill also uses 5 other files; get the full folder from GitHub.Prevent a valid-looking Terraform workflow from publishing unvalidated bytes or widening a change's blast radius. Keep the user's business outcome and the actual mutation surface ahead of plan counts, green wrappers, or process completeness.
PLAN_DIGEST, CONFIRM_*, or agent inference does not supply it.
Do not add personal signatures or per-run human approval when the authorized contract is standard CI.Use these incident-derived symptom patterns to choose the next falsifying check. Confirm the current source and runtime before promoting a historical cause into the present diagnosis.
Symptom: Browser ERR_SSL_PROTOCOL_ERROR or similar, terraform plan shows No changes, but the service is actually broken.
Interpretation: No changes is not a live-health check. Terraform refreshes provider-managed
attributes, but a provisioner's remote files and container side effects are not automatically
represented by those attributes. A broken site can follow an authorized apply, another IaC writer,
or an out-of-band change; this symptom alone does not identify which happened. An HTTP redirect or
healthy container does not prove the affected HTTPS route works.
Diagnosis:
.tftpl/.static files are clues to inspect the archive and copy path,
not proof of an out-of-band write: a normal archive extraction can produce them too.rsync --delete can remove another owner's route omitted from its candidate while retaining
syntactically valid configuration. Check the complete existing hostname set, not just the main API.Recovery: Use the repository's canonical release entry and its plan/apply wrapper; where standard CI is required, initiate the supported recovery or rollback through that same CI. Before a replacement, verify the candidate against the current live baseline and name exactly which files/resources may change. A frozen old commit can be reproducible and still roll back a newer route, policy, environment, or image. Restore only the authorized scope; stop if the current writer cannot preserve other owners' files. Do not use a broad replacement followed by a second sync as the default repair.
A saved plan freezes Terraform's planned values, not arbitrary files or external downloads read by its provisioners at apply time. Check that the actual implementation consumes the validated immutable artifact before claiming recovery will publish those bytes. After the authorized apply, independently verify the affected user path and the previously working routes. Live hash checks can detect drift; they do not by themselves establish its writer or prevent deletion.
port is already allocatedSymptom: Compose deploy passes staging verification, then the production apply dies at docker compose up with Bind for 127.0.0.1:<port> failed: port is already allocated.
Root cause: Staging/production parity covers configuration, not host port allocation. A port that is free on staging can already be occupied by another service on the production host. A tainted null_resource is left behind, so the retry must go through the replace flow (CONFIRM_REPLACE), not a plain re-apply.
Diagnosis:
ssh root@<target-host> 'ss -ltnp | grep <port>' # find the real occupant
docker ps --format "{{.Names}} {{.Ports}}" | grep <port>Prevention: Before binding a host port in a module, check the target host for the exact bind at design time — never infer freeness from staging. Prefer uncommon high ports, record the allocation in the module comment and the deploy doc, and when a container needs a host-local probe target remember 127.0.0.1 inside a container is the container itself: host-local targets belong to host-level probes (systemd scripts), not containerized monitors.
docker: not found in remote-execcloud-init still installing Docker when provisioner SSHs in.
provisioner "remote-exec" {
inline = [
"cloud-init status --wait",
"command -v docker >/dev/null || { echo 'FATAL: Docker not ready'; exit 1; }",
]
}rsync: connection unexpectedly closed in local-execDo not infer a universal Terraform limitation from this symptom. A second SSH client can lose to the
target's connection budget, SSH policy, or a competing deploy. Keep local-exec local: package an
immutable artifact there, then use a Terraform-managed upload or a purpose-built deploy system. Give
every apply a unique remote staging path; never share /tmp/src.tar.gz across concurrent applies.
provisioner "local-exec" {
command = "tar czf /tmp/src-${self.id}.tar.gz --exclude=node_modules --exclude=.git -C ${path.module}/../../.. myproject"
}
provisioner "file" {
source = "/tmp/src-${self.id}.tar.gz"
destination = "/tmp/src-${self.id}.tar.gz"
}
provisioner "remote-exec" {
inline = ["tar xzf /tmp/src-${self.id}.tar.gz -C /data/ && rm -f /tmp/src-${self.id}.tar.gz"]
}macOS BSD tar: --exclude must come BEFORE the source argument.
cloud-init status shows "running" foreverapt-get -y does not suppress debconf dialogs. Packages like iptables-persistent block on TTY prompts.
- |
echo iptables-persistent iptables-persistent/autosave_v4 boolean true | debconf-set-selections
echo iptables-persistent iptables-persistent/autosave_v6 boolean true | debconf-set-selections
DEBIAN_FRONTEND=noninteractive apt-get install -y iptables-persistentKnown offenders: iptables-persistent, postfix, mysql-server, wireshark-common.
EACCES: permission denied in container logs, container RestartingHost volume dirs are root-owned; container runs as non-root (uid 1001). Fix before docker compose up:
mkdir -p /data/myapp/data /data/myapp/logs
chown -R 1001:1001 /data/myapp/data /data/myapp/logsFind UID: grep adduser.*-u or USER in Dockerfile.
Keep fail-fast behavior; attach diagnostics to failure instead of disabling set -e. Otherwise an
early failed command can be overwritten by a later green health check.
provisioner "remote-exec" {
inline = [
"set -eu",
"trap 'rc=$?; if [ $rc -ne 0 ]; then docker logs myapp --tail 20 2>&1 || true; docker ps --format \\\"table {{.Names}}\\\\t{{.Status}}\\\" || true; fi; exit $rc' EXIT",
"docker compose up -d",
"sleep 15",
"docker ps --filter name=myapp --format '{{.Status}}' | grep -q healthy || exit 1",
]
}Failed to save state / Failed to persist state to backend after applyThe apply ran and only the final backend upload failed (a timeout to the state bucket is typical).
First confirm that in the apply log: every resource reports Creation complete,
Modifications complete or Destruction complete, and the only errors are these two. Then every side effect already
happened — provisioners ran, remote writes landed, containers were recreated — but the backend still
holds the previous state, and Terraform wrote the new one to errored.tfstate in the directory it
ran in (for a wrapper, its root module directory, not your shell's). Do not re-run apply: it would
work from the stale state, which Terraform itself warns forks the state, and resources the failed
run already created or replaced would be created or replaced again.
Run the recovery from that directory, through the repository's wrapper when it passes state
subcommands through (operating contract 1); otherwise in exactly the environment the wrapper sets
up, so the same backend and credentials are used. Keep the pulled copies out of the repository:
terraform state pull > "${TMPDIR:-/tmp}/remote.json"
jq '{file: input_filename, lineage, serial}' "${TMPDIR:-/tmp}/remote.json" errored.tfstate
# expect: identical lineage, and the remote serial lower than errored.tfstate's
terraform state push errored.tfstate
terraform state pull | jq '{lineage, serial}'
# expect: serial higher than the remote's before the push (it need not equal
# errored.tfstate's; the backend may increment it). Then check the resources the
# apply created or replaced: `terraform state show <address>` carries the IDs in the apply log.state push refuses an unrelated lineage, a newer remote serial, and an equal serial with different
content (observed on Terraform 1.5.7 with a local backend). A refusal means the remote no longer
matches this errored.tfstate — another writer changed it, the file is left over from an older run,
or you are pointed at a different workspace or backend: stop and reconcile. Never add -force; it overwrites whatever the
remote holds. If the push fails on the same transport error as the apply, retry it later;
errored.tfstate stays usable until the remote serial moves. After a successful push, move
errored.tfstate out of the working directory (to scratch space) so it is not later read as live
state; it and the pulled copies hold the full state, secrets included, so delete them once the
read-back passes. Then read the wrapper's recipe and run by hand every step that follows its apply command —
persisting the new setting, post-apply verification. The wrapper's failure exit hides that the
remote change is already live.
Restarting — database tables missingDB migrations not in provisioner. PostgreSQL docker-entrypoint-initdb.d only runs on empty data dir. Explicitly create DB + run migrations:
# After postgres healthy:
docker exec pg psql -U postgres -tc "SELECT 1 FROM pg_database WHERE datname='mydb'" | grep -q 1 \
|| docker exec pg psql -U postgres -c "CREATE DATABASE mydb;"
# Idempotent migrations:
for f in migrations/*.sql; do
VER=$(basename $f)
APPLIED=$($PSQL -tAc "SELECT 1 FROM schema_migrations WHERE version='$VER'" | tr -d ' ')
[ "$APPLIED" = "1" ] && continue
{ echo 'BEGIN;'; cat $f; echo 'COMMIT;'; } | $PSQL
$PSQL -tAc "INSERT INTO schema_migrations(version) VALUES ('$VER') ON CONFLICT DO NOTHING"
done.envCompose interpolation gives the invoking shell higher precedence than --env-file or project .env.
An old exported value can therefore override the reviewed environment silently. Inspect what Compose
actually used; unset ambient overrides when the env file is meant to be authoritative.
# Inspect interpolation inputs and the rendered model.
docker compose --env-file .env config --environment
docker compose --env-file .env config --format json > compose.rendered.json
# Make the reviewed env file authoritative for this key.
env -u DOCKER_WITH_PROXY_MODE docker compose --env-file .env buildInvalid format for Authorization headerCaddy's Cloudflare DNS module expects a scoped API Token through Bearer authentication. Do not infer credential type, validity, or permissions from length/prefix alone. Verify the token with Cloudflare's official endpoint, then exercise the exact zone operation or provider path required by the release.
curl -fsS https://api.cloudflare.com/client/v4/user/tokens/verify \
-H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
| jq -e '.success == true and .result.status == "active"' >/dev/nullIf the credential is absent or wrong, create a least-privilege API Token through Cloudflare's current dashboard/API flow and grant only the zones/operations the provider needs. Follow the official creation contract rather than copying permission-group IDs that may drift: https://developers.cloudflare.com/fundamentals/api/get-started/create-token/.
Caddyfile or compose has literal domain names. Staging Caddy loads production config, tries to get certs for domains it doesn't own → ACME fails.
Caddyfile: Use {$VAR} — Caddy evaluates env vars at startup.
# WRONG
example.com { tls { dns cloudflare {env.CLOUDFLARE_API_TOKEN} } }
# RIGHT
{$LOBEHUB_DOMAIN} { tls { dns cloudflare {env.CLOUDFLARE_API_TOKEN} } }Compose: Use ${VAR:?required} — fail-fast if unset or empty.
# WRONG
- APP_URL=https://example.com
# RIGHT
- APP_URL=${APP_URL:?APP_URL is required}Pass the env var to the gateway container so Caddy can read it:
environment:
- LOBEHUB_DOMAIN=${LOBEHUB_DOMAIN:?LOBEHUB_DOMAIN is required}
- CLOUDFLARE_API_TOKEN=${CLOUDFLARE_API_TOKEN:?required for DNS-01 TLS}Do not stop at this local assertion. Put all runtime-required keys in one schema, require the same set
from every environment file, render the exact Compose service environment, and run the exact deployed
Caddy image with that full environment before mutating live files. Caddy {$VAR} expansion can become
an empty token before parsing; a Caddyfile default is not an environment-completeness check.
Social sign in failedCasdoor init_data.json contains hardcoded redirect URIs. --createDatabase=true only applies init_data on first-ever DB creation — not on restarts. Fix via SQL in provisioner:
# Replace production domain with staging in existing Casdoor DB
$PSQL -c "UPDATE application SET redirect_uris = REPLACE(redirect_uris,
'example.com', 'staging.example.com')
WHERE name='lobechat'
AND redirect_uris LIKE '%example.com%'
AND redirect_uris NOT LIKE '%staging.example.com%';"Also check AUTH_CASDOOR_ISSUER — it must match the Casdoor subdomain (auth.staging.example.com), not the app root domain.
Before creating a second environment, grep .tf files for hardcoded names. See references/multi-env-isolation.md for the complete matrix.
Environment isolation does not mean configuration-contract drift. Keep one required-key manifest and the same validation path for every environment. Staging and production may use different domains, credentials, instance sizes, and feature values; they must not disagree about whether a runtime key is required, optional, allowed-empty, or silently defaulted.
Will fail on apply (globally unique):
| Resource | Scope | Fix |
|---|---|---|
| SSH key pair | Region | "${env}-deploy" |
| SLS log project | Account | "${env}-logs" |
| CloudMonitor contact | Account | "${env}-ops" |
DNS duplication trap: Two environments creating A records for the same name in the same Cloudflare zone → two independent record IDs → DNS round-robin → ~50% traffic to wrong instance. Fix: use subdomain isolation (staging.example.com) or separate zones. Remember to create DNS records for ALL subdomains Caddy serves (e.g., auth.staging, minio.staging).
Snapshot cross-contamination: Unfiltered data "alicloud_ecs_snapshots" returns ALL account snapshots. New env inherits old 100GB snapshot, fails creating 40GB disk. Gate with variable:
locals {
latest_snapshot_id = var.enable_snapshot_recovery && length(local.available_snapshots) > 0
? local.available_snapshots[0].snapshot_id : null
}Do NOT add count to the data source — changes its state address, causes drift.
Before approval or mutation, read and execute pre-deploy-validation.md. It owns the publisher gates, validation phases, fresh-plan authorization and target-bound promotion evidence.
Fresh disks expose every implicit dependency. See references/zero-to-deploy-checklist.md.
Before an authorized service pause or first live write, also use pre-deploy-validation.md for credential capability and publisher preparation. The fresh-host checklist owns bootstrap dependencies, ordering and memory.
© daymade, MIT. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file
SKILL.md and 5 other files (references) in terraform-skill of daymade/claude-code-skills.
Open the folder on GitHubat commit 91bed2b
Terraform Skill next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.
| Skill | Stars | Used in | Tokens | Auto-check | Licence | Repo updated |
|---|---|---|---|---|---|---|
| Terraform Skill this skilldaymade/claude-code-skills | 1.4k | — | ~4.9k | Automated safety check: Notes | MIT | |
| Terraform and OpenTofu Guideagentscope-ai/QwenPaw | 35k | 6 repos | ~4.2k | Automated safety check: Pass | Apache-2.0 | |
| Terraform Skillantonbabenko/terraform-skill | 2.4k | 1 repos | ~5.1k | Automated safety check: Pass | Apache-2.0 | |
| Review Docshashicorp/terraform-provider-aws | 11k | — | ~1.3k | Automated safety check: Pass | MPL-2.0 | |
| Senior DevOps Toolkitmaslennikov-ig/claude-code-orchestrator-kit | 260 | 6 repos | ~1.1k | Automated safety check: Notes | Custom licence | |
| Cloudflarehodgef/apiker | 127 | 7 repos | ~2.2k | Automated safety check: Pass | MIT |
agentscope-ai/QwenPaw
Guidance for writing and testing Terraform and OpenTofu code: module structure, naming, test approaches, CI/CD workflows, state handling and security scanning.
antonbabenko/terraform-skill
A skill your agent uses when writing, reviewing, or debugging Terraform/OpenTofu modules, tests, CI, scans, or state ops - diagnoses failure mode (identity churn, secrets, blast radius, CI drift…
hashicorp/terraform-provider-aws
Review a Terraform AWS Provider PR's end-user documentation (website/docs//.markdown): whether docs are needed, description openings, argument/attribute style, section structure, tags wording, code…
maslennikov-ig/claude-code-orchestrator-kit
Comprehensive DevOps skill for CI/CD, infrastructure automation, containerization, and cloud platforms (AWS, GCP, Azure). Includes pipeline setup…
hodgef/apiker
Comprehensive Cloudflare platform skill covering Workers, Pages, storage (KV, D1, R2), AI (Workers AI, Vectorize, Agents SDK), feature flags (Flagship), networking (Tunnel, Spectrum), security (WAF…
patrickchugh/terravision
Draw cloud architecture diagrams for AWS, Azure or GCP with the official provider icon sets, using TerraVision.
daymade/claude-code-skills
This skill should be used when comparing two videos to analyze compression results or quality differences.
daymade/claude-code-skills
Generates professional animated CLI demos as GIFs using VHS terminal recordings.
daymade/claude-code-skills
Converts DOCX/PDF/PPTX and saved HTML/HTM to high-quality Markdown with automatic post-processing.
daymade/claude-code-skills
Generates several distinct, clickable HTML interaction prototypes for one product surface into a Design Board and collects selection/remix feedback before implementation.
daymade/claude-code-skills
Diagnoses and repairs repository setup and guarded Git workflows for Claude Code or Codex — environment repair, startup sync, hook auditing, collaborator handoff.
daymade/claude-code-skills
Pulls Bigdata.com (RavenPack) financial and news data via the official bigdata-client SDK and /v1/ REST endpoints — structured financials, prices, analyst estimates, entity-sentiment series…
Works with
Categories
Diagnoses and designs safe Terraform releases, provisioners (remote-exec/local-exec/file, cloud-init, Compose, Caddy), multi-environment isolation, and fresh-host bootstrap. Terraform Skill is an agent skill from daymade/claude-code-skills. Diagnoses and designs safe Terraform releases, provisioners (remote-exec/local-exec/file, cloud-init, Compose, Caddy), multi-environment isolation, and fresh-host bootstrap.
Terraform Skill fits situations like: reviewing plan/apply wrappers; staging/production config may differ; A rollout can mutate a shared gateway; debugging drift.
Run `npx skills add daymade/claude-code-skills --skill terraform-skill -a claude-code`. Or copy the skill folder (terraform-skill in daymade/claude-code-skills) into .claude/skills/terraform-skill in your project. Claude Code loads it when a task matches its description.
Run `npx skills add daymade/claude-code-skills --skill terraform-skill -a codex`. Or copy the skill folder (terraform-skill in daymade/claude-code-skills) into .agents/skills/terraform-skill in your project. Codex loads it when a task matches its description.
Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add daymade/claude-code-skills --skill terraform-skill -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/terraform-skill, .gemini/skills/terraform-skill, .github/skills/terraform-skill and .opencode/skills/terraform-skill in your project.
Going by SKILL.md and its folder, Terraform Skill needs a shell for the scripts in its folder, the command-line tools its instructions call (docker, terraform, jq, ssh, curl and rsync) and credentials named CLOUDFLARE_API_TOKEN. Our summary lists: A Bash shell; Docker.
SKILL.md names 2 domains. In commands or code: api.cloudflare.com; the agent is likely to contact it when it follows the instructions. As links in the text: developers.cloudflare.com. This is read from the text; nothing was executed.
Our automated static check of SKILL.md found notes only (mentions a .env file), nothing it rates as a warning. It is not a guarantee. Review the folder before installing.
Terraform Skill is published under the MIT licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.
About 4.9k tokens (SKILL.md is roughly 20k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full. Its references folder adds about 9k tokens, read only when the agent opens those files.
Skills that share tags, products or a category with Terraform Skill: Terraform and OpenTofu Guide (agentscope-ai/QwenPaw, 35k stars), Terraform Skill (antonbabenko/terraform-skill, 2.4k stars), Review Docs (hashicorp/terraform-provider-aws, 11k stars) and Senior DevOps Toolkit (maslennikov-ig/claude-code-orchestrator-kit, 260 stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.
daymade (a GitHub user) maintains it in daymade/claude-code-skills, which has 1,444 GitHub stars. The repository holds 103 skills in this directory. The repository was last updated on October 8, 2026.
Source: daymade/claude-code-skills on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.