Every Copilot model. One login. Any device. Your server.
Self-hosted multi-model AI chat built on the official @github/copilot-sdk.
Autopilot agents · live reasoning traces · native GitHub tools · SDK-native customizations for agents, skills, prompts, instructions, and MCP servers.
Autopilot reads issue #88, implements the fix, runs tests, and opens a PR — zero intervention.
Independent project — not affiliated with GitHub. MIT licensed.
- Every Copilot model — Claude Opus 4.6, GPT-5.4, Gemini 3 Pro, Claude Sonnet 4.6, and more — switch mid-conversation, keep full history
- Autopilot agents — plan, code, run tests, and open PRs autonomously with live tool execution
- Extended thinking — live reasoning traces with collapsible "Thinking…" blocks
- SDK-native customizations — agents, skills, prompts, instructions, and MCP servers — configure in
~/.copilot/, toggle from the UI (details ↓) - Native GitHub tools — issues, PRs, code search, repos, Actions — built in via the GitHub MCP server
- Image & file attachments — drop images, code, CSVs, or directories with
@autocomplete; vision models analyze images inline - Issue & PR references — type
#to search and reference GitHub issues/PRs across all your repos - Persistent sessions — resume any conversation on any device; chat state survives browser close via server-side storage with cold resume
- CLI ↔ Browser sync — sessions started in the Copilot CLI appear in the browser and vice versa (details ↓)
- Push notifications — Web Push alerts when the browser is closed; full PWA support
- Plan & Fleet mode — editable execution plans with disk sync; multi-agent parallel execution
- Quota tracking — premium request usage, remaining balance, and reset date
- Accessible & responsive — WCAG 2.2 AA compliant: semantic landmarks, keyboard navigation, no keyboard traps (off-screen panels use
visibility:hidden), visible focus rings, screen-reader labels, sufficient colour contrast, and reduced-motion support across all views and viewports - Self-hosted — your data never leaves your server; deploy with Docker or
azd up
The app mirrors the Copilot SDK's native customization model. Configure once, use everywhere — CLI and browser stay in sync.
| Type | Location | How to use |
|---|---|---|
| Agents | ~/.copilot/agents/*.agent.md |
Select in Settings → active for session |
| Skills | Discovered by SDK | Toggle in Settings → model can invoke |
| Prompts | ~/.copilot/prompts/*.prompt.md |
Type /name in chat → autocompletes |
| Instructions | ~/.copilot/copilot-instructions.md |
Auto-discovered, shown in Settings |
| MCP Servers | ~/.copilot/mcp-config.json |
Toggle in Settings → tools available |
All paths also support repo-scoped variants (
.github/agents/,.github/prompts/,.github/instructions/,.github/mcp-config.json).
Source badges in Settings show where each customization was discovered: CLI (SDK runtime), User (~/.copilot), or Repo (.github/).
Prerequisites: GitHub account with Copilot (free tier works) + a GitHub OAuth App.
When creating the OAuth App, set Homepage URL to
http://localhost:3000and leave Authorization callback URL blank — the app uses Device Flow, so no callback is needed.
1. Set required environment variables
Copy .env.example to .env (or create .env) and fill in the two required values:
GITHUB_CLIENT_ID=<your-oauth-app-client-id> # From github.com/settings/developers
SESSION_SECRET=<random-32-byte-hex> # Generate: openssl rand -hex 322. Run
Previously cloned? Pull the latest changes first:
git fetch origin && git reset --hard origin/master
docker compose up --build
npm run devis an alias for the command above.
Docker is required — the @github/copilot CLI is installed inside the container and is a runtime dependency of the SDK. The app will not function without it.
Open localhost:3000. Log in with GitHub. Done.
| Variable | Required | Default | Purpose |
|---|---|---|---|
GITHUB_CLIENT_ID |
yes | — | Client ID from your GitHub OAuth App |
SESSION_SECRET |
yes | — | Random secret for cookie encryption — generate with openssl rand -hex 32 |
PORT |
— | 3000 |
HTTP server port |
ALLOWED_GITHUB_USERS |
— | — | Comma-separated GitHub usernames; omit to allow any authenticated user |
BASE_URL |
— | http://localhost:3000 |
Public URL — sets cookie domain and WebSocket origin validation |
All options
| Variable | Default | Purpose |
|---|---|---|
NODE_ENV |
development |
production enables secure cookies |
TOKEN_MAX_AGE_MS |
86400000 |
Force re-auth interval (24h) |
SESSION_POOL_TTL_MS |
300000 |
Session TTL when disconnected (5 min) |
MAX_SESSIONS_PER_USER |
5 |
Max concurrent tabs/devices |
COPILOT_CONFIG_DIR |
~/.copilot |
Share with CLI for bidirectional sync |
SESSION_STORE_PATH |
/data/sessions |
Persistent session directory |
SETTINGS_STORE_PATH |
/data/settings |
Per-user settings directory |
CHAT_STATE_PATH |
/data/chat-state |
Persisted chat state |
VAPID_PUBLIC_KEY |
— | Push notifications (base64url) |
VAPID_PRIVATE_KEY |
— | Push notifications (base64url) |
VAPID_SUBJECT |
— | Push subject (mailto: or https:) |
PUSH_STORE_PATH |
/data/push-subscriptions |
Push subscription storage |
azd env set DEPLOYER_IP_ADDRESS "$(curl -s https://api.ipify.org)"
azd upContainer Apps, ACR (Basic), Key Vault (RBAC-only), managed identity, Log Analytics, and TLS — all provisioned automatically. azd up prompts for GITHUB_CLIENT_ID if not already set.
VAPID keys, troubleshooting, and details
VAPID keys (optional, for push notifications):
node scripts/generate-vapid-keys.mjs
azd env set VAPID_PUBLIC_KEY "<key>"
azd env set VAPID_PRIVATE_KEY "<key>"
azd env set VAPID_SUBJECT "mailto:you@example.com"Troubleshooting:
- MANIFEST_UNKNOWN: Clear stale image tag with
azd env set SERVICE_WEB_IMAGE_NAME "" && azd up - ACR 403 Forbidden: Re-set deployer IP with
azd env set DEPLOYER_IP_ADDRESS "$(curl -s https://api.ipify.org)" && azd provision - Key Vault secret missing: Ensure
GITHUB_CLIENT_IDis set, thenazd provision
Sessions started in the Copilot CLI appear in the browser and vice versa. The app shares ~/.copilot/session-state/ with the CLI — plan edits sync in both directions automatically.
# docker-compose.yml — enable sync
volumes:
- ~/.copilot:/home/node/.copilotPush sessions to a remote instance without redeploying:
npm run sync:push -- https://your-app.azurecontainerapps.ioHow sync works, session bundling, and more
The SDK stores each session as ~/.copilot/session-state/{uuid}/ with workspace.yaml, plan.md, and checkpoint files. When you resume a session from the browser, the SDK restores conversation history automatically. For disk-only sessions (e.g. bundled into Docker), the app falls back to reading checkpoint files directly and injecting them as context.
Bundle sessions at build time (Azure / CI):
npm run bundle-sessions # snapshots ~/.copilot sessions
azd up # auto-runs via predeploy hookThe Sessions panel auto-refreshes every 30 seconds. Use COPILOT_CONFIG_DIR to customize the session-state path.
Browser ──WebSocket──▶ SvelteKit + server.js ──JSON-RPC──▶ Copilot SDK subprocess
- GitHub Device Flow login → token stored server-side only
- WebSocket opens → server spawns a
CopilotClientper user - SDK streams events → server forwards as typed JSON → Svelte re-renders in real-time
- On disconnect → session pooled with TTL, reconnect replays messages
Device Flow OAuth (same as GitHub CLI). Tokens are server-side only, never sent to the browser. Sessions are encrypted, rate-limited, and validated against GitHub's API on every WebSocket connect.
Full security details
- CSP headers, CSRF protection, HSTS, X-Frame-Options DENY
- Rate limiting: 200 req / 15 min per IP (HTTP) + 30 msg / min per WebSocket
- Secure cookies: httpOnly, secure (prod), sameSite: lax
- DOMPurify on all rendered markdown
- SSRF blocklist for MCP server URLs (IPv4 + IPv6 internal ranges, HTTPS required)
- 10,000 char message limit, 10MB upload limit, extension allowlist
- Per-tool permission prompts with 30s auto-deny countdown
- Token revalidation on every WebSocket connect
- CodeQL scanning + secret scanning via GitHub Advanced Security
- All API endpoints require GitHub authentication — no anonymous access
- Azure: Key Vault (RBAC-only), Basic ACR with deployer IP allowlist, managed identity for pulls
Screenshots
Desktop
![]() |
![]() |
| Autopilot agent — issue → PR, zero intervention | Extended thinking — live reasoning trace |
![]() |
![]() |
| Code generation with syntax highlighting | GitHub Device Flow login |
Tablet (iPad)
![]() |
![]() |
![]() |
![]() |
| Autopilot | Code gen | Reasoning | Login |
Mobile
![]() |
![]() |
![]() |
![]() |
| Autopilot | Code gen | Reasoning | Login |
SvelteKit 5 · Svelte 5 runes · TypeScript 5.7 · Node.js 24 · @github/copilot-sdk v0.2.0 · Vite · ws · Vitest · Playwright · Docker · Bicep
See CONTRIBUTING.md.
MIT











