Package Exports
- copilot-reverse
This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (copilot-reverse) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.
Readme
copilot-reverse
One command. Native experience. · 一行命令,原生体验。
Use the GitHub Copilot subscription you already pay for as a local Claude Code / Codex backend. No new API keys. No per-token bills. One terminal app — and Claude Code feels exactly like the real thing.
Disclaimer: The GitHub Copilot integration uses community-documented, unofficial endpoints, for use with your own Copilot subscription only. It may break if GitHub changes these endpoints.
60-second start
npx copilot-reverse- It asks you to log in to GitHub (device code — paste a code in your browser). One time only.
- The terminal app launches. You'll see a prompt and a status bar.
- In the app, type:
Pick a model (e.g. claude-opus-4.8 (1M)), choose global, done./setup-claude - Open a new terminal and run
claude. It's now talking to Copilot through copilot-reverse. 🎉
That's it. Codex users: run /setup-codex instead.
Here's the app itself — a prompt, a live status bar, and slash-command autocomplete:
✳ copilot-reverse worker: ready
Type a message to chat with the assistant, or /help for commands.
╭─────────────────────────────────────────────────────────────────────────────────────╮
│ › /setup │
╰─────────────────────────────────────────────────────────────────────────────────────╯
❯ /setup-claude print Claude Code config
/setup-codex print Codex/OpenAI config
/setup-status show configured endpoints
↑↓ navigate · tab complete · enter run
model claude-opus-4.8 · daemon ready · claude u:✓ p:○ codex u:✓ p:○ · /helpWhat can I do in the app?
Just talk to it — it understands plain English and will do the work for you:
"list models" → shows every model + its context window "set up claude" → asks scope (global/project) + model, then configures Claude Code "is the worker healthy?" → runs a health check "why did my last request fail?" → shows the error (incl. cut-short stream runaways)
Prefer commands? Type / to see them all. The essentials:
| Command | What it does |
|---|---|
/setup-claude · /setup-codex |
Point Claude Code / Codex at copilot-reverse |
/model |
Switch the chat model (1M-context models marked) |
/network |
Choose access mode: localhost (private) or LAN (shared, key required) |
/status · /doctor |
Is everything healthy? (/status shows each client's scope + model) |
/logs · /metrics |
What ran, what failed, and why |
/dashboard |
Open a live web dashboard in your browser |
/report |
File a pre-filled bug report (diagnostics only — no prompts) |
/reset-claude · /reset-codex |
Undo setup, restore original config |
/login · /logout |
Sign in to GitHub (device-code) · sign out (remove token) |
/help · /quit |
List commands · exit |
The live dashboard
/dashboard opens a self-refreshing web view of everything happening through the proxy — worker
health, request volume, and (most useful) recent errors with their real messages:

Native experience — it really is Claude Code
The whole point: through copilot-reverse, Claude Code (and Codex) behave like a direct connection to the real thing. We translate the full protocol both ways and pass through the features that matter — so you don't trade fidelity for a free backend.
- 🧠 Extended thinking, rendered natively. Ask a hard question and Claude's reasoning streams into
the same collapsible thinking panel you'd see on a direct API connection — a real
thinkingblock (with its signed continuation token) ahead of the answer, frame-for-frame the Anthropic wire shape. The reasoning context is preserved across tool calls, just like native. - 🎚 Reasoning effort that actually works.
/effort low|medium|high|xhigh|max, thethink/think harder/ultrathinkkeywords,CLAUDE_EFFORT— the effort you pick is read from the realoutput_config.effortwire and forwarded upstream, so dialing reasoning up or down genuinely changes how hard the model thinks. (curl -iand you'll see the applied effort echoed back in anx-copilot-reverse-effortheader.) - 🪟 True 1M-context models. 1M-window models show up in Claude Code's native picker with the right badge, and copilot-reverse writes the correct context-window hint so the client sizes its context bar and auto-compaction to the real window — no more "context 100%" at 15%.
- 🛠 Tool use, vision, web search — both directions. Function/tool calls translate faithfully each
way (even models that emit tool calls as inline XML are recovered), images round-trip, and
web_searchruns server-side through the gateway and comes back as a grounded answer — no tool leaks to the client. - 📊 Accurate usage. Real prompt/completion token counts, with cached tokens split out, so Claude Code's context bar and cost reflect what actually happened.
- 🛡 It never freezes. If a model degenerates (loops on one token, never stops), the proxy cuts the
stream cleanly as
max_tokensinstead of hanging your session — native Claude self-stops, and so does this.
Stability and accuracy are the north star: using Claude through the proxy must feel exactly like native Claude. Every feature above is covered by a live, real-Copilot end-to-end test.
Connect your own tools
Already have something that speaks OpenAI or Anthropic? Point it here:
- OpenAI-compatible:
http://127.0.0.1:7891/openai - Anthropic-compatible:
http://127.0.0.1:7891/anthropic
Any API key value works locally (it's your machine). Example:
export ANTHROPIC_BASE_URL=http://127.0.0.1:7891/anthropic
export ANTHROPIC_API_KEY=local
claudeShare it on your network (LAN mode)
By default the proxy is localhost — bound to 127.0.0.1, reachable only from this machine. To let
another device (a second laptop, a phone, a teammate) use it, run /network and switch to LAN:
- The worker rebinds to all interfaces and the panel shows your LAN URL (e.g.
http://192.168.1.5:7891) and a generated access key. - Your own machine keeps working with no key. The key is required only for requests coming from other machines — anything from this host over
127.0.0.1is served as before. So your local Claude Code / Codex need no change when you flip to LAN. - On the other machine, point your tool at that URL plus the protocol path —
…:7891/anthropicfor Claude Code,…:7891/openaifor Codex/OpenAI — and send the key:Authorization: Bearer <key>(OpenAI/Codex) orx-api-key: <key>(Anthropic/Claude Code). A remote request without a valid key is rejected (401).
# On the remote machine — Claude Code against the shared proxy:
export ANTHROPIC_BASE_URL=http://192.168.1.5:7891/anthropic
export ANTHROPIC_API_KEY=<the key from /network>
claudeFor Codex on the remote machine, set the base URL (with the /openai path) and the key in
~/.codex/config.toml — the key goes in the experimental_bearer_token field:
# ~/.codex/config.toml on the remote machine
[model_providers.copilot-reverse]
base_url = "http://192.168.1.5:7891/openai"
experimental_bearer_token = "<the key from /network>"- LAN is fail-closed: you can't enable it without a key, and the proxy refuses to serve if a key ever goes missing — it's never an open relay. Rotate the key anytime from the same panel (remote clients then re-paste the new key). Switch back to localhost to make it private again.
- Firewall: on Windows/macOS, the first time the worker binds all interfaces your OS may prompt to allow it — or you may need to add an inbound allow for port
7891. If a second machine can't connect while the panel shows⚠ LAN, the host firewall is the usual cause.
The supervisor/control plane (dashboard, restart) always stays on localhost — only the model proxy is ever exposed, and only behind the key.
The status bar, decoded
The bottom line of the app tells you everything at a glance:
model claude-opus-4.8 · daemon ready · claude u:✓ p:○ codex u:○ p:○ · /help- worker / daemon — green
readymeans the proxy is up and self-healing. - claude u:✓ p:○ — Claude Code is configured at the user (global) level, not in this project. Read live from your real config files.
- net — your access mode:
localhost(private) or a highlighted⚠ LANwhen the proxy is shared on the network (run/networkto change).
Troubleshooting
"context 100%" or /compact fails in Claude Code
Re-run /setup-claude and pick a 1M model (e.g. claude-opus-4.8 (1M)). copilot-reverse writes
the right context-window hint so the client stops assuming a small window. Then restart Claude Code.
"GitHub login expired" Your Copilot session lapsed. You don't need to restart anything — when a chat fails, copilot-reverse detects it and tells you right there:
assistant error: 401 authentication_error: GitHub login expired
↳ your GitHub login looks expired — run /login to sign in againJust type /login, complete the device-code prompt, and you're back — the worker reloads the new
token automatically. (Switching accounts? /logout first, then /login.)
A request failed and I don't know why
Type /logs (or ask "why did that fail?"). Every failure is captured with its real upstream
message. Still stuck? /report opens a pre-filled GitHub issue with diagnostics — never your
prompt content.
Want to undo everything
/reset-claude and /reset-codex remove exactly the keys copilot-reverse added and leave the rest
of your config untouched.
Good to know
- Your data stays local. The app proxies between your editor and Copilot on
127.0.0.1. Your GitHub token lives only in~/.copilot-reverse/creds.jsonon your own disk. - It heals itself. If the proxy crashes, the supervisor restarts it with backoff and records why.
- A cut-short stream is flagged, not hidden. When the runaway guard ends a degenerate stream early,
it's tagged in
/logsand/reportfiles a prefilled issue — so the rare bad turn is easy to surface. - Tunable.
~/.copilot-reverseconfig covers ports, restart backoff, and the GitHub-token heartbeat interval; defaults are sensible, override only if needed. - Unofficial endpoints. This uses community-documented Copilot endpoints with your own subscription. It may break if GitHub changes them — that's the trade-off for not needing extra keys.
Architecture
Three processes, one terminal app:
- TUI (Ink) — the
copilot-reverseprocess: REPL + slash commands + a claude-agent-sdk assistant (which dogfoods copilot-reverse's own Anthropic endpoint). - Supervisor (:7890) — control API + SQLite + self-healing worker supervision.
- Worker (:7891) — OpenAI
/openai/chat/completions+ Anthropic/anthropic/v1/messages→ Copilot, with tool-use translation both ways. Each protocol also serves a…/modelsdiscovery endpoint.
Development
Requires Node >=20.
npm install && npm test && npm run buildEnd-to-end tests
The e2e/ folder holds cross-module end-to-end scenarios (real worker + supervisor +
TUI wiring, fake Copilot provider). The case catalog is e2e/cases.md and the
latest run is e2e/RESULTS.md.
Every code change must keep the full e2e suite green. npm test runs it (the suite is
included in the default vitest run); npm run test:e2e runs only the e2e cases. After a change,
re-run and update e2e/RESULTS.md.
Test notes
- TUI input tests (
tests/tui/app.test.tsx): the test waits ~30 ms afterrender()before writing tostdin. This is not flakiness padding — Ink'suseInputsubscribes to stdin asynchronously after mount, so writes issued in the same tick asrender()are dropped. The delay lets the subscription attach; assertions are otherwise unchanged.
Questions or bugs? Use /report from inside the app, or open an issue on
GitHub. Happy hacking. 🚀