Lumoswitch Docs
Agent setup

GitHub Copilot CLI setup

GitHub Copilot CLI is GitHub's terminal coding agent. It can understand a repository, edit files, run commands, and invoke tools. Its BYOK mode supports OpenAI Chat Completions-compatible endpoints, so agent requests can run through Lumoswitch.

The API configuration must enable OpenAI-compatible output. The target model should support streaming and Tool / Function Calling, and GitHub recommends a context window of at least 128K. The CLI commands below target Bash or Zsh on macOS and Linux. Before continuing, confirm that copilot --version returns a version number.

Choose a setup method

MethodBest forLocal writesStill active after exit?
One-time launchTesting a URL, Key, or modelNo Copilot CLI configurationNo
Persistent useEveryday terminal useUser environment + optional launcherYes
Copilot app / IDE / GitHub DesktopUsing the corresponding graphical interfaceA BYOK provider stored separately by each appYes

The CLI and Copilot graphical interfaces are separate launch surfaces. CLI environment variables do not become Copilot app, native IDE chat, or GitHub Desktop settings. Graphical interfaces also have no equivalent one-time launch command; the reason is explained below.

Prepare the connection values

PlaceholderValue
{{api_base_url}}The OpenAI-compatible request URL shown by the API configuration; it should end in /v1
{{access_key}}The API configuration's Access Key
{{model}}The client-facing model name shown by the API configuration
{{copilot_reasoning_effort}}Safe default effort for the selected model; empty when it must not be sent

Commands copied from the console already contain real values. When {{copilot_reasoning_effort}} is empty the command sends no --effort; do not manually force one fixed tier across every model.

One-time launch

This command passes Lumoswitch configuration only to the newly started Copilot CLI process. It expires on exit, does not pollute the current shell, and does not change existing Copilot settings.

(
  set -e
  LUMOSWITCH_COPILOT_REASONING_EFFORT="{{copilot_reasoning_effort}}"
  set --
  if [ -n "$LUMOSWITCH_COPILOT_REASONING_EFFORT" ]; then
    set -- --effort "$LUMOSWITCH_COPILOT_REASONING_EFFORT"
  fi
  env \
    COPILOT_PROVIDER_TYPE="openai" \
    COPILOT_PROVIDER_BASE_URL="{{api_base_url}}" \
    COPILOT_PROVIDER_API_KEY="{{access_key}}" \
    COPILOT_MODEL="{{model}}" \
    COPILOT_OFFLINE="true" \
    copilot "$@"
)

BYOK mode does not require a GitHub sign-in. COPILOT_OFFLINE=true prevents this process from contacting GitHub for optional repository integrations and related features. Remove that value from the import template and managed environment if you need those online features.

Persistent use

Run the complete command during initial setup and whenever the Lumoswitch URL, Access Key, or model changes. It writes Copilot-supported user environment values without overwriting other Copilot configuration, 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/github-copilot-cli"
LUMOSWITCH_ENV="$LUMOSWITCH_ROOT/env.sh"
LUMOSWITCH_LAUNCHER="$HOME/.local/bin/lumoswitch-github-copilot-cli"
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

:

cat > "$LUMOSWITCH_ENV" <<'LUMOSWITCH_ENV_EOF'
export COPILOT_PROVIDER_TYPE="openai"
export COPILOT_PROVIDER_BASE_URL="{{api_base_url}}"
export COPILOT_PROVIDER_API_KEY="{{access_key}}"
export COPILOT_MODEL="{{model}}"
export COPILOT_OFFLINE="true"
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: github-copilot-cli'
LUMOSWITCH_SOURCE_LINE='[ -f "$HOME/.config/lumoswitch/agents/github-copilot-cli/env.sh" ] && . "$HOME/.config/lumoswitch/agents/github-copilot-cli/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/github-copilot-cli"
LUMOSWITCH_ENV="$LUMOSWITCH_ROOT/env.sh"
LUMOSWITCH_LAUNCHER="$HOME/.local/bin/lumoswitch-github-copilot-cli"

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

For later sessions, run:

copilot

You can append normal Copilot CLI arguments. Before an update, the installer keeps a timestamped copy of the old launcher with 0600 permissions.

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'
  $lumoswitchEnvironmentNames = @('COPILOT_MODEL', 'COPILOT_OFFLINE', 'COPILOT_PROVIDER_API_KEY', 'COPILOT_PROVIDER_BASE_URL', 'COPILOT_PROVIDER_TYPE')
  $lumoswitchPreviousEnvironment = @{}
  foreach ($lumoswitchName in $lumoswitchEnvironmentNames) {
    $lumoswitchPreviousEnvironment[$lumoswitchName] = [Environment]::GetEnvironmentVariable($lumoswitchName, 'Process')
  }
  $lumoswitchExitCode = 0
  try {
    [Environment]::SetEnvironmentVariable('COPILOT_MODEL', '{{model}}', 'Process')
    [Environment]::SetEnvironmentVariable('COPILOT_OFFLINE', 'true', 'Process')
    [Environment]::SetEnvironmentVariable('COPILOT_PROVIDER_API_KEY', '{{access_key}}', 'Process')
    [Environment]::SetEnvironmentVariable('COPILOT_PROVIDER_BASE_URL', '{{api_base_url}}', 'Process')
    [Environment]::SetEnvironmentVariable('COPILOT_PROVIDER_TYPE', 'openai', 'Process')
    $lumoswitchArguments = @()
    if ('{{copilot_reasoning_effort}}') { $lumoswitchArguments += @('--effort', '{{copilot_reasoning_effort}}') }
    $lumoswitchExecutable = Get-Command 'copilot.cmd' -CommandType Application -ErrorAction SilentlyContinue
    if ($null -eq $lumoswitchExecutable) { $lumoswitchExecutable = Get-Command 'copilot' -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 'copilot 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\github-copilot-cli'
  $lumoswitchLauncher = Join-Path $env:LOCALAPPDATA 'Lumoswitch\bin\lumoswitch-github-copilot-cli.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
  # No Agent configuration file is required.

  $lumoswitchEnvironment = [ordered]@{}
  $lumoswitchEnvironment['COPILOT_PROVIDER_TYPE'] = 'openai'
  $lumoswitchEnvironment['COPILOT_PROVIDER_BASE_URL'] = '{{api_base_url}}'
  $lumoswitchEnvironment['COPILOT_PROVIDER_API_KEY'] = '{{access_key}}'
  $lumoswitchEnvironment['COPILOT_MODEL'] = '{{model}}'
  $lumoswitchEnvironment['COPILOT_OFFLINE'] = 'true'
  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\github-copilot-cli'
$lumoswitchLauncher = Join-Path $env:LOCALAPPDATA 'Lumoswitch\bin\lumoswitch-github-copilot-cli.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 @('COPILOT_PROVIDER_TYPE', 'COPILOT_PROVIDER_BASE_URL', 'COPILOT_PROVIDER_API_KEY', 'COPILOT_MODEL', 'COPILOT_OFFLINE')) {
    [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-github-copilot-cli.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['COPILOT_PROVIDER_TYPE'] = 'openai'
$lumoswitchEnvironment['COPILOT_PROVIDER_BASE_URL'] = '{{api_base_url}}'
$lumoswitchEnvironment['COPILOT_PROVIDER_API_KEY'] = '{{access_key}}'
$lumoswitchEnvironment['COPILOT_MODEL'] = '{{model}}'
$lumoswitchEnvironment['COPILOT_OFFLINE'] = 'true'
foreach ($lumoswitchEntry in $lumoswitchEnvironment.GetEnumerator()) {
  [Environment]::SetEnvironmentVariable($lumoswitchEntry.Key, $lumoswitchEntry.Value, 'Process')
}
$lumoswitchExecutable = Get-Command 'copilot.cmd' -CommandType Application -ErrorAction SilentlyContinue
if ($null -eq $lumoswitchExecutable) { $lumoswitchExecutable = Get-Command 'copilot.exe' -CommandType Application -ErrorAction SilentlyContinue }
if ($null -eq $lumoswitchExecutable) { $lumoswitchExecutable = Get-Command 'copilot' -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: copilot'
  Write-Host 'Optional maintenance launcher:' $lumoswitchLauncher
  $lumoswitchExecutable = Get-Command 'copilot.cmd' -CommandType Application -ErrorAction SilentlyContinue
  if ($null -eq $lumoswitchExecutable) { $lumoswitchExecutable = Get-Command 'copilot.exe' -CommandType Application -ErrorAction SilentlyContinue }
  if ($null -eq $lumoswitchExecutable) { $lumoswitchExecutable = Get-Command 'copilot' -CommandType Application -ErrorAction Stop }
  $lumoswitchArguments = @()
  & $lumoswitchExecutable.Path @lumoswitchArguments
  if ($null -ne $LASTEXITCODE -and $LASTEXITCODE -ne 0) { throw 'copilot exited with code ' + $LASTEXITCODE }
}

The import writes the Agent-supported persistent configuration and starts copilot 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 CLI 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-github-copilot-cli.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 clears the Lumoswitch Copilot user environment and removes the optional launcher and its backups. It does not remove Copilot sign-in state, history, or user configuration.

"$HOME/.local/bin/lumoswitch-github-copilot-cli" --lumoswitch-clean

The one-time command scopes its variables to the Copilot child process, so nothing remains after it exits.

Copilot app, IDEs, and GitHub Desktop

Connect the current CLI to VS Code

Run /ide inside a Copilot CLI session that was started with this page's command. VS Code then connects to the current CLI process, which continues using its Lumoswitch provider without a second credential. This does not change the model provider used by native Copilot Chat in VS Code.

Configure graphical interfaces separately

The Copilot app, supported IDE BYOK interfaces, and GitHub Desktop must each be configured with an OpenAI-compatible provider, the Lumoswitch /v1 URL, Access Key, and client-facing model name. These interfaces offer persistent storage only: the application owns the provider and credential, so there is no reliable command-line one-time mode.

Removing the CLI launcher does not remove those graphical settings. If you added Lumoswitch in an app, switch providers or delete that BYOK configuration in the same app. Copilot in GitHub Desktop applies to Desktop features such as commit messages and conflict resolution; it is not the full coding agent.

See connect Copilot CLI to VS Code, Copilot app BYOK, and configure Copilot in GitHub Desktop.

Verify and troubleshoot

  • Default model still appears: open a new terminal so it inherits the persistent BYOK environment, then run copilot again.
  • Editing or tools fail: the candidate model may not support tool calls, or its context window may be too small.
  • 404: the Base URL should end in /v1; do not append /chat/completions.
  • Model not found: use the API configuration's client-facing model name.

Reference: GitHub Copilot CLI BYOK.

Maintainer publishing fields
  • Platform ID: github-copilot-cli
  • Display name: GitHub Copilot CLI
  • Downstream protocol: openai-compatible
  • commandTemplate: copy the complete code block under "One-time launch"
  • Persistence strategy: native
  • persistentCommandTemplate: copy the complete code block under "Persistent use"
  • futureCommand: copilot
  • Display order: 40
  • Last verified: 2026-08-27

On this page