A thin Google Cloud Vertex AI execution wrapper for Claude Code, plus a Claude Code plugin that delegates work to the Vertex-backed agent over the Agent Client Protocol (ACP).
gcvx does not reimplement anything Claude Code, the Claude Agent SDK, ACP,
acpx, or
claude-agent-acp
already provide. It only selects the provider (Vertex AI) and a default
model via environment variables, then hands off to the real tools. The one
exception is claude-teammate, which additionally rewrites --model on the
argv it was handed — the model a teammate runs cannot be held by environment
variables alone, because Claude Code passes it on argv and argv wins. The
whole runtime is two wrapper scripts, one plugin companion script, and three
command Markdown files.
gcvx init # initial local setup
gcvx doctor # read-only diagnostics (no model requests)
gcvx claude [...] # ordinary Claude Code CLI, backed by Vertex AI
gcvx claude-acp # ACP agent (claude-agent-acp), backed by Vertex AI
gcvx team [...] # Claude Code on your own provider, teammates on Vertex AI
Claude Code plugin commands:
/gcvx:rescue delegate investigation / fixing / implementation
/gcvx:review read-only review of the working tree or branch
/gcvx:adversarial-review challenge design direction and assumptions
The default model is fable, but it is configuration, not part of any
command name.
Direct interactive use:
gcvx claude
└── Vertex environment wrapper
└── ordinary claude CLI
└── Google Cloud Vertex AI
Split-provider teams (gcvx team):
gcvx team
└── ordinary claude CLI, on YOUR provider (e.g. a Claude subscription)
└── teammate spawned as a tmux pane
└── gcvx-teammate
└── Vertex environment wrapper + model policy
└── ordinary claude CLI
└── Google Cloud Vertex AI
Claude Code runs tmux-mode teammates as separate processes, so the leader and
its teammates can sit on different providers and credentials while keeping the
in-session teammate protocol intact — teammates still appear in the team list,
and SendMessage still reaches a running one. The leader deliberately keeps
your own provider; only teammates go to Vertex.
Requires tmux, and a leader started with gcvx team (the plain claude
command spawns in-process teammates, which necessarily share the leader's
provider).
Plugin delegation (ACP is used only at the plugin-to-agent boundary):
Claude Code parent session
└── /gcvx:rescue | /gcvx:review | /gcvx:adversarial-review
└── plugin/scripts/gcvx-companion
└── acpx --agent "gcvx claude-acp"
└── claude-agent-acp (Claude Agent SDK)
└── Google Cloud Vertex AI
Dependencies:
npm install -g @anthropic-ai/claude-code
npm install -g @agentclientprotocol/claude-agent-acp
npm install -g acpx
# and the gcloud CLI: https://cloud.google.com/sdk/docs/installInstall gcvx:
scripts/install.sh # preserves existing files; --force overwrites
gcvx init
gcvx doctorThis installs ~/.local/bin/gcvx and ~/.local/bin/gcvx-teammate, a
reference config example, and the plugin at ~/.local/share/gcvx/plugin.
Shell profiles are never modified. gcvx-teammate must stay beside gcvx:
it locates gcvx relative to its own path, and gcvx team refuses to start
without it.
Load the plugin in Claude Code:
claude --plugin-dir ~/.local/share/gcvx/pluginDuring development, point --plugin-dir at the plugin/ directory of this
repository instead.
gcvx init creates ~/.config/gcvx/config (never overwriting an existing
file). It is plain shell, sourced by the wrapper:
GCVX_GCP_PROJECT_ID="example-project" # required
GCVX_GCP_REGION="global" # default: global
GCVX_CLAUDE_MODEL="fable" # default: fable
# Teammates spawned by `gcvx team`:
GCVX_TEAMMATE_MODEL="claude-sonnet-5"
GCVX_TEAMMATE_ALLOWED_MODELS="sonnet claude-sonnet-5"
# Optional binary overrides:
#GCVX_CLAUDE_BIN="claude"
#GCVX_CLAUDE_ACP_BIN="claude-agent-acp"
#GCVX_ACPX_BIN="acpx"Google Cloud authentication uses Application Default Credentials:
gcloud auth application-default logingcvx claude is a transparent wrapper — every ordinary Claude Code option
and positional argument passes through unchanged, and stdin/stdout/stderr,
the working directory, signals, and the exit status are preserved:
gcvx claude
gcvx claude -p "Review this implementation"
gcvx claude --resume
gcvx claude --permission-mode plan
gcvx claude --model opus # overrides the configured defaultThe wrapper sets only CLAUDE_CODE_USE_VERTEX, ANTHROPIC_VERTEX_PROJECT_ID,
CLOUD_ML_REGION, and ANTHROPIC_MODEL in the launched process. Your
ordinary claude login and global settings are untouched, so subscription
and Vertex use coexist.
gcvx team starts a leader on your own provider and routes its teammates to
Vertex:
gcvx team
gcvx team --resume # options pass through to claudeTeammate model policy is enforced in gcvx claude-teammate, not in prose,
because Claude Code passes the leader's chosen model on the teammate's argv
and argv beats ANTHROPIC_MODEL. Environment pinning alone would let a leader
asking for an expensive model get it, billed to Vertex. A requested model
outside GCVX_TEAMMATE_ALLOWED_MODELS is rewritten to GCVX_TEAMMATE_MODEL
and a warning goes to stderr, which is visible in the teammate's pane. To let
teammates reach another model, add both its alias and its explicit id to the
allowlist — the leader may request either form.
Teammate processes outlive their tmux pane: killing the window or the tmux session leaves them running, and they must be terminated explicitly. Each teammate also pays a full session startup cost (system prompt, CLAUDE.md, skills) on its first request, so many short-lived teammates are more expensive than their task sizes suggest.
Plugin commands:
/gcvx:rescue investigate why the integration tests fail
/gcvx:rescue --background fix the race condition with the smallest safe patch
/gcvx:review
/gcvx:review --base main
/gcvx:adversarial-review challenge the authentication boundary
rescue is write-capable by default (acpx --approve-all). The review
commands run read-only (--approve-reads with non-read permissions denied)
and never apply fixes. --background uses Claude Code's native background
execution; there is no gcvx job manager.
tests/test.shThe suite uses fake executables and makes no network or model requests. It covers argument passthrough, stdio/cwd/exit-status preservation, the Vertex environment, ACP stdout purity, init/doctor behaviour, companion prompt selection, permission posture per mode, and shell-injection safety of task text.
- No Python package, daemon, database, custom job manager, session store, or generic backend framework.
- The single extension seam is ACP: replacing the agent later means changing
the companion's agent command (
gcvx claude-acp) and prompts only. gcvx claude-acpnever writes wrapper output to stdout; ACP owns it.
- ACP session resume through
/gcvx:rescue(--resume/--fresh). - Per-invocation model/effort flags for the plugin commands.
- Version-pinning
claude-agent-acp. /gcvx:status//gcvx:result//gcvx:canceljob commands — only if native background execution proves insufficient.- A separate read-only advisor command.
- Reverse invocation (a Vertex session launching a subscription-authenticated
claude); the wrapper already keeps this possible by touching only its own child process environment.