Skip to content

Instantly share code, notes, and snippets.

@wbern
Last active February 6, 2026 09:10
Show Gist options
  • Select an option

  • Save wbern/93afa23eaa07a684fd177a4f73ac4dad to your computer and use it in GitHub Desktop.

Select an option

Save wbern/93afa23eaa07a684fd177a4f73ac4dad to your computer and use it in GitHub Desktop.
Setup script for running Gemini through Claude Code Router
#!/bin/bash
# Setup script for running Gemini through Claude Code Router (macOS)
# https://github.com/wbern/claude-code-router
set -e
echo "πŸš€ Setting up Gemini for Claude Code..."
# Check if CCR is installed
if ! command -v ccr &> /dev/null; then
echo "❌ Claude Code Router (ccr) is not installed."
echo ""
echo "Install it first:"
echo " git clone https://github.com/wbern/claude-code-router.git ~/.claude-code-router/fork"
echo " cd ~/.claude-code-router/fork && pnpm install && pnpm build && pnpm link --global"
exit 1
fi
# Backup existing configs
backup_if_exists() {
if [ -f "$1" ]; then
BACKUP="$1.backup.$(date +%Y%m%d_%H%M%S)"
cp "$1" "$BACKUP"
echo "⚠️ Backed up existing $1 to $BACKUP"
fi
}
backup_if_exists ~/.claude-code-router/config.json
backup_if_exists ~/.claude-code-router/custom-router.js
backup_if_exists ~/.claude-gemini/settings.json
# Generate random API key for local router
APIKEY="ccr-local-$(openssl rand -hex 8)"
# Create directories
mkdir -p ~/.claude-gemini
mkdir -p ~/.claude-code-router/logs
# 1. Router config
cat > ~/.claude-code-router/config.json << EOF
{
"HOST": "127.0.0.1",
"PORT": 3456,
"APIKEY": "$APIKEY",
"CUSTOM_ROUTER_PATH": "$HOME/.claude-code-router/custom-router.js",
"Providers": [
{
"name": "gemini",
"api_base_url": "https://generativelanguage.googleapis.com/v1beta/models/",
"api_key": "FROM_KEYCHAIN",
"models": ["gemini-3-pro-preview", "gemini-3-flash-preview", "gemini-2.5-flash", "gemini-2.5-pro"],
"transformer": { "use": ["gemini"] }
}
],
"Router": {
"default": "gemini,gemini-3-pro-preview",
"background": "gemini,gemini-3-flash-preview",
"think": "gemini,gemini-3-pro-preview"
}
}
EOF
echo "βœ“ Created ~/.claude-code-router/config.json"
# 2. Custom router for summarization (fixes Gemini 3 Pro empty response issue)
# Gemini 3 Pro can return thinking-only responses during compaction, causing failures.
# This routes summarization requests to Flash which handles them reliably.
# See: https://discuss.ai.google.dev/t/gemini-3-0-pro-preview-with-empty-response-text/109818
cat > ~/.claude-code-router/custom-router.js << 'EOF'
// Custom router for claude-code-router
// Routes summarization/compaction requests to Gemini 2.5 Flash
// Gemini 3 Pro can return thinking-only responses (no text output) during summarization,
// causing Claude Code's compaction to fail. Flash handles these reliably.
// See: https://discuss.ai.google.dev/t/gemini-3-0-pro-preview-with-empty-response-text/109818
module.exports = async function router(req, config) {
const system = req.body.system || [];
const systemText = Array.isArray(system)
? system.map(s => s.text || "").join(" ")
: system;
// Detect Claude Code's summarization/compaction requests
// These prompts contain specific markers from the compact system prompt
const summarizationMarkers = [
"create a detailed summary",
"summarize this coding conversation",
"Primary Request and Intent",
"Key Technical Concepts",
"conversation so far"
];
const isSummarization = summarizationMarkers.some(marker =>
systemText.toLowerCase().includes(marker.toLowerCase())
);
if (isSummarization) {
console.log("[Custom Router] Detected summarization request, routing to Gemini 2.5 Flash");
return "gemini,gemini-2.5-flash";
}
// Return null to use default routing
return null;
};
EOF
echo "βœ“ Created ~/.claude-code-router/custom-router.js (routes summarization to Flash)"
# 3. Gemini settings with sandbox permissions
cat > ~/.claude-gemini/settings.json << EOF
{
"apiKeyHelper": "echo $APIKEY",
"includeCoAuthoredBy": false,
"statusLine": {
"type": "command",
"command": "~/.claude-gemini/statusline.sh"
},
"permissions": {
"allow": [],
"deny": [
"Read(**/.env)",
"Read(**/.env.*)",
"Read(**/secrets/**)",
"Read(**/*.pem)",
"Read(**/*.key)",
"Read(**/*credentials*)",
"Read(**/*secret*)",
"Read(**/apikey*)",
"Read(~/.ssh/**)",
"Read(~/.aws/**)",
"Read(~/.gnupg/**)",
"Read(~/.kube/**)",
"Read(~/.netrc)",
"Read(~/.git-credentials)",
"Read(~/.pypirc)",
"Read(~/.docker/**)",
"Read(~/.cargo/credentials*)",
"Read(~/.m2/**)",
"Read(~/.claude/**)",
"Read(~/Library/Keychains/**)",
"Read(~/Library/Cookies/**)",
"Read(~/Library/Accounts/**)",
"Read(~/Library/Mail/**)",
"Read(~/Library/Messages/**)",
"Read(~/Library/Preferences/**)",
"Read(~/Library/Safari/**)",
"Read(~/Library/Application Support/Google/Chrome/**)",
"Read(~/Library/Application Support/Firefox/**)",
"Read(~/Library/Application Support/Microsoft/Edge/**)",
"Read(~/Library/Application Support/1Password/**)",
"Read(~/Library/Saved Application State/**)",
"Bash(rm -rf:*)",
"Bash(rm -r:*)",
"Bash(sudo:*)",
"Bash(su:*)",
"Bash(chmod 777:*)",
"Bash(curl|sh)",
"Bash(wget|sh)",
"Bash(> /dev:*)",
"Bash(mkfs:*)",
"Bash(dd:*)"
]
},
"sandbox": {
"enabled": true,
"allowUnsandboxedCommands": true,
"network": {
"allowUnixSockets": ["/private/tmp/com.apple.launchd.*/Listeners"],
"allowLocalBinding": true
}
}
}
EOF
echo "βœ“ Created ~/.claude-gemini/settings.json"
# 4. Status line script (visual indicator)
cat > ~/.claude-gemini/statusline.sh << 'EOF'
#!/bin/bash
echo -e "\033[48;5;94m\033[97m πŸ€– GEMINI MODE \033[0m"
EOF
chmod +x ~/.claude-gemini/statusline.sh
echo "βœ“ Created ~/.claude-gemini/statusline.sh"
# 5. Symlink commands and plugins (if they exist)
if [ -d ~/.claude/commands ] && [ ! -e ~/.claude-gemini/commands ]; then
ln -s ~/.claude/commands ~/.claude-gemini/commands
echo "βœ“ Symlinked commands"
fi
if [ -d ~/.claude/plugins ] && [ ! -e ~/.claude-gemini/plugins ]; then
ln -s ~/.claude/plugins ~/.claude-gemini/plugins
echo "βœ“ Symlinked plugins"
fi
echo ""
echo "βœ… Setup complete!"
echo ""
echo "Next steps:"
echo ""
echo "1. Store your Gemini API key in macOS Keychain:"
echo " security add-generic-password -a \"\$USER\" -s gemini-api-key -w 'your-api-key-here'"
echo ""
echo " Get your key at: https://aistudio.google.com/apikey"
echo ""
echo "2. Add these aliases to your ~/.zshrc:"
echo ""
cat << 'ALIASES'
# Gemini via Claude Code Router
gemini() {
unset ANTHROPIC_AUTH_TOKEN
CLAUDE_CONFIG_DIR=~/.claude-gemini ANTHROPIC_BASE_URL=http://127.0.0.1:3456 claude "$@"
}
alias gr='gemini --resume'
alias gyolo='gemini --dangerously-skip-permissions'
alias gyolop='gemini --dangerously-skip-permissions -p'
alias gyolor='gemini --dangerously-skip-permissions --resume'
ALIASES
echo ""
echo "3. Start the router: ccr start &"
echo ""
echo "4. Launch Gemini: gyolo"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment