OpenCode Agent setup
OpenCode is an open-source coding agent for understanding projects, editing files, and running development tasks from a terminal, desktop app, or IDE. All three surfaces use the OpenCode configuration system, but only the CLI has a true process-scoped setup.
Install OpenCode first, then create a Lumoswitch API configuration with OpenAI-compatible output.
Choose a setup method
| Method | Best for | Local writes | Still active after exit? |
|---|---|---|---|
| One-time launch | Testing a URL, Key, or model in the CLI | No OpenCode configuration | No |
| Persistent use | Everyday terminal use | Agent-supported config path + optional launcher | Yes |
| Desktop / IDE | Using OpenCode graphically | Merged global configuration and a dedicated Key file | Yes |
Desktop and IDE have no equivalent one-time command: they are not started by the current shell process and read global configuration instead. Removal instructions are included below.
Prepare the connection values
| Placeholder | Value |
|---|---|
{{api_base_url}} | The downstream API URL, including /v1 |
{{access_key}} | The Lumoswitch Access Key selected for this configuration |
{{model}} | The client-facing model name, not the upstream model ID |
{{opencode_config_json}} | Complete OpenCode config generated from effective reasoning capabilities |
One-time launch
Run this in the project directory where you want to use OpenCode:
LUMOSWITCH_OPENCODE_CONFIG='{{opencode_config_json}}'
env \
LUMOSWITCH_OPENCODE_API_KEY="{{access_key}}" \
OPENCODE_CONFIG_CONTENT="$LUMOSWITCH_OPENCODE_CONFIG" \
opencodeThe configuration is passed only to this OpenCode process. It does not change user- or project-level opencode.json, expires on exit, and does not require /connect first.
Persistent use
Run the complete command during initial setup and whenever the URL, Access Key, or model changes. It writes an OpenCode-supported dedicated configuration and managed environment without altering existing settings, then saves an optional Lumoswitch maintenance launcher.
Persistent import stores the Access Key in an owner-only managed environment or Agent configuration file. Use it only on a trusted personal device.
set -e
LUMOSWITCH_ROOT="$HOME/.config/lumoswitch/agents/opencode"
LUMOSWITCH_ENV="$LUMOSWITCH_ROOT/env.sh"
LUMOSWITCH_LAUNCHER="$HOME/.local/bin/lumoswitch-opencode"
mkdir -p "$LUMOSWITCH_ROOT" "$(dirname "$LUMOSWITCH_LAUNCHER")"
umask 077
if [ -f "$LUMOSWITCH_LAUNCHER" ]; then
LUMOSWITCH_BACKUP="$LUMOSWITCH_LAUNCHER.backup.$(date +%Y%m%d-%H%M%S)-$$"
cp "$LUMOSWITCH_LAUNCHER" "$LUMOSWITCH_BACKUP"
chmod 600 "$LUMOSWITCH_BACKUP"
fi
LUMOSWITCH_OPENCODE_CONFIG="$LUMOSWITCH_ROOT/opencode.json"
printf '%s\n' '{{opencode_config_json}}' > "$LUMOSWITCH_OPENCODE_CONFIG"
cat > "$LUMOSWITCH_ENV" <<'LUMOSWITCH_ENV_EOF'
export OPENCODE_CONFIG="$HOME/.config/lumoswitch/agents/opencode/opencode.json"
export LUMOSWITCH_OPENCODE_API_KEY="{{access_key}}"
LUMOSWITCH_ENV_EOF
case "$SHELL" in
*/zsh) LUMOSWITCH_PROFILE="$HOME/.zshrc" ;;
*/bash) LUMOSWITCH_PROFILE="$HOME/.bashrc" ;;
*) LUMOSWITCH_PROFILE="$HOME/.profile" ;;
esac
touch "$LUMOSWITCH_PROFILE"
LUMOSWITCH_PROFILE_MARKER='# Lumoswitch Agent: opencode'
LUMOSWITCH_SOURCE_LINE='[ -f "$HOME/.config/lumoswitch/agents/opencode/env.sh" ] && . "$HOME/.config/lumoswitch/agents/opencode/env.sh"'
if ! grep -Fqx "$LUMOSWITCH_SOURCE_LINE" "$LUMOSWITCH_PROFILE"; then
printf '\n%s\n%s\n' "$LUMOSWITCH_PROFILE_MARKER" "$LUMOSWITCH_SOURCE_LINE" >> "$LUMOSWITCH_PROFILE"
fi
printf '%s\n' "$LUMOSWITCH_PROFILE" > "$LUMOSWITCH_ROOT/profile-path"
cat > "$LUMOSWITCH_LAUNCHER" <<'LUMOSWITCH_LAUNCHER_EOF'
#!/usr/bin/env bash
set -e
LUMOSWITCH_ROOT="$HOME/.config/lumoswitch/agents/opencode"
LUMOSWITCH_ENV="$LUMOSWITCH_ROOT/env.sh"
LUMOSWITCH_LAUNCHER="$HOME/.local/bin/lumoswitch-opencode"
if [ "$1" = "--lumoswitch-clean" ]; then
if [ -f "$LUMOSWITCH_ROOT/profile-path" ]; then
LUMOSWITCH_PROFILE="$(cat "$LUMOSWITCH_ROOT/profile-path")"
if [ -f "$LUMOSWITCH_PROFILE" ]; then
LUMOSWITCH_PROFILE_MARKER='# Lumoswitch Agent: opencode'
LUMOSWITCH_SOURCE_LINE='[ -f "$HOME/.config/lumoswitch/agents/opencode/env.sh" ] && . "$HOME/.config/lumoswitch/agents/opencode/env.sh"'
LUMOSWITCH_PROFILE_TMP="$LUMOSWITCH_PROFILE.lumoswitch.$$"
awk -v marker="$LUMOSWITCH_PROFILE_MARKER" -v source="$LUMOSWITCH_SOURCE_LINE" '$0 != marker && $0 != source' "$LUMOSWITCH_PROFILE" > "$LUMOSWITCH_PROFILE_TMP"
mv "$LUMOSWITCH_PROFILE_TMP" "$LUMOSWITCH_PROFILE"
fi
fi
if [ -d "$LUMOSWITCH_ROOT" ]; then
find "$LUMOSWITCH_ROOT" -depth \( -type f -o -type l \) -delete
find "$LUMOSWITCH_ROOT" -depth -type d -exec rmdir {} \; 2>/dev/null || true
fi
find "$(dirname "$LUMOSWITCH_LAUNCHER")" -maxdepth 1 -type f -name 'lumoswitch-opencode.backup.*' -delete
rm -f "$LUMOSWITCH_LAUNCHER"
printf '%s\n' 'Lumoswitch native setup and optional launcher removed. Open a new terminal to refresh the environment.'
exit 0
fi
if [ -f "$LUMOSWITCH_ENV" ]; then . "$LUMOSWITCH_ENV"; fi
exec opencode "$@"
LUMOSWITCH_LAUNCHER_EOF
chmod 600 "$LUMOSWITCH_ENV"
find "$LUMOSWITCH_ROOT" -type f -exec chmod 600 {} \;
chmod 700 "$LUMOSWITCH_LAUNCHER"
. "$LUMOSWITCH_ENV"
printf '%s\n' 'Native Lumoswitch setup saved. Future command: opencode'
printf '%s\n' 'Optional maintenance launcher: ~/.local/bin/lumoswitch-opencode'
opencodeFor everyday use, run:
opencodeNative Windows PowerShell import
These commands run natively in Windows PowerShell without WSL and use the same connection values as the macOS/Linux templates on this page.
One-time use on Windows
& {
$ErrorActionPreference = 'Stop'
$lumoswitchConfigContent = @'
{{opencode_config_json}}
'@
$lumoswitchEnvironmentNames = @('LUMOSWITCH_OPENCODE_API_KEY', 'OPENCODE_CONFIG_CONTENT')
$lumoswitchPreviousEnvironment = @{}
foreach ($lumoswitchName in $lumoswitchEnvironmentNames) {
$lumoswitchPreviousEnvironment[$lumoswitchName] = [Environment]::GetEnvironmentVariable($lumoswitchName, 'Process')
}
$lumoswitchExitCode = 0
try {
[Environment]::SetEnvironmentVariable('LUMOSWITCH_OPENCODE_API_KEY', '{{access_key}}', 'Process')
[Environment]::SetEnvironmentVariable('OPENCODE_CONFIG_CONTENT', $lumoswitchConfigContent, 'Process')
$lumoswitchArguments = @()
$lumoswitchExecutable = Get-Command 'opencode.cmd' -CommandType Application -ErrorAction SilentlyContinue
if ($null -eq $lumoswitchExecutable) { $lumoswitchExecutable = Get-Command 'opencode' -CommandType Application -ErrorAction Stop }
& $lumoswitchExecutable.Path @lumoswitchArguments
if ($null -ne $LASTEXITCODE) { $lumoswitchExitCode = $LASTEXITCODE }
} finally {
foreach ($lumoswitchName in $lumoswitchEnvironmentNames) {
[Environment]::SetEnvironmentVariable($lumoswitchName, $lumoswitchPreviousEnvironment[$lumoswitchName], 'Process')
}
}
if ($lumoswitchExitCode -ne 0) { throw 'opencode exited with code ' + $lumoswitchExitCode }
}Persistent use on Windows
This command backs up existing Lumoswitch-owned files and restricts access to the configuration and launcher for the current user.
& {
$ErrorActionPreference = 'Stop'
$lumoswitchRoot = Join-Path $env:LOCALAPPDATA 'Lumoswitch\agents\opencode'
$lumoswitchLauncher = Join-Path $env:LOCALAPPDATA 'Lumoswitch\bin\lumoswitch-opencode.ps1'
$lumoswitchBackupSuffix = (Get-Date -Format 'yyyyMMdd-HHmmss') + '-' + $PID
function Protect-LumoswitchFile([string] $Path) {
$lumoswitchSid = [Security.Principal.WindowsIdentity]::GetCurrent().User.Value
& icacls.exe $Path '/inheritance:r' '/grant:r' ('*' + $lumoswitchSid + ':(F)') '*S-1-5-18:(F)' '*S-1-5-32-544:(F)' | Out-Null
if ($LASTEXITCODE -ne 0) { throw "Could not restrict access to $Path" }
}
function Install-LumoswitchFile([string] $Path, [string] $Content) {
[IO.Directory]::CreateDirectory((Split-Path -Parent $Path)) | Out-Null
if (Test-Path -LiteralPath $Path) {
$lumoswitchItem = Get-Item -LiteralPath $Path -Force
if ($lumoswitchItem.PSIsContainer -or ($lumoswitchItem.Attributes -band [IO.FileAttributes]::ReparsePoint)) {
throw "Lumoswitch refused to replace a directory or link: $Path"
}
$lumoswitchBackup = $Path + '.backup.' + $lumoswitchBackupSuffix
Copy-Item -LiteralPath $Path -Destination $lumoswitchBackup
Protect-LumoswitchFile $lumoswitchBackup
}
$lumoswitchTemporary = $Path + '.' + [Guid]::NewGuid().ToString('N') + '.tmp'
try {
[IO.File]::WriteAllText($lumoswitchTemporary, $Content, [Text.UTF8Encoding]::new($false))
Move-Item -LiteralPath $lumoswitchTemporary -Destination $Path -Force
Protect-LumoswitchFile $Path
} finally {
Remove-Item -LiteralPath $lumoswitchTemporary -Force -ErrorAction SilentlyContinue
}
}
[IO.Directory]::CreateDirectory($lumoswitchRoot) | Out-Null
$lumoswitchOpenCodeConfig = Join-Path $lumoswitchRoot 'opencode.json'
Install-LumoswitchFile $lumoswitchOpenCodeConfig '{{opencode_config_json}}'
$lumoswitchEnvironment = [ordered]@{}
$lumoswitchEnvironment['OPENCODE_CONFIG'] = (Join-Path $lumoswitchRoot 'opencode.json')
$lumoswitchEnvironment['LUMOSWITCH_OPENCODE_API_KEY'] = '{{access_key}}'
foreach ($lumoswitchEntry in $lumoswitchEnvironment.GetEnumerator()) {
[Environment]::SetEnvironmentVariable($lumoswitchEntry.Key, $lumoswitchEntry.Value, 'User')
[Environment]::SetEnvironmentVariable($lumoswitchEntry.Key, $lumoswitchEntry.Value, 'Process')
}
$lumoswitchLauncherContent = @'
param([Parameter(ValueFromRemainingArguments = $true)][string[]] $AgentArgs)
$ErrorActionPreference = 'Stop'
$lumoswitchRoot = Join-Path $env:LOCALAPPDATA 'Lumoswitch\agents\opencode'
$lumoswitchLauncher = Join-Path $env:LOCALAPPDATA 'Lumoswitch\bin\lumoswitch-opencode.ps1'
function Remove-LumoswitchFile([string] $Path) {
if (-not (Test-Path -LiteralPath $Path)) { return }
$lumoswitchItem = Get-Item -LiteralPath $Path -Force
if ($lumoswitchItem.PSIsContainer -or ($lumoswitchItem.Attributes -band [IO.FileAttributes]::ReparsePoint)) {
throw "Lumoswitch refused to remove a directory or link: $Path"
}
Remove-Item -LiteralPath $Path -Force
}
if ($AgentArgs.Count -gt 0 -and $AgentArgs[0] -eq '--lumoswitch-clean') {
foreach ($lumoswitchName in @('OPENCODE_CONFIG', 'LUMOSWITCH_OPENCODE_API_KEY')) {
[Environment]::SetEnvironmentVariable($lumoswitchName, $null, 'User')
[Environment]::SetEnvironmentVariable($lumoswitchName, $null, 'Process')
}
if (Test-Path -LiteralPath $lumoswitchRoot -PathType Container) {
$lumoswitchRootItem = Get-Item -LiteralPath $lumoswitchRoot -Force
if ($lumoswitchRootItem.Attributes -band [IO.FileAttributes]::ReparsePoint) { throw 'Lumoswitch refused to clean through a linked directory.' }
foreach ($lumoswitchFile in @(Get-ChildItem -LiteralPath $lumoswitchRoot -File -Recurse -Force)) { Remove-LumoswitchFile $lumoswitchFile.FullName }
foreach ($lumoswitchDirectory in @(Get-ChildItem -LiteralPath $lumoswitchRoot -Directory -Recurse -Force | Sort-Object FullName -Descending)) {
if ($null -eq (Get-ChildItem -LiteralPath $lumoswitchDirectory.FullName -Force | Select-Object -First 1)) { Remove-Item -LiteralPath $lumoswitchDirectory.FullName -Force }
}
if ($null -eq (Get-ChildItem -LiteralPath $lumoswitchRoot -Force | Select-Object -First 1)) { Remove-Item -LiteralPath $lumoswitchRoot -Force }
}
$lumoswitchBin = Split-Path -Parent $lumoswitchLauncher
if (Test-Path -LiteralPath $lumoswitchBin -PathType Container) {
foreach ($lumoswitchBackup in @(Get-ChildItem -LiteralPath $lumoswitchBin -Filter 'lumoswitch-opencode.ps1.backup.*' -File -Force)) { Remove-LumoswitchFile $lumoswitchBackup.FullName }
}
Remove-LumoswitchFile $lumoswitchLauncher
Write-Host 'Lumoswitch native setup and optional launcher removed. Open a new terminal to refresh the environment.'
exit 0
}
$lumoswitchEnvironment = [ordered]@{}
$lumoswitchEnvironment['OPENCODE_CONFIG'] = (Join-Path $lumoswitchRoot 'opencode.json')
$lumoswitchEnvironment['LUMOSWITCH_OPENCODE_API_KEY'] = '{{access_key}}'
foreach ($lumoswitchEntry in $lumoswitchEnvironment.GetEnumerator()) {
[Environment]::SetEnvironmentVariable($lumoswitchEntry.Key, $lumoswitchEntry.Value, 'Process')
}
$lumoswitchExecutable = Get-Command 'opencode.cmd' -CommandType Application -ErrorAction SilentlyContinue
if ($null -eq $lumoswitchExecutable) { $lumoswitchExecutable = Get-Command 'opencode.exe' -CommandType Application -ErrorAction SilentlyContinue }
if ($null -eq $lumoswitchExecutable) { $lumoswitchExecutable = Get-Command 'opencode' -CommandType Application -ErrorAction Stop }
$lumoswitchArguments = @()
& $lumoswitchExecutable.Path @lumoswitchArguments @AgentArgs
if ($null -ne $LASTEXITCODE) { exit $LASTEXITCODE }
'@
Install-LumoswitchFile $lumoswitchLauncher $lumoswitchLauncherContent
Write-Host 'Native Lumoswitch setup saved. Future command: opencode'
Write-Host 'Optional maintenance launcher:' $lumoswitchLauncher
$lumoswitchExecutable = Get-Command 'opencode.cmd' -CommandType Application -ErrorAction SilentlyContinue
if ($null -eq $lumoswitchExecutable) { $lumoswitchExecutable = Get-Command 'opencode.exe' -CommandType Application -ErrorAction SilentlyContinue }
if ($null -eq $lumoswitchExecutable) { $lumoswitchExecutable = Get-Command 'opencode' -CommandType Application -ErrorAction Stop }
$lumoswitchArguments = @()
& $lumoswitchExecutable.Path @lumoswitchArguments
if ($null -ne $LASTEXITCODE -and $LASTEXITCODE -ne 0) { throw 'opencode exited with code ' + $LASTEXITCODE }
}The import writes the Agent-supported persistent configuration and starts opencode directly. The saved Lumoswitch maintenance script is not required to start the Agent; run it with --lumoswitch-clean when you need to restore or remove this setup.
Remove the Lumoswitch setup
Windows PowerShell
Exit every Lumoswitch session for this Agent, then run the command below. The optional maintenance launcher removes the managed native configuration, restores any preserved shared file, clears Lumoswitch user environment values, and removes itself.
& {
$lumoswitchLauncher = Join-Path $env:LOCALAPPDATA 'Lumoswitch\bin\lumoswitch-opencode.ps1'
if (-not (Test-Path -LiteralPath $lumoswitchLauncher -PathType Leaf)) {
throw 'The optional Lumoswitch maintenance launcher is missing. Run persistent import again before cleanup.'
}
& powershell.exe -NoLogo -NoProfile -ExecutionPolicy Bypass -File $lumoswitchLauncher --lumoswitch-clean
}macOS / Linux
This command removes the managed OpenCode configuration path, environment hook, optional launcher, and its backups. It does not remove OpenCode sessions, project data, or existing settings.
"$HOME/.local/bin/lumoswitch-opencode" --lumoswitch-cleanThe removal command also deletes Agent-supported persistent configuration and optional Lumoswitch launcher backups because they may contain an Access Key. The one-time command scopes its variables to the OpenCode child process, so nothing remains after exit. Rotate that Key in Lumoswitch afterward.
OpenCode Desktop and IDE
OpenCode officially ships a Desktop app and IDE extension. CLI, Desktop, and IDE read the same global configuration. To use Lumoswitch graphically, merge provider.lumoswitch and the top-level model below into ~/.config/opencode/opencode.json; do not replace the whole file:
{
"$schema": "https://opencode.ai/config.json",
"provider": {
"lumoswitch": {
"npm": "@ai-sdk/openai-compatible",
"name": "Lumoswitch",
"options": {
"baseURL": "{{api_base_url}}",
"apiKey": "{file:~/.config/opencode/lumoswitch.key}"
},
"models": {
"{{model}}": { "name": "{{model}}" }
}
}
},
"model": "lumoswitch/{{model}}"
}Store only the rendered {{access_key}} value in ~/.config/opencode/lumoswitch.key, without quotes or a variable name, and set the file permissions to 0600. Fully quit and reopen Desktop or the IDE afterward.
Graphical surfaces support persistent setup only. They read global configuration and do not inherit the process-scoped variables above. To remove the graphical setup:
- Remove only
provider.lumoswitchfromopencode.json. - Remove or change the top-level
modelonly if it still points tolumoswitch/.... - Delete the dedicated Key file:
rm -f "$HOME/.config/opencode/lumoswitch.key"There is no automatic command for rewriting opencode.json because it may contain comments, other providers, and project settings. Removing the two named fields is safer than replacing a shared file.
Verify and troubleshoot
- The command selects
lumoswitch/{{model}}; no second provider selection is required. - This page targets OpenAI-compatible output. Responses output needs a separate SDK configuration.
- If tool calls fail, confirm that the target model supports tools and retry without provider-specific options.
References: OpenCode introduction, providers, and configuration.
Maintainer publication fields
- Platform ID:
opencode - Display name:
OpenCode CLI - Downstream protocol:
openai-compatible commandTemplate: copy the complete One-time launch code block- Persistent strategy:
native persistentCommandTemplate: copy the complete setup command under Persistent usefutureCommand:opencode- Display order:
30 - Last verified:
2026-08-27