---
title: "Agents (Vertex) Environment"
slug: gcp-env-vertex
section: GCP Infrastructure
status: stable
description: "The GCP project `alliance-platform-agents` hosts the automation agent fleet, called \"Vertex agents\" in the Terraform folder name `environments/vertex`."
last-updated: 2026-10-07
---

# Agents (Vertex) Environment

The GCP project `alliance-platform-agents` hosts the automation agent fleet, called "Vertex agents" in the Terraform folder name `environments/vertex`. It is a separate project from the Globus environments (development, qa, production, see `/docs/gcp-overview`). Every agent runs as a Cloud Run service in `us-central1`; the live snapshot found all of them in that single region.

**Read this first: Terraform covers only a small slice of this project.** The live snapshot shows 11 Cloud Run services, 3 buckets, a Firestore database, two Cloud Scheduler jobs and dozens of secrets. Terraform declares none of the Cloud Run services, Firestore or buckets, and only a handful of service accounts and secrets, plus two Atlas Cloud Scheduler jobs (described below). The folder has not been applied through Terraform: its own comments call it an unapplied draft with no backend bucket and empty state, and no workflow in the repo applies it. A few bindings in it are recorded as already created by hand with `gcloud`.

## What runs here

- **Agent services.** Cloud Run services named `<agent>-agent` plus a few helpers, for example the asana-hygiene and pr-hygiene agents, `security-agent`, `env-audit-agent`, `posthog-agent`, `vertex-sync-agent`, the dev-to-qa and qa-to-prod sync agents, `github-token-minter` and `cloudbuild-teams-notifier`. The drift report shows that every one of these is live-only. For the promotion model the sync agents serve, see `/docs/git-branching-release-model`.
- **State and scheduling.** Firestore `(default)` (enabled as an API but not declared); `qa-to-prod-sync-agent` keeps its dedup fingerprint and run lock in a Firestore document (collection `agent_state`, document `qa-to-prod-sync-agent`), and its service account holds `roles/datastore.user`. Cloud Scheduler job `vertex-sync-agent-hourly`, and one declared Pub/Sub topic for the security agent. The other topics are Container Analysis topics created by the platform.
- **Per-agent identity and secrets.** One service account per agent, and per agent usually an `-api-key` and a `-gateway-pat` secret (names only here; values are never in this documentation). Some Cloud Run services reference secrets that live in a different project, via the `run.googleapis.com/secrets` annotation.
- **Images and builds.** Artifact Registry repository `alliance-abroad` and the Cloud Run source-deploy repository. The snapshot found no Cloud Build triggers, no WIF pools and no Cloud SQL.

## What Terraform actually declares

`environments/vertex/main.tf` declares the project service (API) set, a set of service-account modules with their project roles, a few secrets, and one scheduler service account. Further files draft the security agent asset-change topic and push subscription (`security-agent-asset-change-feed.tf`), plus Cloud Run invoker bindings on `security-agent` and `vertex-sync-agent` for a service account from `alliance-platform-services`, and an n8n API key accessor grant. `atlas-ci-caller.tf` declares a separate service account `atlas-ci-caller` that holds no project roles, a Workload Identity pool `github-actions-atlas` with provider `github-provider`, a `roles/run.invoker` binding for that service account on `atlas-agent`, and a `roles/iam.workloadIdentityUser` binding on that service account. The provider's attribute condition requires the repository `Alliance-Strategies/BackOfficePrototype` and a `job_workflow_ref` of `Alliance-Strategies/BackOfficePrototype/.github/workflows/atlas-after-deploy.yml@refs/heads/main`. The `main.tf` header comments are partly stale: they still describe the fleet as mid-migration with only one live Cloud Run service, but later notes in the same file and the live snapshot show the migration finished and the fleet running here. The file also records that `overseer-agent` and `observer-agent-v2` were decommissioned (2026-08-11) and `volume-testing-agent` was decommissioned (2026-08-26), with their blocks removed from the draft. It also records that `branch-drift-agent` was decommissioned, superseded by the sandbox branching model rulesets, and that the `branch-drift-agent-sa` and `branch-drift-scheduler` blocks were removed (2026-10-05). The Cloud Scheduler job `branch-drift-agent-scan` and all `branch-drift-agent-*` secrets were deleted with `gcloud` the same day.

`atlas-egress.tf` declares a network egress allow-list for `atlas-agent`: a custom-mode VPC `atlas-egress-vpc`, a subnet `atlas-egress-uc1`, a Cloud NAT `atlas-egress-nat`, a private Cloud DNS zone `atlas-googleapis` for `googleapis.com.` that sends `*.googleapis.com` to the private VIP, and a network firewall policy `atlas-egress-policy` associated with the VPC. The policy allows `tcp:443` to `199.36.153.8/30` and to an FQDN list (the gateway, Kiwi and the allow-listed dev portal hosts), has a rule 110 that allows `tcp:443` to the current host addresses, and denies all other egress. Like the rest of the folder it has no apply path and no state; its header comment says the objects were created by hand.

`main.tf` also declares two Cloud Scheduler jobs for Atlas. `atlas-agent-daily-regression` runs on the cron schedule `25 6 * * 1-5` in `America/Chicago`. `atlas-agent-weekly-digest` runs on `12 7 * * 1` in `America/Chicago` (Mondays 07:12). The weekly job sends an HTTP `POST` with no retries (`retry_count = 0`); per its description it posts a weekly digest of autonomy-ladder decisions to Platform Pulse and files nothing.

The backend in `backend.tf` points at the development state bucket (`dev-tfstate-skilled-script-469819-f2`, prefix `alliance-gcp-infra/vertex`), and its comment says that bucket does not exist. A different bucket, `platform-agents-tfstate-alliance-platform-agents`, does exist live in this project, but the Terraform code does not reference it. Which of the two is intended is not stated anywhere in the repo.

## How changes get here

- **No Terraform path.** There is no apply workflow for vertex. `terraform-plan-pr` and `terraform-drift-detect` both exclude it on purpose, because planning an unapplied draft would report every resource as new. See `/docs/gcp-terraform-workflows`. This means the live resources here are not managed through Terraform, and neither Terraform workflow would notice drift here.
- **Application CI and manual deploys.** Agent code lives in the `vertex-agents` repo (see `/docs/repo-inventory`). The `github-actions-deploy` service account from the development project holds deploy-type roles here, and Cloud Run source deploys leave their buckets and registry behind. The Terraform file comments describe many fixes (API enablement, IAM roles) as applied out of band.
- **Gateway access is read-only.** The live snapshot was read through the gateway `agents` environment, using `gcp-mcp-sa` in `alliance-mcp-services` impersonating `manus-agent-sa` in this project, and the snapshot notes record it as read-only. Comments in `main.tf` record that this credential was denied secret IAM policy reads and Cloud Run service deletion when tested, and that cleanup and grants therefore had to be run by a person with direct access.

## Relationship to other projects

Agents here call the Alliance MCP Gateway (`/docs/gcp-env-mcp`) with per-agent `-gateway-pat` secrets, and scan or act on the development, qa and production projects (`/docs/gcp-env-development`, `/docs/gcp-env-qa`, `/docs/gcp-env-production`). Cross-project permissions for those scans are granted in the target projects, not here, and some were missing as of the 2026-08-20 comments in `main.tf` (for example Cloud SQL, KMS and IAM visibility in the other scanned projects). Deployment policy context is in `/docs/dev-only-deployment-policy`; recovery context is in `/docs/disaster-recovery-plan`, which does not describe how this fleet would be rebuilt, and since there is no Terraform for the services, a rebuild would depend on the source repo and manual secret recreation.

_Terraform inventory generated from `alliance-gcp-infra` at commit `fc9bd1d`. Live snapshots: `alliance-platform-agents` read 2026-10-01. Snapshots hold names and a few stable attributes only, never secret values._

## Terraform-managed resources

Every module call and resource block under `environments/vertex` (16 in total), grouped by category.

### Identity and access (service accounts, IAM bindings, Workload Identity)

11 items.

| Terraform address | Module or resource type | Identifier | Defined in |
| --- | --- | --- | --- |
| `google_cloud_run_service_iam_member.security_agent_sys_n8n_invoker` | `google_cloud_run_service_iam_member` | `roles/run.invoker -> serviceAccount:sys-n8n-sa@alliance-platform-services.iam.gserviceaccount.com` | `security-agent-vertex-sync-agent-sys-n8n-invoker.tf:21` |
| `google_cloud_run_service_iam_member.vertex_sync_agent_sys_n8n_invoker` | `google_cloud_run_service_iam_member` | `roles/run.invoker -> serviceAccount:sys-n8n-sa@alliance-platform-services.iam.gserviceaccount.com` | `security-agent-vertex-sync-agent-sys-n8n-invoker.tf:29` |
| `google_secret_manager_secret_iam_member.observer_agent_v2_n8n_api_key_accessor` | `google_secret_manager_secret_iam_member` | `n8n-api-key` | `observer-agent-v2-n8n-api-key-accessor.tf:14` |
| `module.asana_hygiene_agent_sa` | `service-account` | `asana-hygiene-agent-sa` | `main.tf:280` |
| `module.cloudbuild_teams_notifier_development` | `service-account` | `cloudbuild-teams-notifier` | `main.tf:380` |
| `module.dev_to_qa_sync_agent_sa_development` | `service-account` | `dev-to-qa-sync-agent-sa` | `main.tf:364` |
| `module.env_audit_agent_sa_development` | `service-account` | `env-audit-agent-sa` | `main.tf:241` |
| `module.posthog_agent_sa` | `service-account` | `posthog-agent-sa` | `main.tf:334` |
| `module.pr_hygiene_agent_sa` | `service-account` | `pr-hygiene-agent` | `main.tf:299` |
| `module.security_agent_sa` | `service-account` | `security-agent-sa` | `main.tf:258` |
| `module.vertex_sync_agent_sa_development` | `service-account` | `vertex-sync-agent-sa` | `main.tf:349` |

### Secrets (Secret Manager containers)

3 items.

| Terraform address | Module or resource type | Identifier | Defined in |
| --- | --- | --- | --- |
| `module.pr_hygiene_agent_api_key` | `secret-manager-secret` | `pr-hygiene-agent-api-key` | `main.tf:454` |
| `module.pr_hygiene_agent_gateway_pat` | `secret-manager-secret` | `pr-hygiene-agent-gateway-pat` | `main.tf:413` |
| `module.pr_hygiene_agent_known_issues` | `secret-manager-secret` | `pr-hygiene-agent-known-issues` | `main.tf:466` |

### Project services, messaging and other

2 items.

| Terraform address | Module or resource type | Identifier | Defined in |
| --- | --- | --- | --- |
| `module.project_services_agents` | `project-services` | `36 items: aiplatform, analyticshub, artifactregistry, ...` | `main.tf:159` |
| `module.security_agent_asset_change_topic` | `pubsub-topic` | `security-agent-asset-changes` | `security-agent-asset-change-feed.tf:30` |

## Live state

### Terraform compared with live state

| Resource type | Live | In Terraform | Matched | Live only (unmanaged) | Platform-created | Terraform only | Name not resolvable |
| --- | --- | --- | --- | --- | --- | --- | --- |
| `api` | 40 | 36 | 35 | 5 | 0 | 1 | 0 |
| `cloud_run_service` | 11 | 0 | 0 | 11 | 0 | 0 | 0 |
| `cloud_run_job` | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| `cloud_sql` | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| `firestore` | 1 | 0 | 0 | 1 | 0 | 0 | 0 |
| `bucket` | 3 | 0 | 0 | 1 | 2 | 0 | 0 |
| `secret` | 35 | 3 | 2 | 33 | 0 | 1 | 0 |
| `service_account` | 15 | 10 | 7 | 7 | 1 | 3 | 0 |
| `wif_pool` | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| `artifact_registry` | 2 | 0 | 0 | 1 | 1 | 0 | 0 |
| `cloudbuild_trigger` | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| `pubsub_topic` | 5 | 1 | 1 | 0 | 4 | 0 | 0 |
| `scheduler_job` | 2 | 0 | 0 | 2 | 0 | 0 | 0 |
| `domain_mapping` | 0 | 0 | 0 | 0 | 0 | 0 | 0 |

### Live but not in Terraform

61 resources of the compared types exist in the project without a matching Terraform declaration.

| Resource type | Name |
| --- | --- |
| `api` | `cloudasset` |
| `api` | `dlp` |
| `api` | `firebaserules` |
| `api` | `firestore` |
| `api` | `recommender` |
| `cloud_run_service` | `asana-hygiene-agent` |
| `cloud_run_service` | `branch-drift-agent` |
| `cloud_run_service` | `cloudbuild-teams-notifier` |
| `cloud_run_service` | `dev-to-qa-sync-agent` |
| `cloud_run_service` | `env-audit-agent` |
| `cloud_run_service` | `github-token-minter` |
| `cloud_run_service` | `posthog-agent` |
| `cloud_run_service` | `pr-hygiene-agent` |
| `cloud_run_service` | `qa-to-prod-sync-agent` |
| `cloud_run_service` | `security-agent` |
| `cloud_run_service` | `vertex-sync-agent` |
| `firestore` | `(default)` |
| `bucket` | `platform-agents-tfstate-alliance-platform-agents` |
| `secret` | `POSTHOG_PERSONAL_API_KEY` |
| `secret` | `asana-hygiene-agent-api-key` |
| `secret` | `asana-hygiene-agent-gateway-pat` |
| `secret` | `branch-drift-agent-api-key` |
| `secret` | `branch-drift-agent-gateway-pat` |
| `secret` | `branch-drift-agent-known-issues` |
| `secret` | `dev-to-qa-sync-agent-api-key` |
| `secret` | `dev-to-qa-sync-agent-gateway-pat` |
| `secret` | `dev-to-qa-sync-agent-state` |
| `secret` | `env-audit-agent-api-key` |
| `secret` | `env-audit-agent-gateway-pat` |
| `secret` | `globus-development-asana-access-token` |
| `secret` | `n8n-api-key` |
| `secret` | `observer-agent-v2-api-key` |
| `secret` | `observer-agent-v2-gateway-pat` |
| `secret` | `overseer-agent-api-key` |
| `secret` | `overseer-agent-gateway-pat` |
| `secret` | `overseer-agent-known-issues` |
| `secret` | `overseer-agent-n8n-sync-state` |
| `secret` | `overseer-agent-openai-api-key` |
| `secret` | `platform-bot-github-pat` |
| `secret` | `posthog-agent-api-key` |
| `secret` | `posthog-agent-gateway-pat` |
| `secret` | `pr-hygiene-agent-asana-pat` |
| `secret` | `qa-to-prod-sync-agent-api-key` |
| `secret` | `qa-to-prod-sync-agent-gateway-pat` |
| `secret` | `security-agent-api-key` |
| `secret` | `security-agent-gateway-pat` |
| `secret` | `security-agent-iac-scan-github-token` |
| `secret` | `security-agent-openai-api-key` |
| `secret` | `teams-platform-pulse-webhook-url` |
| `secret` | `vertex-sync-agent-api-key` |
| `secret` | `vertex-sync-agent-gateway-pat` |
| `service_account` | `cloudbuild-teams-notifier-sa` |
| `service_account` | `github-token-minter-sa` |
| `service_account` | `manus-agent-sa` |
| `service_account` | `observer-agent-v2-sa` |
| `service_account` | `overseer-agent-sa` |
| `service_account` | `pr-hygiene-agent-sa` |
| `service_account` | `qa-to-prod-sync-agent-sa` |
| `artifact_registry` | `alliance-abroad` |
| `scheduler_job` | `branch-drift-agent-scan` |
| `scheduler_job` | `vertex-sync-agent-hourly` |

### In Terraform but not found live

| Resource type | Name | Terraform address | Defined in |
| --- | --- | --- | --- |
| `api` | `container` | `module.project_services_agents` | `main.tf:159` |
| `secret` | `pr-hygiene-agent-known-issues` | `module.pr_hygiene_agent_known_issues` | `main.tf:466` |
| `service_account` | `pr-hygiene-agent` | `module.pr_hygiene_agent_sa` | `main.tf:299` |
| `service_account` | `branch-drift-scheduler` | `module.branch_drift_scheduler` | `main.tf:322` |
| `service_account` | `cloudbuild-teams-notifier` | `module.cloudbuild_teams_notifier_development` | `main.tf:380` |

### Created by GCP or GKE

These are created by the platform itself (default network rules, GKE firewall rules, default compute service accounts, Cloud Build buckets, container analysis topics) and are not drift.

| Resource type | Name |
| --- | --- |
| `bucket` | `alliance-platform-agents_cloudbuild` |
| `bucket` | `run-sources-alliance-platform-agents-us-central1` |
| `service_account` | `668649570162-compute` |
| `artifact_registry` | `cloud-run-source-deploy` |
| `pubsub_topic` | `container-analysis-notes-v1` |
| `pubsub_topic` | `container-analysis-notes-v1beta1` |
| `pubsub_topic` | `container-analysis-occurrences-v1` |
| `pubsub_topic` | `container-analysis-occurrences-v1beta1` |

### Resource types not compared

| Resource type | Reason | Declared in Terraform |
| --- | --- | --- |
| `redis` | snapshot section unreadable (denied, API disabled or not collected) | 0 |
| `gke_cluster` | snapshot section unreadable (denied, API disabled or not collected) | 0 |
| `firewall_rule` | snapshot section unreadable (denied, API disabled or not collected) | 0 |
| `vpc_network` | snapshot section unreadable (denied, API disabled or not collected) | 0 |

### Live reads that were denied or unavailable

| Read attempted | Result |
| --- | --- |
| gcloud billing projects describe | cloudbilling.googleapis.com not enabled on project 668649570162 (SERVICE_DISABLED) |
| gcloud redis instances list | redis.googleapis.com not enabled (treated as no Redis) |
| gcloud compute networks/subnets/firewall/etc. (network, load_balancing) | compute.googleapis.com not enabled; networking not enumerable. No vpc connector on any Cloud Run service. |
| gcloud dns managed-zones list | dns.googleapis.com not enabled |
| gcloud container clusters list | container.googleapis.com not enabled (no GKE) |
| gcloud services api-keys list | apikeys.googleapis.com not enabled on project 668649570162 |
| gcloud deploy delivery-pipelines list | clouddeploy.googleapis.com not enabled |
| first combined gcloud projects describe + services list call | gateway: backend request failed (retried OK as separate calls) |

### Collection notes

Caveats recorded when the live snapshot was read.

- Run via gateway env=agents (read-only). Cloud Run listed across all regions: all 11 in us-central1.
- WIF pools, build triggers, Cloud Build connections (us-central1 only checked), Cloud SQL, Cloud Run jobs, domain mappings (us-central1 only checked) are empty.
- Cloud Run secret env refs recorded as names only; some secrets referenced cross-project (projects/382570452229/secrets/...) via run.googleapis.com/secrets annotation.
- Secrets have no labels, automatic replication.
- SAs overseer-agent-sa and observer-agent-v2-sa exist (with secrets) but no Cloud Run service for them is deployed.
- Project owner is user [user account]; cross-project principals gcp-mcp-sa@alliance-mcp-services and github-actions-deploy@skilled-script-469819-f2 hold run.developer/storage.admin etc.

## Live inventory

Selected stable attributes read from the running project.

### Cloud Run services (live)

| Service | Region | Ingress | Scaling | Runs as |
| --- | --- | --- | --- | --- |
| `asana-hygiene-agent` | `us-central1` | `all` | `0-1` | `asana-hygiene-agent-sa@alliance-platform-agents.iam.gserviceaccount.com` |
| `branch-drift-agent` | `us-central1` | `all` | `0-1` | `branch-drift-agent-sa@alliance-platform-agents.iam.gserviceaccount.com` |
| `cloudbuild-teams-notifier` | `us-central1` | `all` | `0-3` | `cloudbuild-teams-notifier-sa@alliance-platform-agents.iam.gserviceaccount.com` |
| `dev-to-qa-sync-agent` | `us-central1` | `all` | `0-1` | `dev-to-qa-sync-agent-sa@alliance-platform-agents.iam.gserviceaccount.com` |
| `env-audit-agent` | `us-central1` | `all` | `0-1` | `env-audit-agent-sa@alliance-platform-agents.iam.gserviceaccount.com` |
| `github-token-minter` | `us-central1` | `all` | `0-3` | `github-token-minter-sa@alliance-platform-agents.iam.gserviceaccount.com` |
| `posthog-agent` | `us-central1` | `all` | `0-1` | `posthog-agent-sa@alliance-platform-agents.iam.gserviceaccount.com` |
| `pr-hygiene-agent` | `us-central1` | `all` | `0-100` | `pr-hygiene-agent-sa@alliance-platform-agents.iam.gserviceaccount.com` |
| `qa-to-prod-sync-agent` | `us-central1` | `all` | `0-1` | `qa-to-prod-sync-agent-sa@alliance-platform-agents.iam.gserviceaccount.com` |
| `security-agent` | `us-central1` | `all` | `0-1` | `security-agent-sa@alliance-platform-agents.iam.gserviceaccount.com` |
| `vertex-sync-agent` | `us-central1` | `all` | `0-1` | `vertex-sync-agent-sa@alliance-platform-agents.iam.gserviceaccount.com` |

### Cloud Storage buckets (live)

| Bucket | Location | Class | Versioning | Public access prevention |
| --- | --- | --- | --- | --- |
| `alliance-platform-agents_cloudbuild` | `US` | `STANDARD` | `false` | `inherited` |
| `platform-agents-tfstate-alliance-platform-agents` | `US-CENTRAL1` | `STANDARD` | `true` | `inherited` |
| `run-sources-alliance-platform-agents-us-central1` | `US-CENTRAL1` | `STANDARD` | `false` | `inherited` |

### Cloud Scheduler jobs (live)

| Job | Schedule | State |
| --- | --- | --- |
| `branch-drift-agent-scan` | `0 */6 * * *` | `ENABLED` |
| `vertex-sync-agent-hourly` | `0 * * * *` | `ENABLED` |

## Security observations

These are facts from the live snapshot and Terraform files. They should be reviewed.

- The project owner role is held by an individual user account rather than a group or break-glass identity.
- Cross-project principals hold broad roles here: the gateway service account in `alliance-mcp-services` and the development deploy account between them hold roles including `run.developer` and `storage.admin`.
- In the draft Terraform, `security-agent-sa` is given project-level `roles/storage.admin` and `roles/cloudsql.editor`, alongside read and secret-version-adder roles. Whether these are applied live was not verified.
- Service accounts and secrets for decommissioned agents (`overseer-agent`, `observer-agent-v2`) still exist live with no Cloud Run service behind them. The draft notes that cleanup needs someone with write access.
- Secrets carry no labels, and several agents use long-lived API keys and personal access tokens held as secrets.
- An older draft note says `observer-agent-v2` was publicly invokable with only an application-level key. That service no longer exists live, but the current invoker settings of the remaining services were not checked here.

## Known gaps

- `alliance-platform-services` could not be read at all, and `alliance-mcp-services` was read through a development-environment token with many sections denied. This page covers neither.
- In the 2026-10-01 snapshot, Compute, DNS, GKE, Redis, API keys and Cloud Billing APIs were disabled or not readable, so networking, load balancing and firewall rules, and API key restrictions are not verifiable from it (the snapshot notes there is no VPC connector on any Cloud Run service). `main.tf` now lists `compute.googleapis.com` and `dns.googleapis.com` among the project services.
- Cloud Build connections and domain mappings were checked in `us-central1` only.
- Live IAM bindings for the Terraform-declared project roles were not compared with the code; only resource existence was.
- Which service accounts a given Cloud Run service uses, and per-service ingress and invoker settings, were not analysed for this page.
- The intended state bucket for this folder is unconfirmed (see above).
- Whether the read-only limit on the gateway identity is a deliberate policy, and exactly which secret and Cloud Run permissions it lacks, was not confirmed from the snapshot; only the notes and `main.tf` comments above support it.
