Documentation

Everything you need to run Copilot Bridge and point your tools at it.

Overview

Copilot Bridge is a small, self-hosted proxy that exposes your GitHub Copilot subscription through two API dialects at once: the OpenAI Chat Completions API and the Anthropic Messages API. Any tool that can point at a custom base URL — Claude Code, Codex CLI, opencode, Cline, Kilo Code, or the official SDKs — can then run on Copilot.

It runs entirely on your own machine using your own credentials. Nothing is routed through a third party.

This is a hosted instance. You don't install anything. Sign in with GitHub, copy your bridge key, and skip to Configure your tool. Use the key wherever the examples say copilot. You can also self-host your own copy.

Install

Run it on demand with npx, or clone the repo.

# on demand
npx copilotbridge --help

# or from a clone
git clone <repo-url> copilotbridge
cd copilotbridge
node src/index.js --help

Authenticate

Authenticate once with GitHub's device flow. You'll open a URL, enter a short code, and approve the login in your browser.

npx copilotbridge auth

Your GitHub token is stored at ~/.copilotbridge/github-token with file mode 600. The bridge uses it to mint short-lived Copilot tokens as needed. In CI, set GH_TOKEN instead of logging in.

Start the server

npx copilotbridge start # 127.0.0.1:4141 by default
npx copilotbridge start --port 8080
npx copilotbridge start --host 0.0.0.0 --port 8080
Binding beyond localhost? Set BRIDGE_API_KEY so clients must present a key. See Security.

Configure your tool

Claude Code · Anthropic

export ANTHROPIC_BASE_URL=https://157-245-80-136.sslip.io
export ANTHROPIC_AUTH_TOKEN=copilot   # any value, or your BRIDGE_API_KEY
claude

Codex CLI · OpenAI SDK

export OPENAI_BASE_URL=https://157-245-80-136.sslip.io/v1
export OPENAI_API_KEY=copilot

opencode

opencode has native GitHub Copilot support (opencode auth login → GitHub Copilot), so it doesn't need the bridge. If you want it to share one key with your other tools anyway, add an OpenAI-compatible provider:

// opencode.json
{
  "provider": {
    "copilotbridge": {
      "npm": "@ai-sdk/openai-compatible",
      "options": { "baseURL": "https://157-245-80-136.sslip.io/v1", "apiKey": "copilot" }
    }
  }
}

Cline / Kilo Code

Choose an OpenAI-compatible provider, set the base URL to https://157-245-80-136.sslip.io/v1, and use any non-empty API key (or your BRIDGE_API_KEY).

OpenAI SDK (JavaScript)

import OpenAI from "openai";
const client = new OpenAI({
  baseURL: "https://157-245-80-136.sslip.io/v1",
  apiKey: "copilot",
});

Anthropic SDK (JavaScript)

import Anthropic from "@anthropic-ai/sdk";
const client = new Anthropic({
  baseURL: "https://157-245-80-136.sslip.io",
  apiKey: "copilot",
});

Endpoints

EndpointDescription
POST /v1/chat/completionsOpenAI chat — streaming, tools, images
GET  /v1/modelsModels available to your Copilot plan
POST /v1/messagesAnthropic Messages — streaming, tools, images
POST /v1/messages/count_tokensApproximate input-token count
GET  /healthzLiveness check
GET  /This site

Quick check once the server is running:

curl https://157-245-80-136.sslip.io/healthz
curl https://157-245-80-136.sslip.io/v1/models -H "authorization: Bearer copilot"

Models

Which models you can call depends on your Copilot plan. List them with GET /v1/models, then pass one of the returned ids as the model in your request or via ANTHROPIC_MODEL / --model.

# Claude Code example
export ANTHROPIC_MODEL=claude-sonnet-4.5
claude --model gpt-5

Configuration

VariableDefaultMeaning
PORT4141Listen port (also --port)
BRIDGE_API_KEYunsetIf set, clients must send this exact key. If unset, any non-empty key is accepted.
GH_TOKENunsetUse this GitHub token instead of the stored one (for CI).

How it works

  1. Login. auth runs GitHub's OAuth device flow using the public Copilot client id and stores the GitHub token locally.
  2. Token exchange. On demand, the bridge trades that GitHub token for a short-lived Copilot API token, caching it and refreshing about two minutes before it expires.
  3. Upstream. Requests go to Copilot's API with the editor and integration headers it expects.
  4. Translation. OpenAI-shaped requests pass through nearly untouched. Anthropic-shaped requests are translated to OpenAI form on the way in and back to Anthropic form — including streaming SSE events — on the way out.

Troubleshooting

"Not authenticated"

Run copilotbridge auth, or set GH_TOKEN.

Copilot token exchange fails

Your GitHub account may not have an active Copilot subscription, or the token expired. Re-run auth.

401 from the bridge

You set BRIDGE_API_KEY but the client sent a different key. Make the client's key match, or unset the variable.

Model not found

Call GET /v1/models and use an id it returns. Availability follows your plan.

Streams stall

The bridge sends an SSE keepalive every 15 seconds so idle watchdogs don't tear down slow responses. If a client still disconnects, raise its idle timeout.

Limitations

  • count_tokens returns a character-based estimate; Copilot exposes no exact counter.
  • The Anthropic surface implements what Claude Code exercises in practice, not every corner of the Anthropic API.
  • Copilot's token-exchange endpoint is undocumented and could change; this is unofficial software.

Running a hosted instance

The default is single-user: the process holds one GitHub token. Set BRIDGE_MODE=hosted to run a shared bridge where anyone can sign in with their own GitHub account at /login and receive a bridge key tied to their own Copilot subscription.

export BRIDGE_MODE=hosted
export BRIDGE_SECRET=$(node -e "console.log(require('crypto').randomBytes(32).toString('hex'))")
export BRIDGE_PUBLIC_URL=https://bridge.example.com
copilotbridge start --host 127.0.0.1 --port 4141   # put Caddy or nginx in front for TLS
  • GitHub tokens are encrypted at rest with AES-256-GCM under BRIDGE_SECRET. Lose the secret and every user must sign in again.
  • Bridge keys are stored only as SHA-256 hashes and are shown to the user exactly once. Signing in again revokes old keys.
  • POST /api/keys/rotate with an existing key as the bearer token revokes it and returns a fresh one.
  • Each request is served with that user's own Copilot token, so usage and rate limits are per person, not per server.
  • Login starts are throttled per IP. Always run behind HTTPS.

Security

  • Keep the bridge bound to 127.0.0.1 unless you have a reason not to.
  • If you bind to a public interface, always set BRIDGE_API_KEY.
  • The stored GitHub token grants Copilot access. It lives at ~/.copilotbridge/github-token with mode 600; treat it like a password.

Copilot Bridge is unofficial community software. Not affiliated with, endorsed by, or official software from GitHub or Microsoft. Use it in accordance with the GitHub Copilot terms of service.