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
| Method | Best for | Local writes | Still active after exit? |
|---|---|---|---|
| One-time launch | Testing a URL, Key, or model | No Copilot CLI configuration | No |
| Persistent use | Everyday terminal use | User environment + optional launcher | Yes |
| Copilot app / IDE / GitHub Desktop | Using the corresponding graphical interface | A BYOK provider stored separately by each app | Yes |
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
| Placeholder | Value |
|---|---|
{{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'
copilotFor later sessions, run:
copilotYou 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-cleanThe 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
copilotagain. - 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