Lumoswitch Docs
Agent setup

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

MethodBest forLocal writesStill active after exit?
One-time launchTesting a URL, Key, or model in the CLINo OpenCode configurationNo
Persistent useEveryday terminal useAgent-supported config path + optional launcherYes
Desktop / IDEUsing OpenCode graphicallyMerged global configuration and a dedicated Key fileYes

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

PlaceholderValue
{{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" \
  opencode

The 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'
opencode

For everyday use, run:

opencode

Native 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-clean

The 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:

  1. Remove only provider.lumoswitch from opencode.json.
  2. Remove or change the top-level model only if it still points to lumoswitch/....
  3. 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 use
  • futureCommand: opencode
  • Display order: 30
  • Last verified: 2026-08-27

On this page