# coproxy
OpenAI- and Anthropic-compatible API proxy backed by GitHub Copilot.
> [!WARNING]
> This is a reverse-engineered proxy of GitHub Copilot API. It is not supported by GitHub, and may break unexpectedly. Use at your own risk.
> [!WARNING]
> **GitHub Security Notice:**
> Excessive automated or scripted use of Copilot (including rapid or bulk requests, such as via automated tools) may trigger GitHub's abuse-detection systems.
> You may receive a warning from GitHub Security, and further anomalous activity could result in temporary suspension of your Copilot access.
>
> GitHub prohibits use of their servers for excessive automated bulk activity or any activity that places undue burden on their infrastructure.
>
> Please review:
>
> - [GitHub Acceptable Use Policies](https://docs.github.com/site-policy/acceptable-use-policies/github-acceptable-use-policies#4-spam-and-inauthentic-activity-on-github)
> - [GitHub Copilot Terms](https://docs.github.com/site-policy/github-terms/github-terms-for-additional-products-and-features#github-copilot)
>
> Use this proxy responsibly to avoid account restrictions.
## Installation
### From crates.io
```bash
cargo install coproxy
```
### From source
```bash
git clone https://github.com/hedonhermdev/coproxy.git
cd coproxy
cargo install --path .
```
### Prebuilt binaries
Download from [GitHub Releases](https://github.com/hedonhermdev/coproxy/releases). Available for Linux (x86_64, aarch64), macOS (x86_64, aarch64), and Windows (x86_64, aarch64). Linux/macOS builds ship as `.tar.gz`, Windows builds as `.zip`.
### Docker
```bash
docker run -it -p 8080:8080 ghcr.io/hedonhermdev/coproxy serve --host 0.0.0.0
```
On first run, the container will print a GitHub device login URL and code to stdout. Complete the auth flow in your browser, and the server will start automatically.
To persist credentials across restarts, mount a volume:
```bash
docker run -it -p 8080:8080 -v coproxy-data:/data ghcr.io/hedonhermdev/coproxy serve --host 0.0.0.0 --state-dir /data
```
## Quick start
```bash
# First-time login (opens GitHub device flow)
coproxy auth login
# Start the proxy
coproxy serve --port 8080 --api-surface all
# Verify it works
curl http://127.0.0.1:8080/v1/models -H "Authorization: Bearer any-key"
```
## Usage with OpenAI Python client
```python
from openai import OpenAI
client = OpenAI(
base_url="http://127.0.0.1:8080/v1",
api_key="any-key", # or your --api-key value
)
# Chat completions
response = client.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": "Hello!"}],
)
print(response.choices[0].message.content)
# Streaming
stream = client.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": "Hello!"}],
stream=True,
)
for chunk in stream:
if chunk.choices[0].delta.content:
print(chunk.choices[0].delta.content, end="")
# Responses API (model-dependent, e.g. gpt-5.4)
response = client.responses.create(
model="gpt-5.4",
input="Explain quantum computing in one sentence.",
)
print(response.output_text)
# List models
for model in client.models.list():
print(model.id)
```
## API surface
| `POST /v1/chat/completions` | Supported (sync + stream) |
| `GET /v1/models` | Supported |
| `GET /v1/models/{model}` | Supported |
| `POST /v1/responses` | Passthrough (model-dependent) |
| `GET /v1/responses/{response_id}` | Passthrough |
| `POST /v1/embeddings` | Not supported |
| `POST /v1/messages` | Anthropic-compatible (opt in via `--anthropic`) |
### Anthropic-compatible Messages API
`/v1/messages` is **disabled by default** and only exposed when the server is
started with `--anthropic`. The proxy translates each Anthropic Messages
request into an OpenAI chat completion (system blocks, content blocks, tool
definitions, tool_use / tool_result, image inputs), dispatches to GHCP, and
re-shapes the response back into Anthropic format. Streaming requests are
re-emitted as Anthropic SSE events (`message_start`, `content_block_start`,
`content_block_delta`, `content_block_stop`, `message_delta`, `message_stop`,
`ping`).
```bash
coproxy serve --port 8080 --anthropic --api-key my-secret
```
```python
from anthropic import Anthropic
client = Anthropic(api_key="my-secret", base_url="http://127.0.0.1:8080")
message = client.messages.create(
model="claude-3.5-sonnet",
max_tokens=256,
messages=[{"role": "user", "content": "Hello!"}],
)
print(message.content[0].text)
```
You can also point Claude Code at the proxy: `ANTHROPIC_BASE_URL=http://127.0.0.1:8080 ANTHROPIC_API_KEY=my-secret claude`.
## Configuration
### CLI flags
| `--host` | `127.0.0.1` | Bind address |
| `--port` | `8080` | Bind port |
| `-d`, `--daemon` | false | Run the server as a background daemon |
| `--stop` | false | Stop a running daemon |
| `--api-surface` | `chat` | OpenAI surface: `chat`, `chat-responses`, `chat-embeddings`, `all` |
| `--anthropic` | false | Also expose the Anthropic-compatible `POST /v1/messages` endpoint |
| `--api-key` | none | Require Bearer token (or `x-api-key` for `/v1/messages`) for `/v1/*` routes |
| `--default-model` | `gpt-4o` | Default model when requests omit `model` |
| `--state-dir` | OS default | Override credential storage path |
| `--no-auto-login` | false | Skip automatic auth bootstrap at startup |
| `--log-level` | `info` | Log level filter |
### Environment variables
| `GHCP_GITHUB_TOKEN` | `--github-token` (skip device flow, use this token directly) |
| `GHCP_PROXY_API_KEY` | `--api-key` |
## Authentication
On first run, coproxy triggers GitHub device flow:
1. Prints a verification URL and user code.
2. Polls GitHub OAuth until you authorize.
3. Exchanges GitHub token for a GHCP API token.
4. Caches both tokens locally with restricted file permissions (`0600`).
```bash
coproxy auth login # Interactive login
coproxy auth status # Show cached token info
coproxy auth logout # Remove cached credentials
```
Or skip device flow entirely by providing a GitHub token:
```bash
export GHCP_GITHUB_TOKEN=ghp_xxxxx
coproxy serve
```
## Running as a daemon
Use `-d` to start the server in the background. The daemon's PID is written to `<state-dir>/coproxy.pid`.
```bash
# Start in background
coproxy serve -d --port 8080
# Stop the daemon
coproxy serve --stop
```
On Unix, `--stop` sends `SIGTERM` so the server drains in-flight requests before exiting. On Windows it invokes `taskkill /F /PID <pid>`, which terminates immediately — in-flight requests are dropped. The proxy holds no durable cross-request state, so this is normally fine; avoid `--stop` mid-conversation if a streaming response is important to preserve.
## Running as a service
### systemd (Linux)
Copy `contrib/coproxy.service` to `/etc/systemd/system/` and adjust as needed:
```bash
sudo cp contrib/coproxy.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable --now coproxy
```
### launchd (macOS)
Copy `contrib/com.coproxy.plist` to `~/Library/LaunchAgents/`:
```bash
cp contrib/com.coproxy.plist ~/Library/LaunchAgents/
launchctl load ~/Library/LaunchAgents/com.coproxy.plist
```
### Task Scheduler (Windows)
Register a per-user task that starts the proxy at logon. Run from PowerShell:
```powershell
$exe = "$env:USERPROFILE\.cargo\bin\coproxy.exe" # or the path to your extracted release binary
$action = New-ScheduledTaskAction -Execute $exe -Argument 'serve --host 127.0.0.1 --port 8080 --api-surface all --no-auto-login'
$trigger = New-ScheduledTaskTrigger -AtLogOn -User $env:USERNAME
$settings = New-ScheduledTaskSettingsSet -StartWhenAvailable -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries
Register-ScheduledTask -TaskName 'coproxy' -Action $action -Trigger $trigger -Settings $settings
```
Notes:
- Do **not** pass `-d`/`--daemon` — Task Scheduler already runs the task detached from any console.
- Run `coproxy auth login` once interactively before registering the task, or set `GHCP_GITHUB_TOKEN` via `[System.Environment]::SetEnvironmentVariable('GHCP_GITHUB_TOKEN', 'ghp_xxxxx', 'User')` so the task can authenticate without prompting.
- Start/stop on demand: `Start-ScheduledTask -TaskName coproxy` / `Stop-ScheduledTask -TaskName coproxy`.
- Remove entirely: `Unregister-ScheduledTask -TaskName coproxy -Confirm:$false`.
For Windows Service semantics (auto-restart, logs to Event Log, runs without a logged-in user) use a wrapper like [NSSM](https://nssm.cc/) — coproxy is a console app, not a native Windows service, so it can't be registered with `sc create` directly.
## Development
```bash
cargo fmt --all -- --check # Format check
cargo clippy --all-targets # Lint
cargo check # Type check
cargo test # Rust tests
# OpenAI compatibility tests (requires uv + GHCP auth)
scripts/run-openai-compat-tests.sh
# Anthropic compatibility tests (requires uv + GHCP auth)
scripts/run-anthropic-compat-tests.sh
```
## License
MIT