Lumoswitch Docs
Agent setup

Goose Agent setup

Goose is a local general-purpose agent for coding, research, automation, and data work. The official product includes a CLI, Desktop app, and API. CLI and Desktop discover custom provider definitions from the same directory, although credentials can come from different stores.

Install Goose first, then create a Lumoswitch API configuration with OpenAI-compatible output.

Choose a setup method

MethodAvailable?Notes
One-time launch from a clean machineNoA custom Base URL and model must first be registered in a JSON provider definition; the CLI has no complete one-run provider definition flags
One-time Key or model switch after registrationYesEnvironment values apply only to the current Goose process
Persistent useYesA native provider, user environment, and optional launcher are created
RemovalYesThe official removal flow deletes both the provider and Keychain credential

Prepare the connection values

PlaceholderValue
{{api_base_url}}The downstream API URL, including /v1 and without a trailing slash
{{access_key}}The Lumoswitch Access Key selected for this configuration
{{model}}The client-facing model name shown by the API configuration
{{goose_provider_json}}Generated Goose provider definition containing every downstream model

Persistent use

This command creates Goose's native Lumoswitch provider file and stores the Key in an owner-only managed environment file. It does not replace Goose's config.yaml or other providers.

set -e
LUMOSWITCH_ROOT="$HOME/.config/lumoswitch/agents/goose"
LUMOSWITCH_ENV="$LUMOSWITCH_ROOT/env.sh"
LUMOSWITCH_LAUNCHER="$HOME/.local/bin/lumoswitch-goose"
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_GOOSE_PROVIDER="$HOME/.config/goose/custom_providers/lumoswitch.json"
mkdir -p "$(dirname "$LUMOSWITCH_GOOSE_PROVIDER")"
cat > "$LUMOSWITCH_GOOSE_PROVIDER" <<'LUMOSWITCH_CONFIG_EOF'
{{goose_provider_json}}
LUMOSWITCH_CONFIG_EOF

cat > "$LUMOSWITCH_ENV" <<'LUMOSWITCH_ENV_EOF'
export LUMOSWITCH_GOOSE_API_KEY="{{access_key}}"
export GOOSE_PROVIDER="lumoswitch"
export GOOSE_MODEL="{{model}}"
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: goose'
LUMOSWITCH_SOURCE_LINE='[ -f "$HOME/.config/lumoswitch/agents/goose/env.sh" ] && . "$HOME/.config/lumoswitch/agents/goose/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/goose"
LUMOSWITCH_ENV="$LUMOSWITCH_ROOT/env.sh"
LUMOSWITCH_LAUNCHER="$HOME/.local/bin/lumoswitch-goose"

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: goose'
      LUMOSWITCH_SOURCE_LINE='[ -f "$HOME/.config/lumoswitch/agents/goose/env.sh" ] && . "$HOME/.config/lumoswitch/agents/goose/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
  rm -f "$HOME/.config/goose/custom_providers/lumoswitch.json"
  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-goose.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 goose session start "$@"
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: goose session start'
printf '%s\n' 'Optional maintenance launcher: ~/.local/bin/lumoswitch-goose'
goose session start

For everyday use, run:

goose session start

Adjust context_limit to the real model capability. An incorrect value affects Goose's context management.

One-time launch after registration

After the provider has been registered once, temporarily use a different Key or model without updating persistent import:

env \
  LUMOSWITCH_GOOSE_API_KEY="{{access_key}}" \
  GOOSE_MODEL="{{model}}" \
  goose session start --provider lumoswitch

Both values expire when Goose exits, while lumoswitch.json remains. This is not a complete clean-machine one-time setup because Goose officially requires a custom provider definition first.

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.

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\goose'
  $lumoswitchLauncher = Join-Path $env:LOCALAPPDATA 'Lumoswitch\bin\lumoswitch-goose.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
  $lumoswitchGooseProvider = Join-Path $env:APPDATA 'Block\goose\config\custom_providers\lumoswitch.json'
  $lumoswitchProviderContent = @'
{{goose_provider_json}}
'@
  Install-LumoswitchFile $lumoswitchGooseProvider $lumoswitchProviderContent

  $lumoswitchEnvironment = [ordered]@{}
  $lumoswitchEnvironment['LUMOSWITCH_GOOSE_API_KEY'] = '{{access_key}}'
  $lumoswitchEnvironment['GOOSE_PROVIDER'] = 'lumoswitch'
  $lumoswitchEnvironment['GOOSE_MODEL'] = '{{model}}'
  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\goose'
$lumoswitchLauncher = Join-Path $env:LOCALAPPDATA 'Lumoswitch\bin\lumoswitch-goose.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 @('LUMOSWITCH_GOOSE_API_KEY', 'GOOSE_PROVIDER', 'GOOSE_MODEL')) {
    [Environment]::SetEnvironmentVariable($lumoswitchName, $null, 'User')
    [Environment]::SetEnvironmentVariable($lumoswitchName, $null, 'Process')
  }
  Remove-LumoswitchFile (Join-Path $env:APPDATA 'Block\goose\config\custom_providers\lumoswitch.json')
  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-goose.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['LUMOSWITCH_GOOSE_API_KEY'] = '{{access_key}}'
$lumoswitchEnvironment['GOOSE_PROVIDER'] = 'lumoswitch'
$lumoswitchEnvironment['GOOSE_MODEL'] = '{{model}}'
foreach ($lumoswitchEntry in $lumoswitchEnvironment.GetEnumerator()) {
  [Environment]::SetEnvironmentVariable($lumoswitchEntry.Key, $lumoswitchEntry.Value, 'Process')
}
$lumoswitchExecutable = Get-Command 'goose.cmd' -CommandType Application -ErrorAction SilentlyContinue
if ($null -eq $lumoswitchExecutable) { $lumoswitchExecutable = Get-Command 'goose.exe' -CommandType Application -ErrorAction SilentlyContinue }
if ($null -eq $lumoswitchExecutable) { $lumoswitchExecutable = Get-Command 'goose' -CommandType Application -ErrorAction Stop }
$lumoswitchArguments = @('session', 'start')
& $lumoswitchExecutable.Path @lumoswitchArguments @AgentArgs
if ($null -ne $LASTEXITCODE) { exit $LASTEXITCODE }
'@
  Install-LumoswitchFile $lumoswitchLauncher $lumoswitchLauncherContent
  Write-Host 'Native Lumoswitch setup saved. Future command: goose session start'
  Write-Host 'Optional maintenance launcher:' $lumoswitchLauncher
  $lumoswitchExecutable = Get-Command 'goose.cmd' -CommandType Application -ErrorAction SilentlyContinue
  if ($null -eq $lumoswitchExecutable) { $lumoswitchExecutable = Get-Command 'goose.exe' -CommandType Application -ErrorAction SilentlyContinue }
  if ($null -eq $lumoswitchExecutable) { $lumoswitchExecutable = Get-Command 'goose' -CommandType Application -ErrorAction Stop }
  $lumoswitchArguments = @('session', 'start')
  & $lumoswitchExecutable.Path @lumoswitchArguments
  if ($null -ne $LASTEXITCODE -and $LASTEXITCODE -ne 0) { throw 'goose exited with code ' + $LASTEXITCODE }
}

The import writes the Agent-supported persistent configuration and starts goose session start 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-goose.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

If a Key was ever saved through Goose Desktop or goose configure, start with the official removal flow:

goose configure

Choose Custom Providers → Remove Custom Provider → Lumoswitch. The official flow removes the provider file and its Key from the system Keychain, or from secrets.yaml when the Keychain is disabled.

Then remove the dedicated files and backups created by this page:

"$HOME/.local/bin/lumoswitch-goose" --lumoswitch-clean

Every path is dedicated to Lumoswitch. The command does not remove Goose's config.yaml, sessions, extensions, or other providers.

Goose Desktop and IDEs

Goose Desktop is an official native app for macOS, Linux, and Windows. It sees the same lumoswitch.json, but it does not inherit a Key from a terminal environment that was opened before import. Open Settings → Models → Configure providers, select Lumoswitch, and save the Key. Goose stores it in the system Keychain and falls back to secrets.yaml only when the Keychain is unavailable.

Desktop supports persistent setup only because it does not inherit the current shell's LUMOSWITCH_GOOSE_API_KEY. Use Desktop's Delete Provider action or the goose configure flow above so removal also clears the credential.

Goose does not ship a separate official IDE extension with its own Lumoswitch configuration. It can run as an ACP agent for compatible editors; model requests still go through Goose and the same custom provider.

Verify and troubleshoot

  • The API URL must end in .../v1/chat/completions; this page appends the endpoint to {{api_base_url}}.
  • A Goose custom provider uses the openai engine to mean OpenAI-compatible request formatting.
  • Test a normal message first, then tools, streaming, and long context.

References: the Goose overview, custom providers, and the official repository. Last verified: 2026-08-27.

Maintainer publication fields
  • Platform ID: goose
  • Display name: Goose CLI
  • Downstream protocol: openai-compatible
  • One-time mode: disabled; a clean machine cannot register the complete custom provider with one process-only command, so commandTemplate is not applicable
  • Persistent strategy: native
  • persistentCommandTemplate: copy the complete Persistent use code block
  • futureCommand: goose session start
  • Display order: 130
  • Last verified: 2026-08-27

On this page