Skip to content

Instantly share code, notes, and snippets.

@flore2003
Last active March 19, 2026 23:29
Show Gist options
  • Select an option

  • Save flore2003/cd05d90a772564eecc16547537d77dcd to your computer and use it in GitHub Desktop.

Select an option

Save flore2003/cd05d90a772564eecc16547537d77dcd to your computer and use it in GitHub Desktop.
Claude Code on Google Vertex AI

gclaude — Claude Code on Google Vertex AI

This gist contains setup-gclaude.sh, a small installer that:

  • Writes ~/.config/gclaude/env with your GCP project, region, and service-account key path
  • Installs gclaude to ~/.local/bin, a wrapper around the claude CLI with Vertex AI enabled (CLAUDE_CODE_USE_VERTEX=1, etc.)

You run gclaude the same way you would claude; authentication uses a service account JSON key (not the Anthropic API key flow).

Docs: Claude Code on Google Vertex AI

Install

curl -fsSL 'https://bit.ly/4sWf5Ua' | bash

(That short link redirects to the raw setup-gclaude.sh on gist.github.com.)

Ensure ~/.local/bin is on your PATH if the script reminds you to add it.

What you need

  • Claude Code (claude on your PATH)
  • Python 3 (to validate the JSON key)
  • A GCP project with Vertex AI / Claude access, and a service account key JSON with something like roles/aiplatform.user

The script will ask for your project ID, region (default global), and how to provide the key (file path, paste, or macOS clipboard).

After setup

gclaude

Same flags and behavior as claude, using Vertex via your saved config.

#!/usr/bin/env bash
# Interactive bootstrap for gclaude (Claude Code + Vertex AI).
# Run: bash setup-gclaude.sh
# Remote: curl -fsSL 'RAW_URL' | bash
# Prompts use /dev/tty so keyboard input works even when stdin is the script pipe.
# See GIST.md for gist.github.com.
# Docs: https://code.claude.com/docs/en/google-vertex-ai
set -euo pipefail
CONFIG_DIR="${XDG_CONFIG_HOME:-$HOME/.config}/gclaude"
LOCAL_BIN="${HOME}/.local/bin"
KEY_FILE="${CONFIG_DIR}/gcp-key.json"
ENV_FILE="${CONFIG_DIR}/env"
GCLAUDE_BIN="${LOCAL_BIN}/gclaude"
die() {
echo "setup-gclaude: $*" >&2
exit 1
}
# Read from /dev/tty so prompts work when stdin is a pipe (e.g. curl | bash).
read_tty() {
read -r "$@" </dev/tty
}
validate_json_file() {
python3 -c 'import json, sys; json.load(open(sys.argv[1], encoding="utf-8"))' "$1" ||
die "invalid JSON: $1"
}
prompt_yes() {
local reply
read_tty -p "$1 [y/N] " reply
case "${reply}" in
[yY]|[yY][eE][sS]) return 0 ;;
*) return 1 ;;
esac
}
echo "=== gclaude bootstrap ==="
echo
read_tty -p "GCP project ID (ANTHROPIC_VERTEX_PROJECT_ID): " PROJECT_ID
[[ -n "${PROJECT_ID}" ]] || die "project ID is required"
read_tty -p "Vertex region [global]: " REGION
REGION="${REGION:-global}"
echo
echo "Service account JSON key — choose how to provide it:"
echo " 1) Path to a file on disk (recommended)"
echo " 2) Paste in this terminal (full JSON; end with Ctrl-D, often twice if the cursor is mid-line)"
if command -v pbpaste >/dev/null 2>&1; then
echo " 3) Use macOS clipboard (copy the JSON in another app first, then choose 3)"
fi
read_tty -p "Choice [1]: " KEY_MODE
KEY_MODE="${KEY_MODE:-1}"
mkdir -p "${CONFIG_DIR}"
case "${KEY_MODE}" in
1)
read_tty -p "Absolute path to JSON key file: " KEY_PATH
[[ -n "${KEY_PATH}" ]] || die "path is required for option 1"
[[ -f "${KEY_PATH}" ]] || die "file not found: ${KEY_PATH}"
cp "${KEY_PATH}" "${KEY_FILE}"
;;
2)
echo
echo "Paste the entire JSON key below, then press Ctrl-D to finish."
# Read from /dev/tty so a multi-line paste is never split across bash \`read\` + \`cat\`, and Ctrl-D ends input on the terminal.
python3 - "${KEY_FILE}" <<'PY'
import sys
path = sys.argv[1]
try:
with open("/dev/tty", encoding="utf-8", errors="replace") as tty:
data = tty.read()
except OSError:
# No controlling tty (e.g. CI); read pasted input from stdin instead.
data = sys.stdin.read()
if not data.strip():
print("setup-gclaude: no key content received (empty after Ctrl-D)", file=sys.stderr)
sys.exit(1)
open(path, "w", encoding="utf-8").write(data)
PY
;;
3)
command -v pbpaste >/dev/null 2>&1 || die "pbpaste not available; use option 1 or 2"
pbpaste >"${KEY_FILE}" || die "pbpaste failed"
;;
*)
die "invalid choice: ${KEY_MODE}"
;;
esac
validate_json_file "${KEY_FILE}"
chmod 600 "${KEY_FILE}"
if [[ -f "${ENV_FILE}" ]] && ! prompt_yes "Overwrite existing ${ENV_FILE}?"; then
die "aborted"
fi
mkdir -p "${CONFIG_DIR}"
{
echo '# Generated by setup-gclaude.sh — https://code.claude.com/docs/en/google-vertex-ai'
printf 'ANTHROPIC_VERTEX_PROJECT_ID=%q\n' "${PROJECT_ID}"
printf 'GOOGLE_APPLICATION_CREDENTIALS=%q\n' "${KEY_FILE}"
printf 'CLOUD_ML_REGION=%q\n' "${REGION}"
} >"${ENV_FILE}"
chmod 600 "${ENV_FILE}"
if [[ -f "${GCLAUDE_BIN}" ]] && ! prompt_yes "Overwrite existing ${GCLAUDE_BIN}?"; then
die "aborted before installing gclaude"
fi
mkdir -p "${LOCAL_BIN}"
cat >"${GCLAUDE_BIN}" <<'GCLAUDE'
#!/usr/bin/env bash
# Thin wrapper: run Claude Code against Vertex AI with sane defaults.
# Docs: https://code.claude.com/docs/en/google-vertex-ai
set -euo pipefail
gclaude_load_env_file() {
local path="$1"
if [[ -f "$path" ]]; then
set -a
# shellcheck disable=SC1090
source "$path"
set +a
fi
}
if [[ -n "${GCLAUDE_ENV_FILE:-}" ]]; then
gclaude_load_env_file "${GCLAUDE_ENV_FILE}"
else
gclaude_load_env_file "${XDG_CONFIG_HOME:-$HOME/.config}/gclaude/env"
fi
export CLAUDE_CODE_USE_VERTEX=1
export CLOUD_ML_REGION="${CLOUD_ML_REGION:-global}"
if [[ -n "${GCLAUDE_GOOGLE_APPLICATION_CREDENTIALS:-}" ]]; then
export GOOGLE_APPLICATION_CREDENTIALS="${GCLAUDE_GOOGLE_APPLICATION_CREDENTIALS}"
fi
CLAUDE_BIN="${GCLAUDE_CLAUDE_BIN:-claude}"
if ! command -v "${CLAUDE_BIN}" >/dev/null 2>&1; then
echo "gclaude: '${CLAUDE_BIN}' not found on PATH. Install Claude Code or set GCLAUDE_CLAUDE_BIN." >&2
exit 127
fi
if [[ -z "${ANTHROPIC_VERTEX_PROJECT_ID:-}" ]]; then
echo "gclaude: set ANTHROPIC_VERTEX_PROJECT_ID (GCP project ID)." >&2
echo " Tip: run setup-gclaude.sh or edit ~/.config/gclaude/env" >&2
exit 1
fi
if [[ -z "${GOOGLE_APPLICATION_CREDENTIALS:-}" ]]; then
echo "gclaude: set GOOGLE_APPLICATION_CREDENTIALS to your service account JSON key path," >&2
echo " or set GCLAUDE_GOOGLE_APPLICATION_CREDENTIALS to the same path." >&2
exit 1
fi
if [[ ! -f "${GOOGLE_APPLICATION_CREDENTIALS}" ]]; then
echo "gclaude: credentials file not found: ${GOOGLE_APPLICATION_CREDENTIALS}" >&2
exit 1
fi
exec "${CLAUDE_BIN}" "$@"
GCLAUDE
chmod +x "${GCLAUDE_BIN}"
echo
echo "Done."
echo " Config: ${ENV_FILE}"
echo " Key: ${KEY_FILE}"
echo " CLI: ${GCLAUDE_BIN}"
echo
if [[ ":${PATH}:" != *":${LOCAL_BIN}:"* ]]; then
echo "Add ~/.local/bin to PATH, e.g. in ~/.zshrc:"
echo " export PATH=\"\${HOME}/.local/bin:\${PATH}\""
echo
fi
echo "Run: gclaude (same arguments as claude)"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment