OpenCode is an open programming agent that works in the terminal: reads project files, edits code, runs commands and tests, searches the repository and works with git. It is not tied to one model provider, so almost any OpenAI-compatible service can be connected to it.
FreeLLMAPI is an open self-hosted router that collects free plans from dozens of AI providers under one OpenAI-compatible /v1 address. Instead of thirty keys, thirty limits and thirty places where a request can fail, you have one local gateway and one unified key. The router itself selects an available model, switches to the next one when error 429 or 5xx occurs, and makes sure that requests do not exceed the quotas of free tariffs.
In this post I will describe installing FreeLLMAPI, adding providers and connecting the gateway to OpenCode.
What you need
To work you need four things:
- OpenCode installed. If the agent is not yet installed, I discussed the installation procedure in a separate note about OpenCode and DeepSeek.
- FreeLLMAPI running. The easiest way is to install a desktop application or Docker container.
- Node.js 20.18 or later. This is needed for the CLI generator that configures OpenCode. OpenCode itself can be installed without Node.
- Keys of at least one provider. Free plans of Google AI Studio, Groq, Cerebras, Mistral, OpenRouter, NVIDIA, HuggingFace and other services from the catalog are suitable.
Installing FreeLLMAPI
The project has several installation paths. Choose the one that is more convenient for your system.
Desktop application
The easiest option for Windows and macOS is the ready-made installer from the releases page. On Windows it is .exe, on macOS it is .dmg for Apple Silicon or Intel. The application lives in the tray and raises the router along with the control panel locally.
A password is not needed for the desktop version: the panel logs in on its own through a hidden local account. The only credentials you will need is the unified key from the tray pop-up window or from the Keys page header.
The application data is located in one directory:
- Windows — %APPDATA%\FreeLLMAPI\
- macOS — ~/Library/Application Support/FreeLLMAPI/
- Linux — ~/.config/FreeLLMAPI/
Docker
If Docker is already installed, the server is raised with one command. The script creates the ~/freellmapi directory, generates an encryption key, downloads the image and starts the container:
curl -fsSL https://freellmapi.co/install.sh | bash
Running the script again is safe: the .env file and encryption key are saved, and the container is updated to the latest version. On Windows, this method works in WSL or any bash environment.
After launch, the panel opens at:
http://localhost:3001
For server installation, you need to create an account with an email and password. If the password is forgotten, the reset code is printed in the container log:
docker compose logs -f freellmapi
Docker Compose
If you want to keep the configuration in git and manage the launch manually, regular Compose will do. On macOS and Linux:
git clone https://github.com/tashfeenahmed/freellmapi.git
cd freellmapi
ENCRYPTION_KEY="$(openssl rand -hex 32)"
printf "ENCRYPTION_KEY=%s\nPORT=3001\n" "$ENCRYPTION_KEY" > .env
docker compose up -d
In Windows PowerShell:
git clone https://github.com/tashfeenahmed/freellmapi.git
cd freellmapi
$Bytes = New-Object Byte[] 32
[Security.Cryptography.RandomNumberGenerator]::Create().GetBytes($Bytes)
$ENCRYPTION_KEY = -join ($Bytes | ForEach-Object { "{0:x2}" -f $_ })
"ENCRYPTION_KEY=$ENCRYPTION_KEY`nPORT=3001" | Out-File -Encoding utf8 .env
docker compose up -d
The ENCRYPTION_KEY key is required: it is used to encrypt provider keys in the SQLite database. You cannot change it on the fly – old secrets will no longer be decrypted. For rotation, the project has a separate command rotate-encryption-key.
Running from source
For development or debugging, you can run the project through Node.js:
git clone https://github.com/tashfeenahmed/freellmapi.git
cd freellmapi
npm install
ENCRYPTION_KEY="$(node -e 'console.log(require("crypto").randomBytes(32).toString("hex"))')"
printf "ENCRYPTION_KEY=%s\nPORT=3001\n" "$ENCRYPTION_KEY" > .env
npm run dev
In this mode, the API and panel are raised on port 3001, and the Vite interface is raised on 5173.
First launch and provider keys
Open the panel, go to the Keys page and add the keys of the services we use. For each provider, the interface has a link to registration and a hint where to get the key. It’s enough to start with one or two: for example, Google AI Studio and Groq.
Once added, the key undergoes a health check. If the provider responded with an error, the key will remain in the list, but will be marked as unhealthy – it can be checked again or deleted.
Next, you should go to the Models page and see what models are available. There you can also configure the routing strategy and the order of the Fallback Chain – the chain along which the router goes in the event of errors and limits. The auto model means that the choice is made by the router itself. In addition to it, options like auto:fast, auto:smart and named profiles for specific tasks are available.
It’s also worth checking that there are models in the chain that support tools. OpenCode actively uses tool calling, and a model without this feature will not be able to read files or run commands normally.
The Unified key is taken there, on the Keys page, or in the tray of the desktop application. It looks like a string with a prefix:
freellmapi-...
It is this key, and not the keys of individual providers, that is indicated in OpenCode.
Connect to OpenCode
FreeLLMAPI has a configuration generator that itself reads the model directory from the running gateway, makes a backup copy of the existing config and carefully adds the provider to it.
First, let’s set the unified key to the environment variable. The generator reads it instead of a separate flag, so the secret will not end up in the command history.
On macOS and Linux:
export FREELLMAPI_API_KEY=freellmapi-YOUR_KEY
In Windows PowerShell:
$env:FREELLMAPI_API_KEY="freellmapi-YOUR_KEY"
Now let’s see what exactly will be recorded:
npx freellmapi setup-opencode --url http://localhost:3001 --dry-run
If diff is satisfactory, repeat the command without the flag:
npx freellmapi setup-opencode --url http://localhost:3001
The generator writes the global OpenCode config:
~/.config/opencode/opencode.json
The freellmapi provider appears in it with the @ai-sdk/openai-compatible package, the base address http://localhost:3001/v1 and a map of models from the live catalog. The default model becomes freellmapi/auto.
The key itself does not end up in the file: the config contains the substitution {env:FREELLMAPI_API_KEY}. Therefore, the variable must remain set when the agent is started:
opencode
This method is also convenient because the secret does not end up in the config and will not end up in git. For CI and one-time runs, this is more correct than storing the key in a file.
Manual setting
If you don’t want to run the generator, you can manually describe the provider in opencode.json. The minimum option looks like this:
{
"$schema": "https://opencode.ai/config.json",
"model": "freellmapi/auto",
"provider": {
"freellmapi": {
"npm": "@ai-sdk/openai-compatible",
"name": "FreeLLMAPI",
"options": {
"baseURL": "http://localhost:3001/v1",
"apiKey": "{env:FREELLMAPI_API_KEY}"
},
"models": {
"auto": {
"name": "FreeLLMAPI Auto Router",
"limit": { "context": 1048576, "output": 65536 }
}
}
}
}
}
The model field at the top level is important: without it, OpenCode may continue to use the previous model or not select anything on a fresh installation. It is better to take the context and output limits from the gateway response, rather than invent them:
curl http://localhost:3001/v1/models
You can add specific identifiers to the models list if you need to switch to them manually. But for everyday work, auto is enough: the router itself will select a live model and switch when the limit is reached.
How to use it
After launching opencode, the list of models opens with a familiar command:
/models
It will have a FreeLLMAPI provider and an auto model. Then the work proceeds as usual: we describe the task, specify files via @, switch the planning mode with the Tab key, roll back the edits with the /undo command. For a new project, it is useful to run /init to have the agent create AGENTS.md.
A couple of practical tips:
- Routing. For routine, leave it at auto. If you need speed, try auto:fast, if the quality is auto:smart or a specific strong model from the catalog.
- Diagnostics Each gateway response contains an X-Routed-Via header with the name of the provider and model that actually served the request. It shows where the router sent the task.
- Analytics. On the Analytics page, the panel shows the volume of requests, success, p50/p95 delays and token consumption by provider.
- Continuity of dialogue. When switching models in the middle of a conversation, the gateway can add a short note about the transfer of context. Enabled by the variable FREELLMAPI_CONTEXT_HANDOFF=on_model_switch.
If OpenCode is running in a container and FreeLLMAPI is running on a host, localhost will point to the container itself. In this case, you need to use host.docker.internal or another address accessible from the container in the baseURL.
What to pay attention to
FreeLLMAPI is not a replacement for paid models and not a service with an SLA. It’s a way to bundle free plans into one neat gateway. Hence there are several restrictions:
- Quality fluctuates. Free tariffs end, and late in the evening, closer to the exhaustion of daily quotas, the router may switch to weaker models. Quotas usually reset at midnight UTC.
- Latencies are variable. Different providers respond differently, and when switching to a backup model, the request may take noticeably longer.
- There are no flagship models. Good, but not top-end, models are available in free plans. For complex architectures this is worth considering.
- The gateway must be running. If the application or container is stopped, OpenCode will not receive a response. Autostarting the application in the tray or restarting the container policy solves this problem.
- The project is designed for one user. Provider keys are stored locally and encrypted, but a shared panel for several people is not the scenario for this tool. The Unified key and .env should be protected in the same way as a regular secret.
And one more nuance: the model catalog updates itself, but the free installation receives a snapshot of the catalog with a delay of about thirty days. The Premium paid plan speeds up the update, but it is not needed to get acquainted with the project – the router itself remains free and open.
Links
https://github.com/tashfeenahmed/freellmapi
https://freellmapi.co/
https://freellmapi.co/models
https://github.com/tashfeenahmed/freellmapi/releases/latest
https://github.com/tashfeenahmed/freellmapi/blob/main/docs/en/install/01-install.md
https://github.com/tashfeenahmed/freellmapi/blob/main/docs/en/clients/01-agent-clients.md
https://github.com/tashfeenahmed/freellmapi/blob/main/cli/README.md
https://opencode.ai/
https://opencode.ai/docs/
https://opencode.ai/docs/providers/
Sources
https://github.com/tashfeenahmed/freellmapi
https://github.com/tashfeenahmed/freellmapi/blob/main/README.ru.md
https://github.com/tashfeenahmed/freellmapi/blob/main/docs/en/install/01-install.md
https://github.com/tashfeenahmed/freellmapi/blob/main/docs/en/clients/01-agent-clients.md
https://github.com/tashfeenahmed/freellmapi/blob/main/docs/en/clients/02-supported-agents.md
https://github.com/tashfeenahmed/freellmapi/blob/main/cli/README.md
https://opencode.ai/docs/providers/
Leave a Reply