Autonomous AI agent teams for GitHub Copilot. Spawn a team of specialized agents — developers, QA engineers, code reviewers — that collaborate on real software projects. A lead agent decomposes your mission into tasks, spawns workers, and coordinates the pipeline while an autonomy engine keeps everything moving.
Built on the GitHub Copilot SDK.
- Node.js 22+
- GitHub CLI with Copilot extension installed, authenticated, and on your PATH
- Install:
gh extension install github/gh-copilot - Verify:
gh copilot --version
- Install:
- A GitHub account with Copilot access (any plan with agent mode)
git clone https://github.com/nkhoit/copilot-teams.git
cd copilot-teams
npm install
npm run buildnpm run cpt -- daemon start
# or: npx tsx src/cli.ts daemon startThe daemon runs on http://localhost:3742 by default (override with --port).
npm run cpt -- team create my-team \
--mission "Build a REST API for a todo app with Express, SQLite, and vitest tests" \
--dir /path/to/projectnpm run cpt -- agent add my-team --id lead --role "Tech Lead" --model claude-opus-4.6The first agent added becomes the team lead. The mission is delivered automatically — the lead will decompose it into tasks, spawn workers (developers, QA, reviewers), and coordinate the team without further prompting.
npm run cpt -- team status my-team # Agents, tasks, team state
npm run cpt -- tasks my-team # Task board
npm run cpt -- activity my-team # Full activity feednpm run cpt -- send my-team "message" # Message the lead
npm run cpt -- dm my-team <agentId> "message" # DM a specific agentnpm run cpt -- team delete my-team # Delete a specific team
npm run cpt -- daemon stop # Stop the daemon- You describe a mission → the lead agent receives it
- Lead creates a plan → optionally pauses for your approval via
team_request_input - Lead spawns workers → each with a specific role, model, and working directory
- Lead creates tasks with dependency chains → tasks auto-unblock as dependencies complete
- Workers claim and execute tasks → writing code, running tests, doing reviews
- Workers communicate via DMs → reporting blockers, sharing findings
- Autonomy engine nudges → detects idle agents, deadlocks, completed pipelines
- Lead declares mission complete → all agent sessions are disconnected to save tokens
The lead chooses which agents to spawn and which model each uses. Common patterns:
| Role | Recommended Model | Why |
|---|---|---|
| Tech Lead | claude-opus-4.6 |
Best at planning, decomposition, coordination |
| Backend Developer | claude-sonnet-4 |
Fast, capable coder for implementation tasks |
| QA Engineer | gpt-5.4 |
Strong at finding edge cases, writing thorough tests |
| Code Reviewer | claude-opus-4.6 |
Best at security analysis, type safety, best practices |
Default model is claude-opus-4.6. Override per-agent with --model when adding agents, or let the lead choose when spawning workers.
┌─────────────────────────────────────────────────────────┐
│ Daemon (Node.js process, port 3742) │
│ │
│ ┌─────────────┐ ┌──────────────┐ ┌───────────────┐ │
│ │ Gateway │ │ TeamRegistry │ │ AutonomyEngine│ │
│ │ REST + WS API│ │ per-team │ │ per-team │ │
│ └──────┬───────┘ │ orchestrator │ │ event nudges │ │
│ │ └──────┬───────┘ │ + heartbeat │ │
│ │ │ └───────┬───────┘ │
│ │ ┌──────┴───────┐ │ │
│ └─────────►│ Orchestrator │◄─────────┘ │
│ │ │ │
│ │ ┌──────────┐ │ │
│ │ │TeamState │ │ SQLite per team │
│ │ │ (SQLite) │ │ ~/.copilot-teams/ │
│ │ └──────────┘ │ teams/<id>/ │
│ │ │ state.db │
│ │ Sessions: │ config.json │
│ │ lead ──────►│──► Copilot SDK │
│ │ worker-1 ──►│──► Copilot SDK │
│ │ worker-2 ──►│──► Copilot SDK │
│ └──────────────┘ │
└─────────────────────────────────────────────────────────┘
| Component | File | Purpose |
|---|---|---|
| CLI | src/cli.ts |
cpt command — thin REST client for the daemon |
| Gateway | src/gateway.ts |
Express REST API + WebSocket for real-time events |
| Daemon | src/daemon.ts |
Process lifecycle, PID file, graceful shutdown |
| TeamRegistry | src/team-registry.ts |
Multi-team CRUD, event forwarding, persistence |
| Orchestrator | src/orchestrator.ts |
Per-team agent management, messaging, missions |
| TeamState | src/team-state.ts |
SQLite persistence — agents, tasks, messages, activity, tool calls |
| TeamTools | src/team-tools.ts |
Tools injected into each agent via defineTool() |
| AutonomyEngine | src/autonomy-engine.ts |
Event-driven nudges + heartbeat to keep teams moving |
| RoleTemplates | src/role-templates.ts |
Reusable agent role templates (.md files) |
Each agent gets team coordination tools injected into their Copilot session:
| Tool | Available To | Description |
|---|---|---|
team_dm |
All | Direct message another agent |
team_get_roster |
All | See who's on the team |
team_get_tasks |
All | View the task board |
team_create_task |
All | Create a new task with dependencies |
team_claim_task |
All | Claim a pending task (lead cannot claim tasks assigned to others) |
team_complete_task |
All | Mark a task done with results (lead cannot complete others' tasks) |
team_request_input |
All | Signal waiting for user input — sets status to "waiting" |
team_spawn_agent |
Lead only | Spawn a new worker with role, model, and template |
team_complete_mission |
Lead only | Declare mission complete, disconnect all agents |
team_reject_task |
Lead only | Reject a completed task with feedback, send back for rework |
team_list_templates |
Lead only | Discover available role templates |
Each team has an autonomy engine that monitors events and nudges the lead when action is needed:
- Task completed → "Agent X finished task Y. 3 pending, 1 blocked remaining."
- All tasks done → "All tasks complete. Is the mission fulfilled?"
- Deadlock detected → "All agents are idle but work remains. Assign tasks."
- Team resumed → "Team resumed. Review tasks and take action."
- Heartbeat → Periodic check (2min active, 10min idle) for stuck teams.
Create reusable agent archetypes as .md files. The lead can discover and apply them when spawning workers.
Project-specific templates (checked first):
<project>/.copilot-teams/roles/
├── backend-dev.md
├── qa-engineer.md
└── code-reviewer.md
Global templates (fallback):
~/.copilot-teams/roles/
├── backend-dev.md
└── qa-engineer.md
Template content becomes the agent's system prompt. Use team_list_templates to discover available templates, and pass template: "backend-dev" when spawning.
Teams survive daemon restarts:
- Team config persisted to
~/.copilot-teams/teams/<id>/config.json - Team state (agents, tasks, messages, activity) in
~/.copilot-teams/teams/<id>/state.db - Copilot sessions persisted to disk by the SDK — resumed via
client.resumeSession() - On restart, the daemon auto-detects persisted teams and restores them with full conversation history
Every tool call made by every agent (including Copilot's built-in file edits, shell commands, etc.) is logged to the tool_calls table in SQLite. Query via the REST API:
# All tool calls for a team
curl http://localhost:3742/api/teams/my-team/tool-calls
# Filtered by agent
curl http://localhost:3742/api/teams/my-team/tool-calls?agent=backend-dev&limit=50cpt daemon start [--port 3742] Start the daemon
cpt daemon stop Stop the daemon
cpt daemon status Show daemon info
cpt team create <id> [--mission "..."] [--dir /path]
cpt team list List all teams
cpt team status <id> Full team status (agents, tasks, state)
cpt team pause <id> Pause a team
cpt team resume <id> Resume a paused team
cpt team delete <id> Delete a team
cpt mission get <team> Get current mission
cpt mission set <team> "text" Set/update mission
cpt agent list <team> List agents on a team
cpt agent add <team> --id <id> --role "..." [--dir /path] [--model ...]
cpt agent remove <team> <agentId> Remove an agent
cpt send <team> "message" Send message to the lead
cpt dm <team> <agentId> "message" DM a specific agent
cpt activity <team> [--limit N] Activity feed
cpt tasks <team> [--status ...] List tasks (filter: pending, in_progress, done, blocked)
All endpoints are under http://localhost:3742/api.
| Method | Endpoint | Description |
|---|---|---|
| GET | /health |
Health check |
| GET | /daemon/status |
Daemon info, uptime, team list |
| POST | /teams |
Create a team { id, mission?, workingDirectory? } |
| GET | /teams |
List all teams |
| GET | /teams/:id |
Full team status |
| DELETE | /teams/:id |
Delete a team |
| POST | /teams/:id/pause |
Pause a team |
| POST | /teams/:id/resume |
Resume a team |
| POST | /teams/:id/agents |
Add agent { id, role, model?, workingDirectory?, template? } |
| DELETE | /teams/:id/agents/:agentId |
Remove an agent |
| POST | /teams/:id/messages |
Send message to lead { content } |
| POST | /teams/:id/dm/:agentId |
DM an agent { content } |
| GET | /teams/:id/tasks |
List tasks (optional ?status=pending) |
| POST | /teams/:id/tasks |
Create task { id, title, description?, dependsOn? } |
| GET | /teams/:id/mission |
Get mission |
| PUT | /teams/:id/mission |
Set mission { text } |
| GET | /teams/:id/activity |
Activity feed (optional ?limit=50) |
| GET | /teams/:id/tool-calls |
Tool call log (optional ?agent=<id>&limit=100) |
Connect to ws://localhost:3742/ws for real-time events. Filter by team with ?team=<id>.
Events: agent.joined, agent.left, agent.thinking, agent.waiting, task.created, task.claimed, task.completed, task.rejected, message.dm, mission.updated, mission.completed, team.created, team.deleted, team.state_changed.
npm test # Run all tests (123 tests)
npm run test:watch # Watch mode
npm run dev # Start daemon in dev mode (tsx, no build needed)
npm run build # Compile TypeScript to dist/src/
├── index.ts # Entry point — starts the gateway
├── cli.ts # cpt CLI tool
├── gateway.ts # Express REST + WebSocket server
├── daemon.ts # Daemon lifecycle (PID file, shutdown)
├── team-registry.ts # Multi-team management
├── orchestrator.ts # Per-team agent coordination
├── team-state.ts # SQLite persistence layer
├── team-tools.ts # Agent tools (defineTool bindings)
├── autonomy-engine.ts # Event-driven nudges + heartbeat
├── role-templates.ts # Template resolver (project + global)
├── types.ts # Shared TypeScript interfaces
└── test/
├── mocks/
│ └── copilot-sdk.ts # MockCopilotSession + MockCopilotClient
├── team-state.test.ts # 43 tests — SQLite layer
├── team-tools.test.ts # 34 tests — tool bindings + guards
├── team-registry.test.ts # 26 tests — multi-team + crash recovery
├── autonomy-engine.test.ts # 11 tests — nudges + heartbeat
└── role-templates.test.ts # 9 tests — template resolution
skills/
└── copilot-teams.md # Skill file for agent import
All persistent data lives under ~/.copilot-teams/:
~/.copilot-teams/
├── daemon.json # PID file (port, pid, started time)
├── roles/ # Global role templates
│ └── *.md
└── teams/
├── <team-id>/
│ ├── config.json # Team config (mission, workingDirectory)
│ └── state.db # SQLite (agents, tasks, messages, activity, tool_calls)
└── ...
MIT