I wrote this blog as part of my submission to the All Things Agentic Hackathon, Fortified Enterprise Fleet track.
PatchAPI is Dependabot for APIs. When a provider ships a breaking change, it finds the affected code, verifies a migration in isolation, and opens a pull request for a human to review.
The problem
I hate keeping track of every API and service release. Google Cloud has hundreds of services. When a change notice lands I have to dig through my own memory: do any of my apps use this, and will they break when it shuts down?
Breaking changes ship with little warning. New features launch quietly. Release notes rarely get the attention they deserve.
The infrastructure for automated code changes already exists. What is missing is the layer that connects a provider's notice to a customer's codebase.
Providers should not just announce a change. They should apply it.
What PatchAPI does
PatchAPI connects two sides.
| Provider | Developer |
|---|---|
| Publishes services and release changes | Connects repos and subscribes to providers |
| PatchAPI continuously ingests the feeds | PatchAPI maps those changes onto the code |
When a provider change matches something in a repo, that overlap becomes a verified pull request.
Provider side
Providers point PatchAPI at endpoints they already maintain. No extra publishing workflow.
For Google Cloud:
-
Catalog: Service Usage —
serviceusage.googleapis.com/v1/projects/{project}/services -
Changes: BigQuery release notes —
bigquery-public-data.google_cloud_release_notes.release_notes
PatchAPI parses the project, dataset, or table from the URL and keeps the catalog and change stream in sync.
Developer side
You sign in, create a project, and import GitHub repositories. An indexer stores every provider identifier it finds — model IDs, *.googleapis.com hosts, SDK dependencies — in Cloud SQL.
Subscribe to a provider such as Google Cloud. Incoming changes land in the inbox as Needs you or Watching.
Start remediation hands the finding to a warm worker. The agent fleet then:
- Finds the affected code.
- Applies the migration.
- Tests it inside a GKE Agent Sandbox (gVisor, default-deny network).
- Verifies the fix from the pinned base SHA.
- Opens a GitHub pull request with the verified migration.
The human still decides. What disappears is the investigation.
How it is built
1. Release-note ingest
Google does not push when a note lands. Cloud Scheduler starts a Cloud Run job on a cron — patchapi-refresh-releases. The job pulls the enabled-API catalog and the release-notes table as two separate pieces of work. If a pull fails it records error and stops, so a half catalog never goes live.
2. Repo indexing and subscriptions
Importing a repo or pushing new code triggers the indexer. A Cloud Run worker searches for model IDs and *.googleapis.com hosts, then uses ast-grep to drop false positives.
Confirmed usages land in provider_usages with file, line, and type. Progress streams to the UI over SSE.
Subscribe and PatchAPI compares those usages against the change stream:
- Needs you — runtime, config, or tests already depend on something deprecated or shut down.
- Watching — future-dated, not currently used, or a new identifier worth adopting.
Dismissals survive a re-index.
3. Remediation queue and warm workers
Start writes a RECEIVED row. That row is the queue. A warm Cloud Run worker pool claims it with FOR UPDATE SKIP LOCKED, so Start does not wait for a job to boot.
4. GKE Agent Sandbox
Generated code runs only inside a gVisor-isolated GKE sandbox: no service-account token, a read-only root filesystem, dropped capabilities, and resource limits.
The network starts at deny. PatchAPI opens only the egress needed for dependency install or the live call, scoped to that sandbox, then deletes the policy.
5. Credential handling
Connect GCP is a viewer, not a key dump. PatchAPI can see that GEMINI_API_KEY comes from Secret Manager. Postgres stores the resource name only.
For live verification a broker fetches the secret just before the sandbox command and injects it into that command's environment. The value never enters a prompt, a log, evidence, or Postgres. GitHub tokens never land in the database either.
If a required secret is missing, the same run pauses until it is added or GCP is connected.
6. Independent verification
A separate agent grades the run on evidence only: build log, test log, live probe, the diff, and the files it was not allowed to touch. It cannot be the agent that wrote the patch.
- PASS — checks pass, no unexpected files, deprecated identifiers gone.
- FAIL — verification found a real problem.
- INCONCLUSIVE — not enough signal to prove either.
- SKIP — this change never required that check.
No pull request opens without PASS. Nothing overrides the verifier.
Stack
| Layer | Technology |
|---|---|
| Agent runtime | Google ADK 2.1, gemini-3.5-flash on Vertex AI locations/global
|
| Prompt safety | Model Armor — sanitizeUserPrompt
|
| Agent memory | Vertex AI Agent Engine Memory Bank (reasoningEngines), repo-scoped |
| Tracing | Cloud Trace over OTLP/gRPC to telemetry.googleapis.com, OpenTelemetry SDK |
| Console | Next.js 16, React 19, Tailwind 4, TypeScript strict, SSE for live state |
| Control plane | FastAPI, Python 3.12, Pydantic v2 contracts, uv, ruff
|
| Workflow state | Cloud SQL Postgres 16 via SQLAlchemy + asyncpg |
| Events | Pub/Sub push |
| Scheduling | Cloud Scheduler → hourly identifier for release notes |
| Code search | Zoekt shards for recall, ast-grep rules for call-site confirmation |
| Code execution | GKE Agent Sandbox on gVisor |
| Provider ingest | Service Usage API, BigQuery public release-notes table |
| Auth | Identity Platform, Google OAuth, one GitHub App |
| Secrets | Secret Manager |
| Provisioning | Terraform modules per environment |
| CI/CD | GitHub Actions, Workload Identity Federation, Artifact Registry |
What I learned
Seconds-fast change detection
My first idea was to give an agent a repo and a release note and let it inspect everything. That works for one repo and one notice. It does not work for hundreds of services and thousands of notes. The same repo gets reread. Answers drift. The audit trail is a transcript.
The direction was backwards. Process each notice once.
Change Intelligence writes a repo-agnostic manifest. The indexer already knows which APIs, SDKs, models, and services each project uses. Affected projects are a Postgres join. That is why it takes seconds.
A warm pool so Start is instant
A full remediation — clone, patch, build, test, verify, PR — can take minutes. I tried keeping it in the HTTP request, Pub/Sub push, the agents service, and a Cloud Run Job. Request lifetime, redelivery, blocked concurrency, or a 136-second cold start.
The queue is a Postgres row. Workers stay warm and claim RECEIVED runs with FOR UPDATE SKIP LOCKED. When you click Start, the environment is already up.
Resources
The official Google documentation I used to build this project, and that you can learn from too.
| Area | Resource | Used for |
|---|---|---|
| Agent Platform | Memory Bank | Repo-scoped context that survives across runs |
sanitizeUserPrompt REST reference |
Screening provider text before a model reads it | |
| Model Armor through Agent Gateway | Where the guardrail sits in the request path | |
| ADK | ADK on Agent Platform | Running ADK agents on Google infrastructure |
| Multi-agent systems | How the orchestrator and specialists compose | |
| Function tools | The tool contract every agent call goes through | |
| Pause and resume | What a run parked on a missing credential relies on | |
| Safety and security | Guardrail patterns for tool-using agents | |
| adk-python | Source and samples | |
| Long-running agents that pause and resume | The checkpoint-and-wake pattern behind a parked run | |
| Sandbox | Install Agent Sandbox | Bringing the sandbox up on GKE |
| GKE network policy | The per-phase egress windows | |
| gVisor | The isolation boundary generated code runs on | |
| Observability | Agent Observability | What a fleet is expected to emit |
| Tracing on Agent Runtime | Trace configuration | |
| Instrument ADK with OpenTelemetry | Getting ADK spans into Cloud Trace | |
| Cloud Trace OTLP endpoint | One remediation, one trace |







Top comments (0)