ML-workflow tasks run with --repo-mode use the opencode
CLI for multi-file repo edits via understand_repo and edit_repo. opencode
talks to an LLM provider directly (it doesn't go through clients/cortex.py),
so it needs its own credentials.
opencode's built-in anthropic provider expects:
- The Anthropic-style header
x-api-key: <key>. - Standard upstream model IDs (e.g.
claude-sonnet-4-5-20250929).
Snowflake Cortex's Anthropic-compatible endpoint expects:
Authorization: Bearer <token>(Cortex PAT).- Renamed model IDs (e.g.
claude-sonnet-4-6).
Neither side natively understands the other. The fix below configures opencode
to send Bearer auth and to know about Cortex's renamed models, while pointing
its baseURL at the Cortex endpoint.
-
Make sure your
.envis sourced in the shell (soANTHROPIC_BASE_URLandANTHROPIC_AUTH_TOKENare exported). -
Run the helper that generates
~/.config/opencode/opencode.json:bash scripts/setup_opencode.sh
This writes a global opencode config that:
- Points
anthropicprovider'sbaseURLat${ANTHROPIC_BASE_URL}/v1. - Sets
Authorization: Bearer ${ANTHROPIC_AUTH_TOKEN}via theheadersoption. - Registers Cortex's renamed model IDs (
claude-sonnet-4-6,claude-opus-4-7,claude-haiku-4-5) under theanthropicprovider.
- Points
-
Verify it works:
./opencode/opencode run "say hi" \ -m anthropic/claude-sonnet-4-6 --format json | tail -3
You should see a
step_finishevent with a non-zero token count and no error.
Once the global config is in place, repo_mode tasks work like other ml_workflow tasks:
CUDA_VISIBLE_DEVICES=0 python3 run.py \
--task nanogpt \
--repo-mode \
--agent-model-id claude-sonnet-4-6 \
--branch-tag <tag> \
--max-agent-turns 1000 \
--enable-search-review \
--exp-name <name>The agent's tool surface will swap edit_train_file → edit_repo and
get_current_code → understand_repo, both backed by core/opencode.py
which shells out to the opencode CLI.
-
ProviderModelNotFoundError: opencode rejects the model name. Fix: ensure the model ID is registered underprovider.anthropic.modelsin~/.config/opencode/opencode.json. -
401 Unauthorized(Cortex): Bearer token missing or expired. Fix: refreshANTHROPIC_AUTH_TOKENin.env, re-runscripts/setup_opencode.sh. -
404 Not Foundon/messages:baseURLis missing the/v1suffix. The Cortex endpoint is at${ANTHROPIC_BASE_URL}/v1/messages, so the configuredbaseURLmust end in/v1. -
403 AccessDenied with
bedrock:InvokeModelWithResponseStream: opencode is hitting AWS Bedrock instead of Cortex. Check that_PROVIDER_TO_OPENCODEincore/opencode.pymapscortex → anthropic, and that the global config exists.
The Cortex PAT is embedded in ~/.config/opencode/opencode.json. To rotate:
- Update
ANTHROPIC_AUTH_TOKENin.env. - Re-run
scripts/setup_opencode.sh(it overwrites the global config).
Don't commit ~/.config/opencode/opencode.json to git — it contains the
secret.