Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ name: terraform-search-import
description: Discover existing cloud resources using Terraform Search queries and bulk import them into Terraform management. Use when bringing unmanaged infrastructure under Terraform control, auditing cloud resources, or migrating to IaC.
metadata:
copyright: Copyright IBM Corp. 2026
version: "0.1.0"
version: "0.2.0"
compatibility: Requires Terraform >= 1.14 and providers with list resource support (always use latest provider version)
---

Expand Down Expand Up @@ -259,9 +259,13 @@ import {
Generated configuration includes all attributes. Clean up by:

1. Remove computed/read-only attributes
2. Replace hardcoded values with variables
3. Add proper resource naming
4. Organize into appropriate files
1. Replace hardcoded values with variables
1. Remove computed sensitive values
1. Remove non-computed sensitive values. If the provider still requires one of the removed arguments, use a write-only placeholder instead. If that write-only attribute requires a paired non-write-only attribute, ignore changes only to the paired non-write-only attribute, not to the write-only attribute itself.
1. Remove top-level `timeout` blocks from all resources.
1. Run `terraform validate` and resolve conflicting generated arguments.
1. Add proper resource naming
1. Organize into appropriate files

```hcl
# Before: generated
Expand All @@ -273,6 +277,12 @@ resource "aws_instance" "all_0" {
# ... many more attributes
}

resource "aws_ssm_parameter" "all_0" {
type = "SecureString"
name = "AccessCode"
value = "secret" # Remove - sensitive
}

# After: cleaned
resource "aws_instance" "web_server" {
ami = var.ami_id
Expand All @@ -284,6 +294,17 @@ resource "aws_instance" "web_server" {
Environment = var.environment
}
}

resource "aws_ssm_parameter" "access_code" {
type = "SecureString"
name = "AccessCode"
value_wo = "__imported__"
value_wo_version = 1

lifecycle {
ignore_changes = [value_wo_version]
}
}
```

## Import by Identity
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
---
name: terraform-tidy-before-import
description: Prepares Terraform code for safe and correct import. Resolves validation errors, sensitive attributes, and computed attributes. De-duplicates literal values. Use this before committing generated Terraform code to version control and before importing resources into Terraform.
license: MPL-2.0
metadata:
copyright: Copyright IBM Corp. 2026
version: "0.0.1"
---
# Tidy generated Terraform code

Generated Terraform configuration includes all resource attributes. For
correctness, reliability, and security, we tidy Terraform code before we commit
it to version control and before we run `terraform apply`.

The user may specify a priority of either speed or thoroughness. Default to
thoroughness. If the user prioritizes speed, then skip all schema-dependent
work and simply use `terraform validate` as a feedback loop to converge on a
validatable configuration.

When editing Terraform `resource` blocks, honor the Terraform resource
configuration model. Preserve any Terraform-supported built-in resource
argument or nested block that is already present, including `count`,
`depends_on`, `for_each`, `provider`, `lifecycle`, `connection`, and
`provisioner`, along with supported nested arguments and blocks inside them.
Never remove these Terraform language arguments or blocks during cleanup.

When editing Terraform `import` blocks, honor the Terraform import
configuration model. If an existing `import` block passes `terraform validate`,
it does not need to be edited. Preserve all Terraform-supported `import` block
arguments, including `to`, `id`, `identity`, `for_each`, and `provider`. Never
remove a valid `import` block or remove the `provider` argument from one.

<parse_terraform_code_using_python_hcl2_and_hq>
Prioritize correctness when parsing Terraform code. To do so, use the
python-hcl2 module in a virtualenv. This module includes the hq command line
tool. Examples:

* Convert to JSON: `hq '*' <input file> --json`
* Identity resource blocks with top-level timeouts: `hq 'resource~[select(.timeouts)] | .labels' <input file>`
* Identity null-valued attributes: `hq '*..attribute:*[select(.value == null)]' <input file>`

Use generic tools such as grep, awk, and sed only as a last resort when parsing Terraform code.
</parse_terraform_code_using_python_hcl2_and_hq>


1. Temporarily rename the source file to a .tf.bak extension so that
`terraform` commands do not read it.
1. Start a non-blocking background task in a temporary directory to build
resource schema lookup tables, as detailed in
[resource-schema-lookup-tables.md](references/resource-schema-lookup-tables.md).
1. Run `terraform validate`. Resolve conflicting generated provider arguments
without removing Terraform-supported built-in resource arguments or blocks.
Resolve all other validation errors.
1. Replace literal values with variables for values that are used 3 or more
times
1. Remove top-level provider-defined `timeouts` blocks from all resources.
1. Wait for the background schema-analysis task to finish, then use its lookup
tables for the remaining schema-dependent cleanup steps.
1. Remove provider-defined attributes that are `computed` and not `optional` by
using the computed-attributes lookup table for each resource type. Preserve
provider-defined attributes that are both `computed` and `optional`, unless
the configuration explicitly sets them to `null`; in that case, remove the
null-valued argument.
1. Remove non-computed sensitive provider-defined attributes. If the provider
requires one of the removed arguments, try to use an equivalent
write-only attribute, such as the `value_wo` and `value_wo_version` pair for
`value`. If the write-only attribute requires a non-write-only
paired attribute, use the `lifecycle` meta-argument to ignore changes only
to that paired non-write-only attribute, e.g. `value_wo_version`.
1. Run `terraform validate` as the final validation step. Make a best effort to
resolve errors before continuing.
1. On completion, restore the original source file name

```hcl
# Before: generated
resource "aws_instance" "all_0" {
ami = "ami-0c55b159cbfafe1f0"
instance_type = "t2.micro"
arn = "arn:aws:ec2:..." # Remove - computed
id = "i-0abc123" # Remove - computed
# ... many more attributes
}

resource "aws_ssm_parameter" "all_0" {
type = "SecureString"
name = "AccessCode"
value = "secret" # Remove - sensitive
}

# After: tidied
resource "aws_instance" "all_0" {
ami = var.ami_id
instance_type = var.instance_type
subnet_id = var.subnet_id
}

resource "aws_ssm_parameter" "access_code" {
type = "SecureString"
name = "AccessCode"
value_wo = "__imported__"
value_wo_version = 1

lifecycle {
ignore_changes = [value_wo_version]
}
}
```
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can't seem to find a schema for this filetype?
I looked at the docs of tessl, which is used in a Github Action of this repo, and I can only find different files: https://docs.tessl.io/evaluate/evaluating-your-codebase#file-formats

How to run this eval?

Copy link
Copy Markdown
Collaborator Author

@bbasata bbasata Apr 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

image

Yes, spot-on observation! 😃 I took a speculative leap in this pull request.

For the eval, I chose the format described on agentskills.io. I ran it locally (WORKS ON MY MACHINE 😃) with the skill-creator skill from anthropics/skills.

It would be Really Useful to include some output, would it not? 🙃

Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{
"skill_name": "terraform-tidy-before-import",
"evals": [
{
"id": 1,
"prompt": "Tidy the generated Terraform in aws_thorough_before_cleanup.tf so it is ready for import and safe to commit. Use the default thoroughness level, keep valid import blocks intact, preserve Terraform language meta-arguments and nested language blocks, and organize the finished configuration into appropriate Terraform files before you wrap up. Keep terraform.tf in any terraform working directories for base provider configuration. Make a best effort: if the final file does not validate or does not meet all criteria, the computer should still present it as output for evaluation.",
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How much instruction normally goes into the prompt vs into the skill?
How does it perform if this was just Tidy the generated Terraform config in aws_thorough_before_cleanup.tf?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right on, super helpful feedback. I think this prompt needs to be lighter. Agent fatigue. Time to edit.

"expected_output": "A cleaned AWS configuration as close to aws_thorough_after_cleanup.tf as possible. Expect absence of provider-defined computed attributes and top-level timeout blocks while preserving valid import blocks, lifecycle/meta-arguments, and connection timeouts.",
"files": [
"evals/files/aws_thorough_before_cleanup.tf",
"evals/files/aws_thorough_after_cleanup.tf",
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As Anthropic denotes these files as input files, do we need to somehow assert that the agent (while using the skill) does not read this file? Else it might be relatively easy to get to this result 🥷

"evals/files/terraform.tf"
],
"expectations": [
"terraform validate exits with code 0 on the output .tf files",
"All 7 import blocks from the source are present across the output files",
"Every import block retains its provider argument",
"No resource block contains a top-level timeouts {} block",
"aws_ssm_parameter resources have no value = null attribute (sensitive attribute removed)",
"aws_ssm_parameter resources have value_wo set to a non-null string",
"Each aws_ssm_parameter resource has a lifecycle block with ignore_changes = [value_wo_version]",
"aws_ssm_parameter resources retain the arn attribute (it is computed+optional per schema, so must be preserved not removed)",
"At least 2 Terraform variables are defined for values used 3 or more times",
"aws_instance resources retain the tags_all attribute (it is computed+optional per schema and must be preserved)"
]
}
]
}
Loading