From 36829c3b93859c0a1761abc1c0fcd1bedd6e5a36 Mon Sep 17 00:00:00 2001 From: Ben Tossell Date: Tue, 17 Feb 2026 07:05:54 -0500 Subject: [PATCH 1/2] config: support Anthropic, OpenAI, Gemini, and OpenCode Zen providers - Add ANTHROPIC_API_KEY, OPENAI_API_KEY, GEMINI_API_KEY to .env.schema - OPENCODE_ZEN_API_KEY no longer required (any one provider suffices) - start.sh auto-detects provider and picks model: - Orchestration/coding: opus-4-6 / gpt-5.3-codex / gemini-3-pro - Triage (sentry): haiku-4-5 / gpt-5-mini / gemini-3-flash - install.sh prompts for all four providers - Remove hardcoded defaultProvider/defaultModel from settings.json - Update control-agent skill with model selection tables - Update CI simulated input for new prompt order --- .env.schema | 22 ++++++++++++--- CONFIGURATION.md | 18 +++++++++---- bin/ci/setup-arch.sh | 4 +-- bin/ci/setup-ubuntu.sh | 4 +-- install.sh | 46 +++++++++++++++++++++++++++++--- pi/settings.json | 2 -- pi/skills/control-agent/SKILL.md | 34 ++++++++++++++++++++++- start.sh | 16 ++++++++++- 8 files changed, 126 insertions(+), 20 deletions(-) diff --git a/.env.schema b/.env.schema index dbe236e..55617ed 100644 --- a/.env.schema +++ b/.env.schema @@ -9,10 +9,26 @@ # --- # ── LLM Access ─────────────────────────────────────────────────────────────── +# Set at least one. Multiple can coexist — switch models at runtime. -# API key for the LLM provider (Anthropic, OpenAI, or a proxy) -# @required @type=string -# @docs(https://docs.anthropic.com/en/api/getting-started) +# Anthropic API key (Claude models) +# @type=string(startsWith=sk-ant-) +# @docs(https://console.anthropic.com/settings/keys) +ANTHROPIC_API_KEY= + +# OpenAI API key (GPT, o-series models) +# @type=string(startsWith=sk-) +# @docs(https://platform.openai.com/api-keys) +OPENAI_API_KEY= + +# Google Gemini API key +# @type=string +# @docs(https://aistudio.google.com/apikey) +GEMINI_API_KEY= + +# OpenCode Zen API key (multi-provider router) +# @type=string +# @docs(https://opencode.ai) OPENCODE_ZEN_API_KEY= # ── GitHub ─────────────────────────────────────────────────────────────────── diff --git a/CONFIGURATION.md b/CONFIGURATION.md index 13e0fba..aa799c8 100644 --- a/CONFIGURATION.md +++ b/CONFIGURATION.md @@ -12,9 +12,14 @@ Baudbot uses [Varlock](https://varlock.dev) to validate environment variables at ### LLM Access -| Variable | Description | How to get it | -|----------|-------------|---------------| -| `OPENCODE_ZEN_API_KEY` | API key for the LLM provider | Your LLM provider dashboard (e.g. Anthropic, OpenAI, or a proxy like OpenCode Zen) | +Set at least one. Multiple can coexist — switch models at runtime via `/model`. + +| Variable | Provider | How to get it | +|----------|----------|---------------| +| `ANTHROPIC_API_KEY` | Anthropic (Claude) | [console.anthropic.com/settings/keys](https://console.anthropic.com/settings/keys) | +| `OPENAI_API_KEY` | OpenAI (GPT, o-series) | [platform.openai.com/api-keys](https://platform.openai.com/api-keys) | +| `GEMINI_API_KEY` | Google Gemini | [aistudio.google.com/apikey](https://aistudio.google.com/apikey) | +| `OPENCODE_ZEN_API_KEY` | OpenCode Zen (multi-provider router) | [opencode.ai](https://opencode.ai) | ### GitHub @@ -90,8 +95,11 @@ Set during `setup.sh` via env vars (or edit `~/.gitconfig` after): ## Example `.env` File ```bash -# LLM -OPENCODE_ZEN_API_KEY=sk-... +# LLM (set at least one) +ANTHROPIC_API_KEY=sk-ant-... +# OPENAI_API_KEY=sk-... +# GEMINI_API_KEY=... +# OPENCODE_ZEN_API_KEY=... # GitHub GITHUB_TOKEN=ghp_... diff --git a/bin/ci/setup-arch.sh b/bin/ci/setup-arch.sh index 36e4136..184a2c8 100755 --- a/bin/ci/setup-arch.sh +++ b/bin/ci/setup-arch.sh @@ -20,7 +20,7 @@ sudo -u baudbot_admin bash -c 'cd ~/baudbot && git init -q && git config user.em echo "=== Running install.sh ===" # Simulate interactive input: admin user, required secrets, skip optionals, decline launch -printf 'baudbot_admin\nsk-test-key\nghp_testtoken\nxoxb-test\nxapp-test\nU01TEST\n\n\n\n\n\nn\n' \ +printf 'baudbot_admin\nsk-ant-testkey\n\n\n\nghp_testtoken\nxoxb-test\nxapp-test\nU01TEST\n\n\n\n\n\nn\n' \ | bash /home/baudbot_admin/baudbot/install.sh echo "=== Verifying install ===" @@ -32,7 +32,7 @@ test "$(stat -c '%U' /home/baudbot_agent/.config/.env)" = "baudbot_agent" test -f /home/baudbot_agent/runtime/start.sh test -d /home/baudbot_agent/.pi/agent/extensions # Required secrets written -grep -q "OPENCODE_ZEN_API_KEY=sk-test-key" /home/baudbot_agent/.config/.env +grep -q "ANTHROPIC_API_KEY=sk-ant-testkey" /home/baudbot_agent/.config/.env grep -q "SLACK_BOT_TOKEN=xoxb-test" /home/baudbot_agent/.config/.env grep -q "BAUDBOT_SOURCE_DIR=" /home/baudbot_agent/.config/.env echo " ✓ install.sh verification passed" diff --git a/bin/ci/setup-ubuntu.sh b/bin/ci/setup-ubuntu.sh index 174b335..8fc3771 100755 --- a/bin/ci/setup-ubuntu.sh +++ b/bin/ci/setup-ubuntu.sh @@ -31,7 +31,7 @@ sudo -u baudbot_admin bash -c 'cd ~/baudbot && git init -q && git config user.em echo "=== Running install.sh ===" # Simulate interactive input: admin user, required secrets, skip optionals, decline launch -printf 'baudbot_admin\nsk-test-key\nghp_testtoken\nxoxb-test\nxapp-test\nU01TEST\n\n\n\n\n\nn\n' \ +printf 'baudbot_admin\nsk-ant-testkey\n\n\n\nghp_testtoken\nxoxb-test\nxapp-test\nU01TEST\n\n\n\n\n\nn\n' \ | bash /home/baudbot_admin/baudbot/install.sh echo "=== Verifying install ===" @@ -43,7 +43,7 @@ test "$(stat -c '%U' /home/baudbot_agent/.config/.env)" = "baudbot_agent" test -f /home/baudbot_agent/runtime/start.sh test -d /home/baudbot_agent/.pi/agent/extensions # Required secrets written -grep -q "OPENCODE_ZEN_API_KEY=sk-test-key" /home/baudbot_agent/.config/.env +grep -q "ANTHROPIC_API_KEY=sk-ant-testkey" /home/baudbot_agent/.config/.env grep -q "SLACK_BOT_TOKEN=xoxb-test" /home/baudbot_agent/.config/.env grep -q "BAUDBOT_SOURCE_DIR=" /home/baudbot_agent/.config/.env echo " ✓ install.sh verification passed" diff --git a/install.sh b/install.sh index da64f5b..373356c 100755 --- a/install.sh +++ b/install.sh @@ -237,10 +237,38 @@ prompt_secret() { echo -e "${BOLD}Required${RESET} ${DIM}(agent won't start without these)${RESET}" echo "" +echo -e "${BOLD}LLM provider${RESET} ${DIM}(set at least one)${RESET}" +echo "" + +prompt_secret "ANTHROPIC_API_KEY" \ + "Anthropic API key" \ + "https://console.anthropic.com/settings/keys" \ + "" \ + "sk-ant-" + +prompt_secret "OPENAI_API_KEY" \ + "OpenAI API key" \ + "https://platform.openai.com/api-keys" \ + "" \ + "sk-" + +prompt_secret "GEMINI_API_KEY" \ + "Google Gemini API key" \ + "https://aistudio.google.com/apikey" + prompt_secret "OPENCODE_ZEN_API_KEY" \ - "LLM API key (Anthropic/OpenAI)" \ - "https://docs.anthropic.com/en/api/getting-started" \ - "required" + "OpenCode Zen API key (multi-provider router)" \ + "https://opencode.ai" + +HAS_LLM_KEY=false +for k in ANTHROPIC_API_KEY OPENAI_API_KEY GEMINI_API_KEY OPENCODE_ZEN_API_KEY; do + if [ -n "${ENV_VARS[$k]:-}" ]; then HAS_LLM_KEY=true; break; fi +done +if [ "$HAS_LLM_KEY" = false ]; then + warn "No LLM key set — agent needs at least one to work" +fi + +echo "" prompt_secret "GITHUB_TOKEN" \ "GitHub personal access token" \ @@ -321,6 +349,9 @@ ENV_CONTENT="# Baudbot agent configuration # Write in a sensible order ordered_keys=( + ANTHROPIC_API_KEY + OPENAI_API_KEY + GEMINI_API_KEY OPENCODE_ZEN_API_KEY GITHUB_TOKEN SLACK_BOT_TOKEN @@ -358,7 +389,14 @@ header "Launch" # Check if we have the minimum required secrets MISSING="" -for key in OPENCODE_ZEN_API_KEY GITHUB_TOKEN SLACK_BOT_TOKEN SLACK_APP_TOKEN SLACK_ALLOWED_USERS; do +HAS_LLM=false +for k in ANTHROPIC_API_KEY OPENAI_API_KEY GEMINI_API_KEY OPENCODE_ZEN_API_KEY; do + if [ -n "${ENV_VARS[$k]:-}" ]; then HAS_LLM=true; break; fi +done +if [ "$HAS_LLM" = false ]; then + MISSING+=" - LLM key (ANTHROPIC_API_KEY, OPENAI_API_KEY, GEMINI_API_KEY, or OPENCODE_ZEN_API_KEY)\n" +fi +for key in GITHUB_TOKEN SLACK_BOT_TOKEN SLACK_APP_TOKEN SLACK_ALLOWED_USERS; do if [ -z "${ENV_VARS[$key]:-}" ]; then MISSING+=" - $key\n" fi diff --git a/pi/settings.json b/pi/settings.json index 453362c..59234d3 100644 --- a/pi/settings.json +++ b/pi/settings.json @@ -1,7 +1,5 @@ { "lastChangelogVersion": "0.52.12", - "defaultProvider": "opencode-zen", - "defaultModel": "claude-opus-4-6", "skills": [ "~/.pi/agent/skills" ], diff --git a/pi/skills/control-agent/SKILL.md b/pi/skills/control-agent/SKILL.md index 897603a..a00495b 100644 --- a/pi/skills/control-agent/SKILL.md +++ b/pi/skills/control-agent/SKILL.md @@ -150,6 +150,17 @@ If dev-agent reports repeated failures (e.g. CI failing after 3+ fix attempts, o ## Spawning a Dev Agent +Pick the model based on which API key is available (check env vars in this order): + +**Coding / orchestration (top-tier):** + +| API key | Model | +|---------|-------| +| `ANTHROPIC_API_KEY` | `anthropic/claude-opus-4-6` | +| `OPENAI_API_KEY` | `openai/gpt-5.2-codex` | +| `GEMINI_API_KEY` | `google/gemini-3-pro-preview` | +| `OPENCODE_ZEN_API_KEY` | `opencode-zen/claude-opus-4-6` | + Full procedure for spinning up a task-scoped dev agent: ```bash @@ -170,7 +181,7 @@ tmux new-session -d -s $SESSION_NAME \ "cd ~/workspace/worktrees/$BRANCH && \ export PATH=\$HOME/.varlock/bin:\$HOME/opt/node-v22.14.0-linux-x64/bin:\$PATH && \ export PI_SESSION_NAME=$SESSION_NAME && \ - exec varlock run --path ~/.config/ -- pi --session-control --skill ~/.pi/agent/skills/dev-agent" + exec varlock run --path ~/.config/ -- pi --session-control --skill ~/.pi/agent/skills/dev-agent --model " ``` **Important notes:** @@ -331,6 +342,27 @@ The script: **Note**: Dev agents are NOT started at startup. They are spawned on-demand when tasks arrive. +### Spawning sentry-agent + +The sentry-agent triages Sentry alerts and investigates critical issues via the Sentry API. It runs on a cheap model to save tokens. + +**Triage (cheap):** + +| API key | Model | +|---------|-------| +| `ANTHROPIC_API_KEY` | `anthropic/claude-haiku-4-5` | +| `OPENAI_API_KEY` | `openai/gpt-5-mini` | +| `GEMINI_API_KEY` | `google/gemini-3-flash-preview` | +| `OPENCODE_ZEN_API_KEY` | `opencode-zen/claude-haiku-4-5` | + +```bash +tmux new-session -d -s sentry-agent "export PATH=\$HOME/.varlock/bin:\$HOME/opt/node-v22.14.0-linux-x64/bin:\$PATH && export PI_SESSION_NAME=sentry-agent && varlock run --path ~/.config/ -- pi --session-control --skill ~/.pi/agent/skills/sentry-agent --model " +``` + +**Model note**: `github-copilot/*` models reject Personal Access Tokens and will fail in non-interactive sessions. + +The sentry-agent operates in **on-demand mode** — it does NOT poll. Sentry alerts arrive via the Slack bridge in real-time and are forwarded by you. The sentry-agent uses `sentry_monitor get ` to investigate when asked. + ### Starting the Slack Bridge The Slack bridge (Socket Mode) receives real-time Slack events and forwards them to this session via port 7890. diff --git a/start.sh b/start.sh index ed3a656..465d68f 100755 --- a/start.sh +++ b/start.sh @@ -36,6 +36,20 @@ umask 077 # Set session name (read by auto-name.ts extension) export PI_SESSION_NAME="control-agent" +# Pick model based on available API keys (first match wins) +if [ -n "${ANTHROPIC_API_KEY:-}" ]; then + MODEL="anthropic/claude-opus-4-6" +elif [ -n "${OPENAI_API_KEY:-}" ]; then + MODEL="openai/gpt-5.3-codex" +elif [ -n "${GEMINI_API_KEY:-}" ]; then + MODEL="google/gemini-3-pro-preview" +elif [ -n "${OPENCODE_ZEN_API_KEY:-}" ]; then + MODEL="opencode-zen/claude-opus-4-6" +else + echo "❌ No LLM API key found — set ANTHROPIC_API_KEY, OPENAI_API_KEY, GEMINI_API_KEY, or OPENCODE_ZEN_API_KEY" + exit 1 +fi + # Start control-agent # --session-control: enables inter-session communication (handled by control.ts extension) -pi --session-control --skill ~/.pi/agent/skills/control-agent "/skill:control-agent" +pi --session-control --model "$MODEL" --skill ~/.pi/agent/skills/control-agent "/skill:control-agent" From ac3b8e6cbab549f752a22868606b912e1db0a26c Mon Sep 17 00:00:00 2001 From: Ben Tossell Date: Tue, 17 Feb 2026 07:10:43 -0500 Subject: [PATCH 2/2] config: use gpt-5.2-codex (5.3 not available via API key yet) --- start.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/start.sh b/start.sh index 465d68f..7144281 100755 --- a/start.sh +++ b/start.sh @@ -40,7 +40,7 @@ export PI_SESSION_NAME="control-agent" if [ -n "${ANTHROPIC_API_KEY:-}" ]; then MODEL="anthropic/claude-opus-4-6" elif [ -n "${OPENAI_API_KEY:-}" ]; then - MODEL="openai/gpt-5.3-codex" + MODEL="openai/gpt-5.2-codex" elif [ -n "${GEMINI_API_KEY:-}" ]; then MODEL="google/gemini-3-pro-preview" elif [ -n "${OPENCODE_ZEN_API_KEY:-}" ]; then