If you use a terminal coding agent every day, one practical problem shows up quickly: how do you keep model access reproducible, project-friendly, and easy to verify without changing the way you work?
OpenCode is a terminal-first coding agent from the SST team. It can read code, modify files, run commands, explain errors, and help with day-to-day development tasks from your shell. The useful part for builders is that OpenCode supports custom model providers, so you can point it at an OpenAI-compatible endpoint while keeping the normal opencode command and TUI workflow.
This guide walks through configuring OpenCode to use Ace Data Cloud as a custom provider through its OpenAI Chat Completions-compatible proxy.
What you can do
After the setup, your workflow stays familiar:
- run
opencodeinside a project and choose a model from/models - run one-off tasks with
opencode run - keep your API token out of the JSON config by using an environment variable
- expose only the model IDs you want OpenCode to use
- use either a global config or a project-level config depending on the repository
The key values from the source guide are:
- Base URL:
https://api.acedata.cloud/v1 - Chat Completions endpoint used under the hood:
https://api.acedata.cloud/v1/chat/completions - Provider key used in the example:
provider.acedatacloud - API token environment variable:
ACEDATACLOUD_API_KEY - Authorization format:
Authorization: Bearer <token> - Model name format in OpenCode:
acedatacloud/<model>
How it works
OpenCode reads opencode.json at startup. The documented load order is:
- global config:
~/.config/opencode/opencode.json - a custom config file pointed to by
OPENCODE_CONFIG - project config:
opencode.jsonin the project root, up to the Git root
Later config overrides earlier config. That makes it reasonable to keep a safe global provider definition and still customize models for a specific repository.
For this integration, OpenCode uses the Vercel AI SDK adapter @ai-sdk/openai-compatible. When you select a model such as acedatacloud/gpt-5-mini, OpenCode resolves the acedatacloud provider block, reads options.baseURL, resolves {env:ACEDATACLOUD_API_KEY}, and sends an OpenAI Chat Completions-format request to /v1/chat/completions with a bearer token.
No local proxy process is required. No wrapper CLI is required. You still run OpenCode normally; the configuration changes only the underlying API target and model list.
Install OpenCode
OpenCode supports macOS, Linux, Windows, and WSL. On macOS, Linux, or WSL, the guide lists this one-line installer:
curl -fsSL https://opencode.ai/install | bash
If you prefer package managers, the documented alternatives are:
brew install sst/tap/opencode
npm install -g opencode-ai
On Windows, you can use:
winget install sst.opencode
After installing, reopen your terminal and verify the command is available:
opencode --version
If you see command not found, the current shell probably has not loaded the new PATH yet. Close and reopen the terminal. On macOS with Homebrew, you can also check the binary path with which opencode.
Keep the token out of your config file
First, put your Ace Data Cloud API token into an environment variable:
export ACEDATACLOUD_API_KEY="{token}"
Replace {token} with the token from your console. Put the line in ~/.zshrc, ~/.bashrc, or ~/.bash_profile, then reload it:
source ~/.zshrc
A subtle issue: if your token lives in a .env file as ACEDATACLOUD_API_KEY=... without export, a plain source .env only creates a shell variable. Child processes such as OpenCode may not see it. Use this instead:
set -a && source .env && set +a
The goal is for OpenCode to resolve {env:ACEDATACLOUD_API_KEY} when it starts.
Register Ace Data Cloud as a provider
Create the global config file if it does not exist:
mkdir -p ~/.config/opencode
touch ~/.config/opencode/opencode.json
Then add a provider block like this:
{
"$schema": "https://opencode.ai/config.json",
"provider": {
"acedatacloud": {
"npm": "@ai-sdk/openai-compatible",
"name": "Ace Data Cloud",
"options": {
"baseURL": "https://api.acedata.cloud/v1",
"apiKey": "{env:ACEDATACLOUD_API_KEY}"
},
"models": {
"claude-sonnet-4-6": { "name": "Claude Sonnet 4.6" },
"claude-haiku-4-5-20251001": { "name": "Claude Haiku 4.5" },
"claude-opus-4-7": { "name": "Claude Opus 4.7" },
"gpt-5": { "name": "GPT-5" },
"gpt-5-mini": { "name": "GPT-5 mini" },
"gemini-2.5-pro": { "name": "Gemini 2.5 Pro" },
"deepseek-v3.2-exp": { "name": "DeepSeek V3.2 Exp" }
}
}
}
}
The important pieces are provider.acedatacloud as the local provider ID, @ai-sdk/openai-compatible as the adapter, https://api.acedata.cloud/v1 as the base URL, and {env:ACEDATACLOUD_API_KEY} as the token placeholder. The models object is the list OpenCode exposes under the provider.
Verify and run a smoke test
List the registered models:
opencode models acedatacloud
With the example config, the output should include:
acedatacloud/claude-haiku-4-5-20251001
acedatacloud/claude-opus-4-7
acedatacloud/claude-sonnet-4-6
acedatacloud/deepseek-v3.2-exp
acedatacloud/gemini-2.5-pro
acedatacloud/gpt-5
acedatacloud/gpt-5-mini
Now run a simple one-off task:
opencode run --model acedatacloud/claude-sonnet-4-6 "Reply: Hello from AceData via OpenCode."
The documented test output is:
> build · claude-sonnet-4-6
Hello from AceData via OpenCode.
For interactive work, move into a project and start the TUI:
cd /path/to/your/project
opencode
Then use /models to pick a configured model.
Troubleshooting notes
If opencode models acedatacloud does not show your provider, OpenCode probably did not read the config file. Restart the TUI after edits, or run with --print-logs --log-level INFO and check which config path is loaded.
If you get 401 Unauthorized, check that ACEDATACLOUD_API_KEY is exported in the current shell. If opencode debug config shows "Authorization": "Bearer ", the placeholder resolved to an empty value.
If OpenCode reports Model not found: acedatacloud/..., make sure that model ID is present as a key under provider.acedatacloud.models.
For MCP-heavy sessions, the guide notes that OpenAI-series models such as gpt-5 or gpt-5-mini are a good first choice when many MCP tools are mounted, while Claude models work normally for plain conversation.
If you want the full reference, read the original OpenCode Terminal Setup Guide.

Top comments (1)
The distinction between a shell variable and an exported
ACEDATACLOUD_API_KEYis the most operationally useful part here; seeingAuthorization: Bearerinopencode debug configturns a vague 401 into a specific failure. I'd add one verification layer afteropencode models acedatacloud: run a tiny request through each model you actually expose, because a locally registered ID proves the config loaded, not that the upstream route supports that model and response shape. Keeping a conservative global provider block and narrower project-level model lists also gives teams a clean tradeoff between convenience and reproducibility.