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
| Method | Available? | Notes |
|---|---|---|
| One-time launch from a clean machine | No | A 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 registration | Yes | Environment values apply only to the current Goose process |
| Persistent use | Yes | A native provider, user environment, and optional launcher are created |
| Removal | Yes | The official removal flow deletes both the provider and Keychain credential |
Prepare the connection values
| Placeholder | Value |
|---|---|
{{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 startFor everyday use, run:
goose session startAdjust 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 lumoswitchBoth 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 configureChoose 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-cleanEvery 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
openaiengine 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
commandTemplateis not applicable - Persistent strategy:
native persistentCommandTemplate: copy the complete Persistent use code blockfutureCommand:goose session start- Display order:
130 - Last verified:
2026-08-27