Go-based interactive CLI for converting existing cloud resources to Terraform/OpenTofu configuration using AI.
Looking to codify at scale? If you need to codify cloud resources across your organization with minimal setup — plus governance, drift detection, and module management — check out
terraclaw is a BubbleTea-powered terminal UI tool that:
- Discovers your existing cloud resources via Steampipe (AWS and Azure)
- Lets you select the resources you want to import interactively
- Matches your own Terraform modules from git repos or local paths, scoring them by fit
- Generates Terraform HCL using OpenCode (AI coding agent), preferring your modules over public registry modules
- Runs
terraform importto create state files for the selected resources
Every generation call is guarded by the TerraShark failure-mode prompt suite. The references (workflow, coding standards, do/don't patterns, identity-churn rules, secret-exposure rules, migration playbooks, good/bad example banks, module architecture) are:
- Embedded into the binary via
internal/terrasharkand injected as a<terrashark_guardrails>block into both Stage 1 (blueprint design) and Stage 2 (HCL emission) prompts. - Also registered as an OpenCode skill at
.agents/skills/terrashark/, so the agent can load full references on demand.
This gives the model an explicit diagnostic frame (prefer pinned trusted modules, for_each with business keys, no invented attribute names, no plaintext secrets, moved blocks on renames) before it emits a single line of HCL — independent of the underlying model or provider.
- Go 1.25+
- Steampipe with at least one cloud plugin installed
- Terraform (for the import step)
- OpenCode (
brew install opencodeornpm install -g opencode-ai) - An AI provider configured in OpenCode (e.g. GitHub Copilot, OpenAI) via
opencode providers login
git clone https://github.com/arunim2405/terraclaw.git
cd terraclaw
make buildOr install directly:
go install .terraclaw reads configuration from environment variables or a .env file in the working directory. The AI provider is configured through OpenCode's own auth system, not via terraclaw env vars.
| Variable | Default | Description |
|---|---|---|
STEAMPIPE_HOST |
localhost |
Steampipe PostgreSQL host |
STEAMPIPE_PORT |
9193 |
Steampipe PostgreSQL port |
STEAMPIPE_DB |
steampipe |
Steampipe database name |
STEAMPIPE_USER |
steampipe |
Steampipe database user |
STEAMPIPE_PASSWORD |
(empty) | Steampipe database password |
OPENCODE_PORT |
4096 |
Port for the OpenCode headless server |
TERRAFORM_BIN |
terraform |
Path to the terraform binary |
OUTPUT_DIR |
./output |
Directory to write generated .tf files |
CACHE_DIR |
~/.cache/terraclaw |
Directory for SQLite scan cache |
CACHE_TTL |
1h |
How long cached scans remain valid |
NO_CACHE |
false |
Skip the resource cache entirely |
DEBUG |
false |
Enable debug logging to file |
DEBUG_LOG_FILE |
terraclaw.log |
Path for debug log output |
terraclaw delegates all LLM interaction to OpenCode, which manages its own provider authentication. To get started:
# Log in to a provider (e.g. GitHub Copilot, OpenAI)
opencode providers login
# Verify your credentials
opencode providers listThe project includes an opencode.json that configures the model, permissions, and Terraform skills for headless operation. OpenCode will automatically pick it up from the project directory.
- Start Steampipe with your desired cloud plugin:
steampipe plugin install aws
steampipe service start- Run
terraclaw:
terraclaw- Follow the interactive prompts:
- Select a cloud provider (Steampipe schema)
- Select a resource type (table)
- Toggle individual resources with Space, confirm with Enter
- Review the generated Terraform code
- Confirm running
terraform import
Generate Terraform directly by specifying resource ARNs or Azure resource IDs:
# AWS
terraclaw generate --resources arn:aws:s3:::my-bucket --schema aws
# Azure
terraclaw generate --resources /subscriptions/xxx/resourceGroups/rg/providers/Microsoft.Compute/virtualMachines/vm1 --schema azure
# With user modules (auto-select all matching modules)
terraclaw generate --resources arn:aws:s3:::my-bucket --schema aws --auto-modulesRegister your organization's Terraform modules so terraclaw uses them instead of public registry modules during code generation.
# From a git repository (Terraform source format)
terraclaw add-module "git::https://github.com/acme/tf-modules.git//modules/vpc?ref=v2.0"
# From a git repo via SSH
terraclaw add-module "git@github.com:acme/tf-modules.git//modules/vpc?ref=v2.0"
# From a local directory
terraclaw add-module ./my-modules/vpc
# With a custom name (overrides auto-derived name)
terraclaw add-module --name "custom-vpc" "git::https://github.com/acme/tf-modules.git//modules/vpc?ref=v2.0"When you add a module, terraclaw automatically:
- Clones the repository (for git sources) or reads the local directory
- Parses all
.tffiles to extract resource types, variables, and outputs - Detects the cloud provider (AWS, Azure) from resource type prefixes
- Reads the README for a description
- Stores the metadata in a local SQLite database (
~/.cache/terraclaw/modules.db)
# List all registered modules
terraclaw list-modules
# Show full metadata (variables, outputs, resource types)
terraclaw inspect-module vpc
# Remove a module
terraclaw remove-module vpcInteractive mode (TUI): After you select resources and confirm generation, terraclaw checks your registered modules for matches. If any modules manage the same resource types you selected, a module selection screen appears showing each module's fit score (0-100%). Modules scoring 60%+ are pre-selected. Toggle with Space, confirm with Enter.
Non-interactive mode: Use --use-modules or --auto-modules:
# Auto-select all matching modules
terraclaw generate --resources arn:aws:... --schema aws --auto-modules
# Use modules (pre-selects those with >= 60% fit)
terraclaw generate --resources arn:aws:... --schema aws --use-modulesThe fit score tells you how well a module matches your selected resources:
| Component | Weight | What it measures |
|---|---|---|
| Coverage | 50% | Fraction of your selected resource types the module handles |
| Specificity | 30% | How focused the module is (penalizes modules that drag in many unrelated resources) |
| Variable Readiness | 20% | Fraction of required variables that have defaults or match resource properties |
Selected modules are injected into the AI prompt as hard constraints, taking priority over public registry modules (e.g. terraform-aws-modules).
Validate local dependencies and configuration:
terraclaw doctorThis checks that steampipe, terraform, and opencode are available on PATH, the output directory is writable, and Steampipe is reachable.
Global flags:
--output-dir string Directory to write generated Terraform files (default "./output")
--terraform-bin string Path to the terraform binary (default "terraform")
--debug Enable debug logging to file (see DEBUG_LOG_FILE)
--no-cache Skip the resource cache and always rescan from Steampipe
Generate flags:
-r, --resources string Comma-separated resource ARNs or Azure resource IDs (required)
--schema string Steampipe schema (auto-detected from resource IDs if omitted)
--use-modules Use registered user modules (matched by resource type)
--auto-modules Auto-select all matching user modules (implies --use-modules)
Add-module flags:
--name string Override the auto-derived module name
A Docker image bundles all dependencies (Steampipe, Terraform, OpenCode, AWS CLI) for self-contained runs.
make docker-build- Create your env file from the sample:
make env-sample
# Edit .docker.env with your credentials- Run the container:
make docker-runOr extract output artifacts to a local directory:
make docker-run-artifactsThe .sample.docker.env documents all required and optional environment variables for Docker runs. Key variables:
| Variable | Required | Description |
|---|---|---|
TERRACLAW_CMD_B64 |
Yes | Base64-encoded terraclaw CLI command |
OPENCLAW_CREDS_B64 |
Yes | Base64-encoded OpenCode auth.json content |
AWS_ACCESS_KEY_ID |
No | AWS credentials (auto-detected by Steampipe) |
AWS_SECRET_ACCESS_KEY |
No | AWS secret key |
AWS_REGION |
No | AWS region |
LOCAL_ARTIFACTS_DIR |
No | Bind-mount path to copy the output zip into |
STEAMPIPE_PLUGINS |
No | Comma-separated extra plugins (e.g. azure,gcp) |
This variable contains your OpenCode auth credentials (provider tokens) base64-encoded so they can be injected into the container at runtime. The credentials live in OpenCode's local auth file on your machine.
- First, make sure you have at least one provider logged in locally:
opencode providers login # follow the OAuth flow for GitHub Copilot, OpenAI, etc.
opencode providers list # verify credentials are saved- Base64-encode the auth file:
# macOS
cat ~/.local/share/opencode/auth.json | base64
# Linux
cat ~/.local/share/opencode/auth.json | base64 -w 0- Paste the output into your
.docker.env:
OPENCLAW_CREDS_B64=eyJnaXRodWItY29waWxvdCI6ey...Similarly, for TERRACLAW_CMD_B64:
echo "terraclaw generate --resources arn:aws:s3:::my-bucket --schema aws" | base64The entrypoint (docker/entrypoint.sh) runs these steps in order:
- Writes OpenCode auth credentials from
OPENCLAW_CREDS_B64 - Installs Steampipe plugins and starts the Steampipe service
- Starts
opencode servein the background - Runs the decoded terraclaw command
- Zips the output and optionally copies it to
LOCAL_ARTIFACTS_DIR - Cleans up OpenCode and Steampipe processes
Run make help to see all available targets:
build Build the binary for the current platform
build-linux Cross-compile for linux/amd64
run Build and run with sample args (override with ARGS=)
test Run all tests
lint Run go vet
clean Remove build artifacts
docker-build Build the Docker image
docker-run Run the Docker container with .docker.env
docker-run-artifacts Run and extract output to ./artifacts
docker-shell Open a shell in the Docker container
env-sample Copy sample env to .docker.env
help Show this help
terraclaw/
├── main.go Entry point
├── cmd/
│ ├── root.go Cobra CLI setup & TUI entry
│ ├── generate.go Non-interactive generate command
│ ├── module.go Module management commands (add, list, remove, inspect)
│ ├── doctor.go Dependency checker command
│ └── debug.go Debug utilities
├── config/config.go Configuration loading
├── opencode.json OpenCode project config (model, permissions, plugins)
├── internal/
│ ├── opencode/opencode.go OpenCode server lifecycle & REST client
│ ├── llm/
│ │ ├── provider.go Two-stage Terraform generation pipeline
│ │ ├── prompts_aws.go AWS-specific prompt content
│ │ └── prompts_azure.go Azure-specific prompt content
│ ├── terrashark/
│ │ ├── terrashark.go Embeds TerraShark refs; exposes DesignGuidance()/CodingGuidance()
│ │ └── refs/ Embedded *.md references (SKILL, coding-standards, do-dont, etc.)
│ ├── modules/
│ │ ├── types.go ModuleMetadata, FitResult types
│ │ ├── store.go SQLite CRUD for module metadata
│ │ ├── scanner.go Git clone + HCL parsing (terraform-config-inspect)
│ │ ├── matcher.go Fit score algorithm (coverage, specificity, var readiness)
│ │ └── prompt.go User module prompt section builder
│ ├── provider/provider.go Cloud provider detection (AWS, Azure)
│ ├── steampipe/
│ │ ├── client.go Steampipe PostgreSQL client
│ │ └── resource_mapping.go AWS ARN + Azure resource ID → table mapping
│ ├── terraform/
│ │ ├── generator.go HCL file helpers
│ │ └── importer.go terraform import runner
│ ├── tui/
│ │ ├── model.go BubbleTea model & views (incl. module selection step)
│ │ ├── commands.go Async tea.Cmd definitions
│ │ └── styles.go Lipgloss styles
│ ├── cache/ SQLite scan cache
│ ├── debuglog/ File-based debug logger
│ ├── doctor/ Dependency validation
│ └── graph/ Resource dependency graph
├── .agents/skills/ OpenCode Terraform skills (style guide, import, TerraShark, etc.)
├── docker/
│ └── entrypoint.sh Docker container entrypoint
├── Dockerfile Multi-stage Docker build
├── Makefile Build & run targets
└── .sample.docker.env Sample env file for Docker runs
| Key | Action |
|---|---|
Enter |
Select / confirm |
Space |
Toggle resource or module selection |
r |
Expand related resources (resource step) |
↑ / ↓ |
Navigate list / scroll code |
Esc |
Go back to previous step |
/ |
Filter list |
q / Ctrl+C |
Quit |
