Live app: https://web-zeynepbastas-zeynepbastas-projects.vercel.app
API: https://dispatch-api.fly.dev
Voice and typed command orchestration for local coding agents.
Dispatch lets developers control coding agents on their local machine by speaking or typing commands in a hosted dashboard. You issue a request — via voice call, Telegram, or the web UI — and your local machine executes it through a connected companion process. An AI security layer reviews every command before it runs, and you approve or reject it hands-free by speaking.
┌──────────────┐ ┌──────────────┐ ┌──────────────────┐
│ Voice Call │────▶│ Twilio │────▶│ │
│ (phone) │ │ │ │ FastAPI │
└──────────────┘ └──────────────┘ │ Backend │
│ │
┌──────────────┐ │ - Intent parse │
│ Telegram │─────────────────────────▶│ - Security scan │
│ Bot │ │ - Approval gate │
└──────────────┘ │ │
└────────┬─────────┘
┌──────────────┐ │
│ Web UI │◀──────── dashboard / logs ────────┤
│ (Next.js) │ │
└──────────────┘ ┌────────▼─────────┐
│ Local Agent │
│ Daemon │
│ (companion) │
└────────┬─────────┘
│
┌────────▼─────────┐
│ Claude / Cursor │
│ CLI │
└──────────────────┘
- User speaks, types in the dashboard, or sends a Telegram message.
- Backend parses the intent (via Groq LLM) and builds a CLI command.
- AI Security Analyzer classifies the command as
SAFE,WARNING, orHIGH_RISK. - Command is placed in
pending_approvalstate — the local agent will not run it yet. - User approves (by speaking "yes", "approve", etc. or clicking in the UI).
- Local agent daemon claims the command, executes it in the project directory, and streams logs back.
- Dashboard updates in real time with status and output.
User FastAPI Backend Security Analyzer Local Agent Daemon Claude/Cursor CLI
│ │ │ │ │
│──voice/text──────▶│ │ │ │
│ │──parse intent───────▶│ │ │
│ │ (Groq LLM) │ │ │
│ │◀─ intent JSON ───────│ │ │
│ │ │ │ │
│ │──analyze command────▶│ │ │
│ │ │─ classify ─────────▶│ │
│ │◀─ SAFE/WARNING/──────│ │ │
│ │ HIGH_RISK │ │ │
│ │ │ │ │
│ │── save command ──────────────────────────▶│ │
│ │ (pending_approval) │ │ │
│◀── dashboard ──────│ │ │ │
│ shows command │ │ │ │
│ │ │ │ │
│──approve──────────▶│ │ │ │
│ (voice/click) │── set approved ──────────────────────────▶│ │
│ │ │ │ │
│ │ │ │──claim command─────▶│
│ │ │ │──execute───────────▶│
│ │ │ │◀─ stream logs ──────│
│◀── live logs ──────│◀─────────────────────────────────────────│ │
| Layer | Technology |
|---|---|
| Backend | Python, FastAPI, Uvicorn |
| Database | Supabase (Postgres) |
| Frontend | Next.js 16, React 19, Tailwind CSS, shadcn/ui |
| Speech-to-text | Groq Whisper API |
| LLM (intent + security) | Groq (llama-3.3-70b-versatile) |
| Voice calls | Twilio |
| SMS verification | Twilio Verify |
| Local agent | Python daemon (local-agent/dispatch_local_agent.py) |
- Python 3.9+
- Node.js 18+
- A Supabase project
- A Groq API key
- (Optional) Twilio account for voice calls and SMS
git clone https://github.com/mxy680/dispatch.git
cd dispatch
cp .env.example .envFill in .env:
SUPABASE_URL=https://your-project.supabase.co
SUPABASE_SERVICE_ROLE_KEY=your-service-role-key
GROQ_API_KEY=your-groq-key
# Optional — for voice calls and SMS OTP
TWILIO_ACCOUNT_SID=
TWILIO_AUTH_TOKEN=
TWILIO_PHONE_NUMBER=
TWILIO_VERIFY_SERVICE_SID=
# Optional — for Telegram bot
TELEGRAM_BOT_TOKEN=
TELEGRAM_SECRET_TOKEN=
Fill in web/.env.local (copy from web/.env.local.example):
cp web/.env.local.example web/.env.localNEXT_PUBLIC_SUPABASE_URL=https://your-project.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=your-anon-key
In your Supabase dashboard, open the SQL Editor and run the migration files in order:
supabase/migrations/20260319000000_initial_schema.sql
supabase/migrations/20260319100000_init_schema.sql
supabase/migrations/20260319200000_add_terminal_access.sql
supabase/migrations/20260321000000_add_companion_tables.sql
supabase/migrations/20260321100000_add_provider_columns.sql
supabase/migrations/20260322000000_instances_project_agnostic.sql
Alternatively, if you have the Supabase CLI installed:
supabase db pushcd server
python -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -r requirements.txt
uvicorn main:app --reload --port 8000cd web
npm install
npm run devThe dashboard is available at http://localhost:3000.
The local agent daemon bridges the backend to your machine. Run it in the project directory you want to control:
python local-agent/dispatch_local_agent.py \
--backend-url http://localhost:8000 \
--project-path /absolute/path/to/your/project \
--agent-token <token-from-dashboard-settings>The agent token is generated in the dashboard under Settings → Agents → Create agent token.
Once the backend, frontend, and local agent are all running:
1. Connect your local agent
python local-agent/dispatch_local_agent.py \
--backend-url http://localhost:8000 \
--project-path /path/to/your/project \
--agent-token <token-from-settings>2. Issue a command
Open the dashboard at http://localhost:3000. In the Unified Command Center, type:
refactor the auth module to use async/await
Or call your Twilio number and speak it, or send it via Telegram.
3. Review the security classification
The AI Security Analyzer classifies the command. For the example above you'd see:
Risk: SAFE
Reason: Code refactoring operation with no destructive or network side effects.
A command like rm -rf /tmp/build would show HIGH_RISK and require explicit UI confirmation — voice approval is blocked for high-risk commands.
4. Approve and watch it run
Click Approve in the dashboard (or say "yes" / "approve" if you're on a voice call). The local agent claims the command, runs claude -p "refactor the auth module to use async/await" in your project directory, and streams the output back line by line into the dashboard log viewer.
Unified Command Center — Voice and typed input feed a single command timeline with real-time log streaming.
AI Security Analyzer — Every command is classified SAFE, WARNING, or HIGH_RISK by an LLM before execution. High-risk commands cannot be voice-approved and require explicit confirmation.
Approval Gate — Commands default to pending_approval. The local agent never executes a command without explicit user approval, preventing accidental destructive operations.
Voice Approval — Speak "yes", "approve", "run it", etc. to approve a pending command, or "no", "cancel" to reject. The intent router handles natural affirmations.
Telegram Bot — Send commands via Telegram. The bot parses intent, dispatches to the local agent, and replies with status.
Phone Calls — Call a Twilio number, speak your request, and the system transcribes and dispatches it.
Project Management — Commands are grouped by project with persistent task history.
Provider Support — Supports Claude Code CLI and Cursor CLI, with shell fallback for raw commands.
CSDS 493 quality artifacts — coverage report, mutation testing results, and CI pipeline details are documented in full in testing.md.
cd server
python -m pytest -q # run all 474 tests
python -m pytest --cov=. --cov-report=term-missing # with coverage report1. Mock-object testing is used throughout so the suite runs without real Supabase credentials, API keys, or network access. A shared conftest.py provides a chainable in-memory Supabase mock. Additional patches use unittest.mock to isolate every external dependency.
2. Property-based testing (Hypothesis) verifies invariants that hold for any input, not just hand-picked examples:
_normalize_level(s)always returns one of{SAFE, WARNING, HIGH_RISK}normalize_provider(s)always returns one of{cursor, claude, shell}build_provider_command(provider, prompt)always contains the prompt and required flags
3. Mutation testing with mutmut was applied to agents/command_builder.py and services/security_analyzer.py. Initial run found 70 surviving mutants in the security analyzer. Targeted tests reduced this to 2 (97% killed). The 2 remaining are equivalent mutants — the mutation produces identical observable behavior, making them impossible to kill without brittle tests. See demo 4/mutation_report.txt.
cd server && mutmut run && mutmut results4. CI/CD regression testing — GitHub Actions runs the full suite on every push. Every failing commit is caught before it reaches main.
Key test files:
| File | What it covers |
|---|---|
test_security_analyzer.py |
All HIGH_RISK/WARNING/SAFE patterns, LLM path, fallback, helpers |
test_dispatcher.py |
Agent dispatch pipeline, task resolution, terminal command creation |
test_command_builder.py |
Provider normalization, CLI command construction |
test_main_routes.py |
Settings, dashboard, tasks, agent, unified endpoints |
test_main_extra.py |
Helper functions, phone, project, dispatch routes |
test_main_extra2.py |
Device, agent-token, terminal, unified-reply, transcribe-text |
test_property_based.py |
Hypothesis property tests across three modules |
test_sidecar_store.py |
SQLite sidecar — conversation turns, state, command risk |
test_agents_and_llm.py |
copilot_agent, prompt_refiner, LLM service, Supabase client |
test_services.py |
Telegram and transcription services |
test_models.py |
Supabase model functions (51 tests) |
Overall: 88% across 474 tests — see demo 4/coverage_report.txt for the full breakdown.
Highlight modules:
agents/command_builder.py— 100%agents/copilot_agent.py— 100%agents/prompt_refiner.py— 100%agents/dispatcher.py— 93%services/security_analyzer.py— 99%services/telegram.py— 100%services/transcription.py— 100%services/llm.py— 97%services/phone_verification.py— 95%database/sidecar_store.py— 97%main.py— 79%
Claude Code and Cursor were used throughout development.
- Cursor was used for scaffolding Next.js components (the Risk Shield UI, Unified Command Center), backend refactoring, and writing Supabase migration DDL. Cursor's
@workspacecontext allowed generated components to match existing Tailwind configuration automatically. - Claude Code was used for test infrastructure work: diagnosing and fixing Python 3.9 compatibility issues across the codebase, building the conftest mock fixture, running and interpreting mutation testing results, and expanding the security analyzer test suite from 2 tests to 37 based on mutation findings.
All AI-generated code was reviewed and tested before merging.
Auto-generated HTML documentation for all backend modules is in api-docs/. Open api-docs/index.html in a browser after cloning. Generated with pdoc.
To regenerate:
cd server
pip install pdoc
PYTHONPATH=. pdoc agents.command_builder agents.dispatcher agents.copilot_agent \
agents.prompt_refiner services.security_analyzer services.llm services.transcription \
services.phone_verification database.models database.sidecar_store main \
--output-dir ../api-docsdispatch/
├── server/ # FastAPI backend
│ ├── main.py # API routes
│ ├── agents/ # Dispatcher, command builder
│ ├── services/ # LLM, security analyzer, Telegram, Twilio
│ ├── database/ # Supabase models and client
│ └── tests/ # Full test suite
├── web/ # Next.js frontend
│ ├── app/ # Pages and layout
│ ├── components/ # UI components
│ └── lib/voice/ # VAD loop, TTS, earcons
├── local-agent/ # Local agent daemon
│ └── dispatch_local_agent.py
├── companion/ # Electron desktop companion (scaffold)
├── cursor-extension/ # Cursor IDE extension (scaffold)
└── demo 4/ # Demo artifacts: coverage and mutation reports
| Member | Role | Key Contributions |
|---|---|---|
| Mark Shteyn | Full-stack Lead | Project initialization; Next.js frontend (dashboard, bento grid, shadcn/ui); FastAPI server bootstrap; SQLite → Supabase Postgres migration; Groq integration; Twilio SMS OTP; real-time log streaming; agent command claiming and stale-command recovery |
| Zeynep Baştaş | Testing, Backend & Project Coordination | Full pytest test suite (474 tests, 88% coverage); CI/CD GitHub Actions pipeline; mutation testing with mutmut; property-based testing with Hypothesis; rate limiting via slowapi; Twilio voice webhooks, call history API and call history page (frontend); end-to-end Twilio voice pipeline debugging and verification; database API endpoints for projects and tasks; real-time dashboard polling; initial SQLite database setup and CRUD; transcription error handling; Python 3.9 compatibility; module-level and function-level docstrings across all 16 source files (services, agents, database); pdoc HTML API docs generation; project-wide documentation (README, testing.md, docstrings, pdoc API docs); Trello board setup and sprint tracking; TA communication and in-team coordination |
| Paulo Aguiar | Integrations | Telegram bot (bulk implementation and webhook handler); local agent daemon; initial project structure and database schema for intent parsing and call logs |
| Ali Nawaf | Security & Agent Features | AI security analyzer; approval gate for sensitive voice commands; terminal agent connections with tokens; centralized agent orchestration; coding agent support (Claude/Cursor); access token cache, settings, and danger zone UI; Electron companion app scaffold; file watcher; intent parsing; voice agent transcription integration |
- AI-assisted development — Cursor handled frontend scaffolding and Claude Code handled test infrastructure, which cut boilerplate time significantly. Both tools were used with code review before merging.
- Security-first design — The approval gate and AI security analyzer were built early, so every subsequent feature inherited those guarantees without retrofit work.
- Mutation testing payoff — Running mutmut revealed 70 surviving mutants in the security analyzer that normal coverage metrics didn't surface. Targeted tests killed 68 of them (97%), leaving only 2 equivalent mutants that produce identical behavior and cannot be killed without brittle assertions. This gave far higher confidence in the most critical module than line coverage alone.
- Mock-based CI from day one — The shared
conftest.pySupabase mock let every contributor write and run tests without real credentials, and the GitHub Actions pipeline worked from the first commit.
- Finalize the database schema earlier — Mid-project schema changes required coordinating migrations across branches and occasionally blocked parallel work. A stable schema agreed on at week 2 would have removed integration friction.
- Add types to the backend up front — Adding Pydantic return types and annotations to
models.pyretroactively was slower than writing them first. Full typing at initial implementation would have caught bugs at development time instead of test time. - Invest in frontend tests in parallel with features — Backend coverage is 88%; frontend Vitest coverage is lower. Writing component tests alongside features would have improved UI confidence throughout the project.
MIT License — see LICENSE for details.
Built for CSDS 393/493 Software Engineering at Case Western Reserve University.