Skip to content
Development
Agent

terraform-patterns

**Assumes `/google-agents-cli-scaffold` scaffolding.** These patterns apply to projects with `deployment/terraform/` directories.

From plugin
google-agents-cli
5.9k28 skills28 agents
Install
$ npx -y skills add google/agents-cli --agent claude-code

How it fires

How this agent gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.

Context preview

The summary Claude sees to decide when to auto-load this agent.

**Assumes `/google-agents-cli-scaffold` scaffolding.** These patterns apply to projects with `deployment/terraform/` directories.

Agent definition

terraform-patterns.md

Custom Infrastructure (Terraform)

> **Assumes `/google-agents-cli-scaffold` scaffolding.** These patterns apply to projects with `deployment/terraform/` directories.

Where to Put Custom Terraform

| Scenario | Location | |----------|----------| | Single-project infrastructure | `deployment/terraform/single-project/` | | CI/CD environments (staging/prod) | `deployment/terraform/cicd/` |

Example: Custom Resources

# deployment/terraform/single-project/custom_resources.tf

resource "google_pubsub_topic" "events" {
  name    = "${var.project_name}-events"
  project = var.project_id
}

resource "google_bigquery_dataset" "analytics" {
  dataset_id = "${replace(var.project_name, "-", "_")}_analytics"
  project    = var.project_id
  location   = var.region
}

# Eventarc trigger for Cloud Storage
resource "google_eventarc_trigger" "storage_trigger" {
  name     = "${var.project_name}-storage-trigger"
  location = var.region
  project  = var.project_id

  matching_criteria {
    attribute = "type"
    value     = "google.cloud.storage.object.v1.finalized"
  }
  matching_criteria {
    attribute = "bucket"
    value     = google_storage_bucket.uploads.name
  }

  destination {
    cloud_run_service {
      service = google_cloud_run_v2_service.app.name
      region  = var.region
      # ADK trigger-source route; on other frameworks point this at your app's own path
      path    = "/apps/${var.project_name}/trigger/eventarc"
    }
  }

  service_account = google_service_account.app_sa.email
}

**For CI/CD environments (staging/prod):**

Add resources to `deployment/terraform/cicd/` (applies to staging and prod):

# deployment/terraform/cicd/custom_resources.tf
# Resources here are created in BOTH staging and prod projects
# Use for_each with local.deploy_project_ids for multi-environment

resource "google_pubsub_topic" "events" {
  for_each = local.deploy_project_ids
  name     = "${var.project_name}-events"
  project  = each.value
}

IAM for Custom Resources

**Single-project** (`deployment/terraform/single-project/`):

resource "google_pubsub_topic_iam_member" "app_publisher" {
  topic   = google_pubsub_topic.events.name
  project = var.project_id
  role    = "roles/pubsub.publisher"
  member  = "serviceAccount:${google_service_account.app_sa.email}"
}

# Grant BigQuery data editor
resource "google_bigquery_dataset_iam_member" "app_editor" {
  dataset_id = google_bigquery_dataset.analytics.dataset_id
  project    = var.project_id
  role       = "roles/bigquery.dataEditor"
  member     = "serviceAccount:${google_service_account.app_sa.email}"
}

**CI/CD** (`deployment/terraform/cicd/`) — use `for_each` to apply across environments:

resource "google_pubsub_topic_iam_member" "app_publisher" {
  for_each = local.deploy_project_ids
  topic    = google_pubsub_topic.events[each.key].name
  project  = each.value
  role     = "roles/pubsub.publisher"
  member   = "serviceAccount:${google_service_account.app_sa[each.key].email}"
}

Applying Custom Infrastructure

# For single-project infrastructure
agents-cli infra single-project  # Runs terraform apply in deployment/terraform/single-project/

# For CI/CD, infrastructure is applied automatically on push

Common Patterns

> The `/apps/{app_name}/trigger/*` paths below are ADK's trigger-source routes. The Terraform is the same on any framework — point it at whatever path your app serves.

**Cloud Storage trigger (Eventarc):**

  • Create bucket in Terraform
  • Create Eventarc trigger pointing to `/apps/{app_name}/trigger/eventarc` endpoint
  • Grant `eventarc.eventReceiver` role to app service account

**Pub/Sub processing:**

  • Create topic and push subscription in Terraform
  • Point subscription to `/apps/{app_name}/trigger/pubsub` endpoint
  • Grant `iam.serviceAccountTokenCreator` role for push auth

> **Go trigger endpoints are not enabled by default, and sit under `/api`.** The scaffolded `main.go` > already registers the `pubsub` and `eventarc` sub-launchers, but the container `ENTRYPOINT` omits > their keywords, so the routes are not served. Each trigger launcher keeps its own `-path_prefix`. > The launcher prints both URLs at startup; point the subscription at those.

**BigQuery Remote Function:**

  • Create BigQuery connection in Terraform
  • Grant connection service account permission to invoke Cloud Run
  • Create the remote function via SQL after deployment

**Cloud SQL sessions:**

  • Already configured when using `--session-type cloud_sql` via the Agents CLI (see `/google-agents-cli-scaffold`)
  • Additional tables/schemas can be added via migration scripts

Terraform State Management

Remote State (Default)

By default, `infra cicd` creates a GCS bucket for remote Terraform state:

# Auto-configured backend in deployment/terraform/cicd/backend.tf
terraform {
  backend "gcs" {
    bucket = "{cicd_project}-terraform-state"
    prefix = "{repository_name}/{prod|single-project}"
  }
}

The state bucket is named `{cicd_project}-terraform-state` and uses the repository name + environment as the prefix to isolate state per project and environment.

Local State

Use the `--local-state` flag with `infra cicd` to skip remote backend setup and store state locally:

agents-cli infra cicd \
  --staging-project STAGING_PROJECT \
  --prod-project PROD_PROJECT \
  --repository-name REPO_NAME \
  --create \
  --local-state

Local state is stored in `deployment/terraform/cicd/terraform.tfstate`. This is suitable for single-developer projects but not recommended for teams (state conflicts).

Importing Existing Resources

If resources already exist (e.g., created manually or by a previous deployment), import them into Terraform state:

# Import a Cloud Run service
cd deployment/terraform/single-project
terraform import google_cloud_run_v2_service.app \
  projects/PROJECT_ID/locations/REGION/services/SERVICE_NAME

# Import a service account
terraform import goo
Read more
Ships withgoogle-agents-cli

The CLI and skills that turn any coding assistant into an expert at creating, evaluating, and deploying AI agents on Google Cloud.

Get the whole plugin

Other agents on google-agents-cli.