A CLI for interacting with the Terraform Cloud / HCP Terraform API. Built with Go, designed for both human operators and AI coding agents.
- Full CRUD support for core Terraform Cloud resources (organizations, projects, workspaces, runs, plans, applies, etc.)
- Terraform CLI authentication conventions - uses your existing
terraform logincredentials - Multiple contexts - manage multiple TFC/TFE environments with named profiles
- Automation-friendly - consistent JSON output, exit codes, and
--forceflag for non-interactive use - Download support - fetch plan JSON, sanitized plans, errored state, and configuration versions
# Clone and build
git clone https://github.com/richclement/tfccli.git
cd tfccli
make build
# Binary is at bin/tfccli
./bin/tfccli versiongo install github.com/richclement/tfccli/cmd/tfccli@latestDownload pre-built binaries from the releases page.
# Interactive setup
tfccli init
# Non-interactive setup (for CI/agents)
tfccli init --non-interactive --address app.terraform.io --default-org my-org --yesThis creates ~/.tfccli/settings.json with your default context.
tfccli uses Terraform CLI's authentication system. Run terraform login to authenticate:
terraform login
# Follow the prompts to generate and store your API tokentfccli doctorThis validates your settings, token discovery, and API connectivity.
tfccli discovers API tokens using Terraform CLI conventions. No tokens are stored in ~/.tfccli/settings.json.
Token discovery precedence (highest to lowest):
-
Environment variable:
TF_TOKEN_<sanitized_host># For app.terraform.io (dots become underscores) export TF_TOKEN_app_terraform_io="your-token-here"
-
Terraform CLI config:
TF_CLI_CONFIG_FILEenvironment variable or~/.terraformrccredentials "app.terraform.io" { token = "your-token-here" }
-
Terraform login credentials:
~/.terraform.d/credentials.tfrc.json(Created automatically byterraform login)
If no token is found, tfccli suggests running terraform login.
~/.tfccli/settings.json
Manage multiple TFC/TFE environments with named contexts:
# List contexts
tfccli contexts list
# Add a new context
tfccli contexts add prod --ctx-address tfe.example.com --default-org acme
# Switch contexts
tfccli contexts use prod
# Show current context config
tfccli contexts show
# Remove a context (requires confirmation)
tfccli contexts remove dev| Flag | Description |
|---|---|
--context <name> |
Select a named context from settings |
--address <addr> |
Override the API address for this invocation |
--org <org> |
Override the default organization |
--output-format <table|json> |
Output format (default: table on TTY, json otherwise) |
--debug |
Enable debug logging |
--force |
Bypass confirmation prompts for destructive operations |
# List all organizations
tfccli organizations list
# Get organization details
tfccli organizations get my-org
# Create an organization
tfccli organizations create --name new-org --email admin@example.com
# Update an organization
tfccli organizations update my-org --email new-email@example.com
# Delete an organization (requires confirmation)
tfccli organizations delete old-org
tfccli organizations delete old-org --force # Skip confirmation# List projects (uses --org or default_org)
tfccli projects list
# List projects for a specific org
tfccli projects list --org my-org
# Get project by ID
tfccli projects get prj-abc123
# Create a project
tfccli projects create --name my-project
# Update a project
tfccli projects update prj-abc123 --name new-name --description "Updated desc"
# Delete a project
tfccli projects delete prj-abc123 --force# List workspaces
tfccli workspaces list --org my-org
# Get workspace by ID
tfccli workspaces get ws-abc123
# Create a workspace
tfccli workspaces create --name my-workspace --org my-org
# Create workspace in a specific project
tfccli workspaces create --name my-workspace --org my-org --project-id prj-abc123
# Update a workspace
tfccli workspaces update ws-abc123 --name renamed-workspace
# Delete a workspace
tfccli workspaces delete ws-abc123 --force# List variables for a workspace
tfccli workspace-variables list --workspace-id ws-abc123
# Create an environment variable
tfccli workspace-variables create --workspace-id ws-abc123 \
--key AWS_REGION --value us-east-1 --category env
# Create a sensitive terraform variable
tfccli workspace-variables create --workspace-id ws-abc123 \
--key db_password --value secret123 --category terraform --sensitive
# Create an HCL variable
tfccli workspace-variables create --workspace-id ws-abc123 \
--key tags --value '{"env":"prod"}' --category terraform --hcl
# Update a variable
tfccli workspace-variables update var-abc123 --value new-value
# Delete a variable
tfccli workspace-variables delete var-abc123 --force# List resources in a workspace (read-only)
tfccli workspace-resources list --workspace-id ws-abc123# List runs for a workspace
tfccli runs list --workspace-id ws-abc123
# Get run details
tfccli runs get run-abc123
# Create a run
tfccli runs create --workspace-id ws-abc123 --message "Deploying new feature"
# Create a run with auto-apply
tfccli runs create --workspace-id ws-abc123 --auto-apply --message "Auto-deploy"
# Apply a run (requires confirmation)
tfccli runs apply run-abc123
tfccli runs apply run-abc123 --force # Skip confirmation
# Discard a run
tfccli runs discard run-abc123 --force
# Cancel a run
tfccli runs cancel run-abc123 --force
# Force-cancel a run
tfccli runs force-cancel run-abc123 --force# Get plan details
tfccli plans get plan-abc123
# Download JSON plan output
tfccli plans json-output plan-abc123
tfccli plans json-output plan-abc123 --out plan.json # Save to file
# Download sanitized plan (HYOK feature)
tfccli plans sanitized-plan plan-abc123
tfccli plans sanitized-plan plan-abc123 --out sanitized.json# Get apply details
tfccli applies get apply-abc123
# Download errored state (for recovery)
tfccli applies errored-state apply-abc123
tfccli applies errored-state apply-abc123 --out errored.tfstate# List configuration versions
tfccli configuration-versions list --workspace-id ws-abc123
# Get configuration version details
tfccli configuration-versions get cv-abc123
# Create a new configuration version
tfccli configuration-versions create --workspace-id ws-abc123
# Create without auto-queuing runs
tfccli configuration-versions create --workspace-id ws-abc123 --auto-queue-runs=false
# Upload configuration (tar.gz)
tfccli configuration-versions upload cv-abc123 --file ./config.tar.gz
# Download configuration
tfccli configuration-versions download cv-abc123
tfccli configuration-versions download cv-abc123 --out config.tar.gz
# Archive a configuration version
tfccli configuration-versions archive cv-abc123 --force# Get current authenticated user
tfccli users me
# Get user by ID
tfccli users get user-abc123# List invoices
tfccli invoices list --org my-org
# Get next/upcoming invoice
tfccli invoices next --org my-orgUse --output-format=json or pipe output (auto-detects non-TTY):
# Explicit JSON
tfccli organizations list --output-format=json
# Piped (auto-JSON)
tfccli organizations list | jq '.data[].attributes.name'
# JSON for empty responses (204 status)
tfccli organizations delete old-org --force --output-format=json
# Output: {"meta":{"status":204}}Default when stdout is a TTY:
tfccli organizations list
# NAME EMAIL EXTERNAL-ID
# my-org admin@example.com ext-123
# other-org other@example.com ext-456JSON output follows three patterns depending on the command type:
Commands that fetch or modify API resources wrap results in a data key:
// Single resource (get/create/update)
{"data": {"id": "org-abc123", "type": "organizations", "attributes": {...}}}
// List of resources
{"data": [{"id": "ws-abc123", "type": "workspaces", ...}, ...]}
// Empty list
{"data": []}
// runs get includes plan_id and apply_id for cross-referencing
{"data": {"id": "run-abc123", "status": "applied", "plan_id": "plan-xyz", "apply_id": "apply-def", ...}}Applies to: organizations, projects, workspaces, runs, plans get, applies get, configuration-versions, workspace-variables, workspace-resources
Commands that write to files (using --out) emit metadata about the operation:
// After writing a file
{"meta": {"written_to": "/path/to/file.json", "bytes": 12345}}
// After uploading
{"meta": {"status": "uploaded", "cv_id": "cv-abc123", "bytes": 5678}}Applies to: plans json-output --out, plans sanitized-plan --out, applies errored-state --out, configuration-versions download --out, configuration-versions upload
Some commands pass through the raw JSON:API response from the TFC API:
// users get / users me
{"data": {"id": "user-abc", "type": "users", "attributes": {...}}}
// invoices list (includes pagination)
{"data": [...], "links": {"self": "...", "next": "..."}}Applies to: users get, users me, invoices list, invoices next
| Code | Meaning |
|---|---|
| 0 | Success |
| 1 | CLI usage/validation error (missing flags, invalid enum) |
| 2 | Runtime error (config missing, auth failed, API error) |
| 3 | Unexpected/internal error |
For CI/CD pipelines and AI coding agents:
# Non-interactive initialization
tfccli init --non-interactive --address app.terraform.io --default-org my-org --yes
# Always use --force for destructive operations
tfccli organizations delete old-org --force
tfccli runs apply run-abc123 --force
# Explicit JSON output for parsing
tfccli workspaces list --output-format=json | jq '.data[].id'
# Check exit codes
if tfccli doctor; then
echo "TFC connection healthy"
else
echo "TFC connection failed"
exit 1
fi# Build
make build
# Run tests
make test
# Run linter
make lint
# Format code
make fmt
# CI pipeline (fmt-check + lint + test)
make ci
# Build and run with args
make tfccli ARGS="version"See LICENSE for details.