aws-ami-builder
Build Amazon Machine Images (AMIs) with Packer using the amazon-ebs builder. Use when creating custom AMIs for EC2 instances.
Implement Terraform Provider resources and data sources using the Plugin Framework: CRUD operations, schema design, plan modifiers and validators, not-found handling, waiters for eventually consistent APIs, import support, resource design principles, and required acceptance test
$ npx -y skills add hashicorp/agent-skills --skill provider-resources --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
/provider-resourcesContext preview
The summary Claude sees to decide when to auto-load this skill.
Implement Terraform Provider resources and data sources using the Plugin Framework: CRUD operations, schema design, plan modifiers and validators, not-found handling, waiters for eventually consistent APIs, import support, resource design principles, and required acceptance test
name: provider-resources description: >- Implement Terraform Provider resources and data sources using the Plugin Framework: CRUD operations, schema design, plan modifiers and validators, not-found handling, waiters for eventually consistent APIs, import support, resource design principles, and required acceptance test coverage. Use when adding or changing a resource or data source, deciding whether an API concept should be a resource, wiring a resource to the provider's configured client, handling drift or resource-not-found, or reviewing a resource implementation before submission. license: MPL-2.0 metadata: lifecycle-status: active copyright: Copyright IBM Corp. 2026 version: "0.0.1"
This guide covers developing Terraform Provider resources and data sources. Resources represent infrastructure objects that Terraform manages through Create, Read, Update, and Delete (CRUD) operations.
**Use the [Plugin Framework](https://developer.hashicorp.com/terraform/plugin/framework) for all net-new resources and data sources.** Plugin SDKv2 is for maintaining resources that already exist on it; do not write new code against it. A provider can serve both during migration by muxing ([terraform-plugin-mux](https://developer.hashicorp.com/terraform/plugin/mux)), so adopting the Framework never requires a big-bang rewrite. To tell which mode an existing provider is in, check `go.mod`: `terraform-plugin-mux` present means it serves both SDKv2 and Framework code; only `terraform-plugin-sdk/v2` means SDKv2-only; only `terraform-plugin-framework` means Framework-only. Be cautious about *migrating* existing SDKv2 resources: the Framework distinguishes null from zero values, so naive migrations change behavior for existing users (use the `provider-framework-migration` skill, if available).
**References** (load when needed):
resource; data source semantics; relationship and async-task modeling
patterns, and status/wait function structure
Most providers keep every resource in a single package:
internal/provider/ ├── provider.go # Provider schema + Configure ├── widget_resource.go # Resource implementation ├── widget_resource_test.go # Acceptance tests ├── widget_data_source.go # Data source (if applicable) └── widget_data_source_test.go
Large multi-service providers (e.g. terraform-provider-aws) split into `internal/service/<service>/` packages instead, with an idiomatic file taxonomy worth adopting once a package grows: `consts.go`, `find.go` (finders), `status.go` (status functions), `wait.go` (waiters), `sweep.go` (test sweepers), `exports_test.go`.
Documentation lives in `docs/` and is generated with `tfplugindocs`:
docs/ ├── resources/<name>.md # generated; optional <name>.md.tmpl template └── data-sources/<name>.md
(Hand-written `website/docs/r/*.html.markdown` trees exist in some older, large providers — follow the target repo's convention when editing one.)
A Framework resource is a struct holding the API client, with interface assertions making the implemented behaviors explicit:
var (
_ resource.Resource = &widgetResource{}
_ resource.ResourceWithConfigure = &widgetResource{}
_ resource.ResourceWithImportState = &widgetResource{}
)
func NewWidgetResource() resource.Resource {
return &widgetResource{}
}
type widgetResource struct {
client *examplecloud.Client
}
func (r *widgetResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
resp.TypeName = req.ProviderTypeName + "_widget"
}
// Configure receives the client the provider built in its own Configure.
func (r *widgetResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
if req.ProviderData == nil {
return // provider not yet configured (e.g. validation phase)
}
client, ok := req.ProviderData.(*examplecloud.Client)
if !ok {
resp.Diagnostics.AddError(
"Unexpected Resource Configure Type",
fmt.Sprintf("Expected *examplecloud.Client, got: %T.", req.ProviderData),
)
return
}
r.client = client
}
func (r *widgetResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
resp.Schema = schema.Schema{
Attributes: map[string]schema.Attribute{
"name": schema.StringAttribute{
Required: true,
PlanModifiers: []planmodifier.String{
stringplanmodifier.RequiresReplace(),
},
Validators: []validator.String{
stringvalidator.LengthBetween(1, 255),
},
},
"id": schema.StringAttribute{
Computed: true,
PlanModifiers: []planmodifier.String{
stringplanmodifier.UseStateForUnknown(),
},
},
},
}
}How the provider's `Configure` produces that client — schema, credential resolution, validation — is covered by the `provider-configuration` skill (if available).
**On `id`:** SDKv2 required a magic `id` attribute; the Framework does not. If the API has its own identifier, expose it under its real meaning and do not add a second, redundant `id`. Only keep `id` when it *is* the API's identifier (as above).
func (r *widgetResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
var data widgetResourceModel
resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)
if resp.Diagnostics.HasError() {
return
}
inpHashiCorp Agent Skills for Terraform and Packer. See SKILLS.md for the complete catalog and lifecycle status of each Skill. Legal note: Your use of a third-party MCP client or LLM is subject solely to that provider's terms.
Repo: hashicorp/agent-skills
Build Amazon Machine Images (AMIs) with Packer using the amazon-ebs builder. Use when creating custom AMIs for EC2 instances.
Build Azure managed images and Azure Compute Gallery images with Packer. Use when creating custom images for Azure VMs.
Push Packer build metadata to HCP Packer registry for tracking and managing image lifecycle. Use when integrating Packer builds with HCP Packer for version…
Build Windows images with Packer using WinRM communicator and PowerShell provisioners. Use when creating Windows AMIs, Azure images, or VMware templates.
Azure Verified Modules (AVM) requirements and best practices for developing certified Azure Terraform modules. Use when creating or reviewing Azure modules…
Use this when scaffolding a new Terraform provider with the Plugin Framework: workspace layout, go module setup, provider server main.go, and a provider.go…