用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/tomevault-io/skills-registry --skill terraform命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
| Use when this capability is needed.
> Use when this capability is needed.
Review architecture and API design for the vfs-s3 project. Use when the user mentions @architect, asks to review an issue's design, discuss module boundaries, API shape, or architectural decisions for vfs-s3. Also trigger when the user wants to create an ADR (Architecture Decision Record) or evaluate a technical approach for the project. Intended for dispatch from Codex automation or Claude routines; GitHub trigger phrase: @vfs-s3-bot please prepare design doc Use when this capability is needed.
基于 SOC 职业分类
正在显示 SKILL.md
| name | terraform |
| description | Use when writing, modifying, reviewing, or reading Terraform (HCL) code. |
| metadata | {"author":"FollowTheProcess"} |
Opinionated conventions for safe, minimal, well-typed Terraform modules. Configuration is data; expose the smallest knob surface that supports real use cases. Bad input should fail at parse, not at plan a day later in CI.
RELATED SKILLS: General test discipline (TDD, black-box testing, naming) lives in tests and superpowers:test-driven-development. This skill only adds Terraform-specific test notes.
.tf / .hcl or .tftest.hcl fileterraform fmt -recursive, tflint in the module directory, then terraform validate. All three must pass before ship. Ignore failures in .terraform/modules/ (downloaded deps).required_version and every entry in required_providers. Commit .terraform.lock.hcl.object({...}), list(string), map(...). Never any on a complex input.optional(T, default) for non-required object fields.validation blocks with a concrete condition and a clear error_message.enable_x = true requires x_arn, enforce it with a validation.main.tf over exposing a variable. If you can't name a consumer that would set it differently, don't add the knob.for_each over count. Map keys survive reorders; count indexes don't.moved {} blocks for renames or refactors. Never destroy and recreate just to rename.removed {} blocks when dropping a resource you want to keep. With lifecycle { destroy = false } to only remove from state.import {} blocks to adopt existing infra. Reviewable in a PR, visible in plan. Imperative terraform import is neither.sensitive = true on variables and outputs holding secrets, tokens, ARNs, or PII.data sources for account ID, region, partition. Never hardcode 123456789012 or us-east-1.default_tags) or a single tags module. Don't sprinkle tags = merge(...) across every resource.terraform test is verbose; use it only for what would silently break consumers (required outputs, validation rejection, key resource attributes).try() / coalesce() beat deeply nested ternaries.var.a = true requires var.b = false, that's a footgun, not a feature - constrain it or remove it.depends_on to paper over a missing reference. Reference an attribute of B from A instead.null_resource / local-exec when a provider resource exists.moved, removed, or an import {} block. terraform state rm and terraform import (the CLI) are last resorts, not workflows.count = var.enabled ? 1 : 0 when for_each over a (possibly empty) set reads more clearly and survives future changes.Common excuses for exposing a knob you shouldn't. If you catch yourself reaching for one, hardcode the literal in main.tf instead.
| Excuse | Reality |
|---|---|
| "Flexibility for future deployments" | Future deployments rarely materialize. Add the variable when a real consumer needs it; the change is small. |
| "Different deployments might answer differently" | Name the deployment. If you can't, it's one answer. |
| "It's just one more knob" | One more knob is one more invalid combination and one more thing to validate. |
| "Upstream exposes it, so we should too" | Upstream serves many consumers; this module may serve one operating model. Match yours, not theirs. |
| Need | Pattern |
|---|---|
| Format | terraform fmt -recursive |
| Lint (current module) | tflint (don't --recursive into deps) |
| Validate | terraform validate |
| Run tests | terraform test |
| Rename a resource | moved { from = ... to = ... } |
| Adopt existing infra | import { to = ... id = "..." } |
| Drop without destroy | removed { from = ... lifecycle { destroy = false } } |
| Optional object field | optional(string, null) |
| Reject bad input | validation { condition = ... error_message = ... } |
| Iterate a map | for k, v in var.things : k => ... |
| Sensitive output | output "x" { value = ...; sensitive = true } |
variable "cluster_name" {
type = string
description = "EKS cluster name. <= 100 chars, DNS-1123 compatible."
validation {
condition = length(var.cluster_name) <= 100 && can(regex("^[a-z0-9-]+$", var.cluster_name))
error_message = "cluster_name must be <= 100 lowercase alphanumeric or hyphen characters."
}
}
variable "logging" {
type = object({
enabled = bool
bucket_arn = optional(string)
retention_days = optional(number, 30)
})
validation {
condition = !var.logging.enabled || var.logging.bucket_arn != null
error_message = "logging.bucket_arn is required when logging.enabled = true."
}
}
The second block is the key pattern: cross-field constraints belong at the variable, not in plan-time errors.
Source: FollowTheProcess/dotfiles — distributed by TomeVault.