╔══════════════════════════════════════════════════════╗
║ ║
║ ● Ask · Plan · Agent ║
║ ┌──────────────────────────────────────────────┐ ║
║ │ > How do I add auth to this Express app? │ ║
║ │ │ ║
║ │ I'll set up Passport.js with JWT tokens. │ ║
║ │ Here's a 4-step plan: │ ║
║ │ │ ║
║ │ 1. Install dependencies ○ low risk │ ║
║ │ 2. Create auth middleware ○ low risk │ ║
║ │ 3. Add login route ● medium risk │ ║
║ │ 4. Protect endpoints ○ low risk │ ║
║ │ │ ║
║ │ [Send to Agent ▶] │ ║
║ └──────────────────────────────────────────────┘ ║
║ ┌─ Terminal ───────────────────────────────────┐ ║
║ │ $ npm install passport passport-jwt bcrypt │ ║
║ │ ✓ 3 packages installed │ ║
║ └──────────────────────────────────────────────┘ ║
╚══════════════════════════════════════════════════════╝
An unofficial, open-source desktop coding agent for GitHub.
Ask questions. Generate plans. Let the agent execute — with your approval at every step.
Getting Started · How It Works · Architecture · Contributing · Security
GitHub Copilot coding agents are powerful — but they live inside VS Code or the browser. If you want a standalone desktop experience that talks directly to GitHub Models and the Copilot SDK, nothing exists yet.
This project fills that gap: a native desktop app where you can ask a model anything, plan multi-step changes with risk visibility, and hand the plan to an agent that executes it — with explicit permission gates before every file write, shell command, or network call.
It is unofficial and community-driven. Not affiliated with GitHub or Microsoft.
| Mode | What It Does | Powered By |
|---|---|---|
| Ask | Multi-turn chat with any GitHub Models model. Attach workspace files as context. Stream responses in real time. | GitHub Models API |
| Plan | Describe what you want. Get a structured plan with steps, affected files, and risk levels. Review before anything happens. | GitHub Models API |
| Agent | Execute the plan. The agent reads files, writes code, runs shell commands — each action requires your explicit approval. | Copilot SDK |
Every agent action passes through a permission gate:
read file → auto-approved within workspace
write file → diff shown, you approve or reject
shell command → risk-classified (safe / review / dangerous)
dangerous cmd → blocked by default, override requires confirmation
Shell commands are classified by a risk engine before they reach you:
| Classification | Examples | Behavior |
|---|---|---|
| Safe | ls, git status, cat, pwd |
Auto-approved |
| Review | npm install, node script.js |
Show for approval |
| Dangerous | rm -rf, sudo, curl | bash |
Blocked + warning |
Bring-your-own-key support is planned, but it is intentionally hidden in this build until provider routing and model selection are fully wired.
- GitHub browser sign-in + Device Flow + PAT — local loopback auth for development, backend auth-service support for production-style sign-in, and secure token storage via the OS keychain
- Model picker — browse the full GitHub Models catalog, grouped by publisher, with capability badges
- Monaco diff viewer — review every proposed file change in a real code editor
- Integrated terminal — xterm.js panel for command output and interaction
- Plan → Agent handoff — one click to convert a plan into an agent execution
- Session persistence — resume agent sessions across app restarts
- Cross-platform — Windows, macOS, Linux builds via electron-builder
- Node.js ≥ 20
- pnpm ≥ 9 (
npm install -g pnpm) - A GitHub account (for GitHub OAuth / Models API access)
# Clone
git clone https://github.com/AniketJoshi/github-agent-desktop.git
cd github-agent-desktop
# Install dependencies
pnpm install
# Configure local loopback auth
cp .env.example .env
# Edit .env — add your GitHub OAuth App credentials for local development
# Start dev mode (hot-reload)
pnpm devFor development, the desktop app can still use a loopback GitHub OAuth App directly:
GITHUB_CLIENT_ID=...
GITHUB_CLIENT_SECRET=...
GITHUB_CALLBACK_URL=http://127.0.0.1:48163/callbackThis is the fastest setup for local work, but it is not the recommended production distribution model because the desktop app is a public client.
This repo now also includes a small backend auth service under auth-service/ for hosted OAuth exchange.
Use that path when you want:
- desktop installs that do not require users to edit
.env - the GitHub client secret to stay on the server
- a browser login flow that redirects back into the desktop app through a custom protocol
Minimal setup:
# Terminal 1 — desktop app
pnpm dev
# Terminal 2 — auth service
pnpm auth:service:typecheck
pnpm auth:service:build
pnpm auth:service:startThen configure the desktop app with:
GITHUB_AUTH_SERVICE_URL=http://localhost:3001
DESKTOP_AUTH_CALLBACK_URL=github-agent://auth/callbackSee docs/auth-architecture.md for the full hosted flow.
- Click Continue with GitHub
- Your browser opens for sign-in
- After approval, the desktop app stores your token securely and restores focus
- Pick a model from the catalog
- Start with Ask mode — type a question
- Switch to Plan to generate a structured plan
- Hit Send to Agent to execute it
pnpm build:win # Windows → .exe / portable
pnpm build:mac # macOS → .dmg
pnpm build:linux # Linux → .AppImage / .debYou chat. The model streams back. Workspace files can be attached as context so the model understands your codebase.
You: How should I structure the database layer for this Express app?
Model: Based on your project structure, I'd recommend a repository pattern...
[streams in real time via SSE]
Describe an objective. The model returns a structured JSON plan:
{
"goal": "Add JWT authentication to the Express API",
"assumptions": ["Express 4.x", "PostgreSQL for user storage"],
"steps": [
{ "title": "Install dependencies", "files": ["package.json"], "risk": "low" },
{ "title": "Create auth middleware", "files": ["src/middleware/auth.ts"], "risk": "low" },
{ "title": "Add login/register routes", "files": ["src/routes/auth.ts"], "risk": "medium" },
{ "title": "Protect existing routes", "files": ["src/routes/api.ts"], "risk": "low" }
]
}Each step shows affected files and a risk badge. You review, reorder, or remove steps before proceeding.
The Copilot SDK takes the plan and executes it. Every tool invocation surfaces in the UI:
▸ Reading src/routes/api.ts ✓ auto-approved
▸ Writing src/middleware/auth.ts ⏸ awaiting your approval
┌─ Diff ──────────────────────────────────────┐
│ + import jwt from 'jsonwebtoken' │
│ + export function authenticate(req, res, next) { │
│ + ... │
└──────────────────────────────────────────────┘
[Approve] [Reject]
You stay in control. Nothing writes to disk or runs a command without your say.
┌─────────────────────────────────────────────────────────────┐
│ Electron Main Process │
│ │
│ ┌──────────┐ ┌──────────────┐ ┌────────────────────────┐ │
│ │ Auth │ │ GitHub Models│ │ Copilot SDK │ │
│ │ │ │ API │ │ (adapter.ts only) │ │
│ │ • OAuth │ │ • Catalog │ │ • Session management │ │
│ │ • Device │ │ • Inference │ │ • Permission handling │ │
│ │ • PAT │ │ • Streaming │ │ • Tool execution │ │
│ └──────────┘ └──────────────┘ └────────────────────────┘ │
│ ┌──────────────────────── auth-service ───────────────────┐ │
│ │ • GitHub OAuth callback │ │
│ │ • Code → token exchange │ │
│ │ • One-time desktop grant issuance │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
│ ┌──────────┐ ┌──────────────┐ ┌────────────────────────┐ │
│ │Workspace │ │ Shell │ │ Services │ │
│ │ • Repo │ │ • Terminal │ │ • ask-service │ │
│ │ • Files │ │ • Risk │ │ • plan-service │ │
│ │ • Guard │ │ classifier │ │ • agent-service │ │
│ └──────────┘ └──────────────┘ └────────────────────────┘ │
│ │
│ ┌──────────────────────────────────────────────────────────┐│
│ │ IPC Layer — Zod-validated on every handle() ││
│ └──────────────────────────────────────────────────────────┘│
├──────────────────────────────────────────────────────────────┤
│ Preload (context bridge) │
├──────────────────────────────────────────────────────────────┤
│ Renderer (React 19) │
│ │
│ ┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐ ┌───────────┐ │
│ │ Auth │ │ Models │ │ Chat │ │ Plan │ │ Agent │ │
│ │ Login │ │ Picker │ │ Thread │ │ View │ │ RunView │ │
│ │ Chip │ │ │ │ Prompt │ │ Cards │ │ ToolList │ │
│ └────────┘ └────────┘ └────────┘ └────────┘ └───────────┘ │
│ │
│ ┌────────────────────────────────────────────────────────┐ │
│ │ Zustand Stores: auth, models, session, workspace, ui │ │
│ └────────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────┘
| Decision | Rationale |
|---|---|
| Single SDK import file | adapter.ts is the only file that touches @github/copilot-sdk. If the SDK breaks, you update one file. |
| Zod on every IPC boundary | The renderer is untrusted. Every ipcMain.handle validates input with a Zod schema before processing. |
| safeStorage for tokens | Tokens are encrypted via the OS keychain (Windows Credential Manager / macOS Keychain / libsecret). Never stored as plaintext. |
| Path traversal guard | Every file operation is checked against the workspace root + path.sep. No ../ escape possible. |
| Risk classifier for shell | Shell commands pass through regex-based classification before reaching the user. Dangerous patterns are blocked by default. |
| contextIsolation + no nodeIntegration | The renderer has zero access to Node.js APIs. Everything goes through the typed preload bridge. |
auth-service/ # Optional hosted OAuth exchange service
├── src/
│ ├── config.ts # Env validation
│ ├── server.ts # /start, /callback, /exchange
│ ├── services/ # GitHub OAuth, state, grants
│ └── lib/pkce.ts # PKCE helpers
docs/
├── auth-architecture.md # Production auth flow and protocol design
src/
├── shared/ # Shared between main + renderer
│ ├── types.ts # All domain types
│ ├── events.ts # IPC channel constants
│ └── ipc-schemas.ts # Zod schemas for every IPC call
├── main/ # Electron main process
│ ├── index.ts # Entry point
│ ├── windows.ts # BrowserWindow creation
│ ├── ipc.ts # All handle() registrations
│ ├── auth/ # OAuth, device flow, PAT, token store
│ ├── github/ # Models API catalog + inference
│ ├── copilot/ # SDK adapter + permission handling
│ ├── services/ # Ask, Plan, Agent business logic
│ ├── workspace/ # Repo management + path guard
│ └── shell/ # Terminal execution + risk classifier
├── preload/
│ └── index.ts # contextBridge typed API
└── renderer/
├── main.tsx # React entry
├── app/
│ ├── App.tsx # Root component with auth gate
│ ├── store/ # Zustand stores (6 stores)
│ ├── layout/ # Topbar, Sidebar, BottomPanel, Inspector
│ └── features/ # Auth, Models, Chat, Plan, Agent, Settings
└── styles/
├── tokens.css # Design tokens (oklch palette)
└── global.css # Base styles + Tailwind
| Command | Purpose |
|---|---|
pnpm dev |
Start in development mode with hot reload |
pnpm build |
Production build (main + preload + renderer) |
pnpm auth:service:typecheck |
Type-check the backend auth service |
pnpm auth:service:build |
Compile the backend auth service |
pnpm auth:service:start |
Start the backend auth service |
pnpm test |
Run unit tests (Vitest) |
pnpm test:coverage |
Unit tests with V8 coverage report |
pnpm test:e2e |
Run E2E tests (Playwright + Electron) |
pnpm typecheck |
TypeScript type checking (both tsconfigs) |
pnpm lint |
ESLint check |
pnpm format |
Prettier format all source files |
pnpm build:win |
Build Windows distributables (.exe) |
pnpm build:mac |
Build macOS distributables (.dmg) |
pnpm build:linux |
Build Linux distributables (.AppImage, .deb) |
| Layer | Technology |
|---|---|
| Desktop shell | Electron 34 |
| UI framework | React 19 |
| Language | TypeScript 5.9 (strict) |
| Build | electron-vite 5 (Vite 7 under the hood) |
| Styling | Tailwind CSS 4 with oklch design tokens |
| State | Zustand 5 |
| AI (Ask/Plan) | GitHub Models API (streaming SSE) |
| AI (Agent) | @github/copilot-sdk 0.2.x |
| Code viewer | Monaco Editor |
| Terminal | xterm.js |
| Animation | Framer Motion 12 |
| Markdown | react-markdown + remark-gfm + rehype-highlight |
| Icons | Lucide React |
| IPC validation | Zod 3.25 |
| Tests | Vitest 3 + Playwright |
| Packaging | electron-builder |
| CI/CD | GitHub Actions |
This app runs an AI agent that can read files, write code, and execute shell commands on your machine. Security is not optional.
| Boundary | Protection |
|---|---|
| Renderer ↔ Main | contextIsolation: true, nodeIntegration: false. Every IPC input Zod-validated. |
| File system | Path traversal guard rejects any access outside workspace root. |
| Shell execution | Risk classifier categorizes every command. Dangerous commands blocked. All require approval. |
| Token storage | OS-level encryption via Electron safeStorage (Credential Manager / Keychain / libsecret). |
| Permissions | Every agent tool invocation surfaces in the UI. Write and shell ops require explicit user approval. |
| CSP | Content Security Policy headers on the renderer. No eval(), no innerHTML. |
| Dependencies | Copilot SDK is in optionalDependencies — the app works without it (Ask/Plan still function). |
Found a vulnerability? See SECURITY.md for responsible disclosure.
We welcome contributions! See CONTRIBUTING.md for setup instructions, commit conventions, and the PR process.
Quick version:
git clone https://github.com/AniketJoshi/github-agent-desktop.git
cd github-agent-desktop
pnpm install
cp .env.example .env
pnpm dev # hack away
pnpm test # before you push- v0.1 — Current: Ask, Plan, Agent with GitHub OAuth + Models + Copilot SDK
- v0.2 — Session history persistence, conversation export, file context improvements
- v0.3 — BYOK Ask/Plan, then BYOK Agent mode once provider routing is stable
- v0.4 — MCP tool support, custom tool definitions
- v0.5 — Multi-workspace support, project switching
- v1.0 — Stable release with auto-update
MIT — use it, fork it, ship it.
Built by Aniket Joshi and contributors.
Not affiliated with GitHub or Microsoft. GitHub, Copilot, and GitHub Models are trademarks of their respective owners.