Multi-agent SDLC orchestration with voice, GitHub, and human-in-the-loop approvals.
Send a voice note (or text) to your Telegram, WhatsApp, or Slack bot describing a feature. Voiceable breaks it down into 5 SDLC stages, writes code, opens a PR, runs tests, and merges — pausing for your approval at every step.
- You send a message (text or voice): "Build a REST API for task management"
- Planner agent decomposes it into user stories, risks, and scope
- You approve (or request revisions) via inline buttons
- Designer produces architecture, components, and API contracts
- You approve
- Implementer writes the code and a GitHub PR draft
- GitHub branch is created, files pushed, PR opened
- You approve
- Tester writes pytest tests and estimates CI coverage
- Test results posted as a PR comment
- You approve
- Integrator reviews the full pipeline
- You tap Merge PR & Close Issue — done
Each approval message shows the agent's reasoning (Verbose Reasoning Transparency). If you tap "Request Revision", the bot asks what to change and re-runs the stage with your feedback.
Human (voice/text)
│ Telegram / WhatsApp / Slack
▼
FastAPI Webhooks (/webhooks/{platform})
│
├─ VoiceService → Whisper STT → text
│ ← OpenAI TTS ← voice note reply
│
├─ ApprovalService → handles button taps & revision replies
│
└─ PipelineService → PipelineMachine (plans actions)
│ │
│ Execute Actions:
│ ├─ RunAgent(stage)
│ ├─ SendApproval → channel.send_approval()
│ ├─ CreateGitHubIssue
│ ├─ PushFilesAndOpenPR
│ └─ MergePRAndCloseIssue
│
└── SDLC Agents (spawned on demand, direct Anthropic API)
├─ PlannerAgent (claude-opus-4-6)
├─ DesignerAgent (claude-opus-4-6)
├─ ImplementerAgent (claude-sonnet-4-6)
├─ TesterAgent (claude-sonnet-4-6)
└─ IntegratorAgent (claude-haiku-4-5)
Human (voice/text)
│ Telegram / WhatsApp / Slack
▼
OpenClaw Gateway (channels, bindings, routing)
│
└─ OpenClaw Agent ──► POST /api/pipelines (start run)
──► POST /api/pipelines/{id}/approve (approval)
──► POST /api/pipelines/{id}/revision (revision)
◄── PipelineRunResponse (data + message_text)
│
└─ OpenClaw sends messages/approval UI to user
Voiceable (backend API — FSM, run state, GitHub)
└─ PipelineService → PipelineMachine
│ ├─ OpenClawAdapter ──► OpenClaw Gateway ──► LLM
│ ├─ CreateGitHubIssue
│ ├─ PushFilesAndOpenPR
│ └─ MergePRAndCloseIssue
└─ SQLite (PipelineRun state)
Channel webhook handling, approval button flows, and voice I/O move into OpenClaw
(Phases 2–4 of the migration). Set VOICEABLE_AGENT_BACKEND=openclaw to route
agent execution through OpenClaw while keeping channels in-process during the transition.
Human (voice/text)
│ Telegram / WhatsApp / Slack
▼
FastAPI Webhooks (/webhooks/{platform})
│
└─ PipelineService → PipelineMachine
│ ├─ NanobotAdapter ──► nanobot-ai LiteLLMProvider
│ │ ├─ OpenRouter
│ │ ├─ Anthropic
│ │ ├─ OpenAI
│ │ └─ ... (DeepSeek, Gemini, etc.)
│ ├─ CreateGitHubIssue
│ ├─ PushFilesAndOpenPR
│ └─ MergePRAndCloseIssue
└─ SQLite (PipelineRun state)
CREATED
│
PLANNING
│
AWAITING_PLAN_APPROVAL
│ approved
DESIGNING → AWAITING_DESIGN_APPROVAL
│ approved
IMPLEMENTING → AWAITING_IMPL_APPROVAL
│ approved
TESTING → AWAITING_TEST_APPROVAL
│ approved
INTEGRATING → AWAITING_INTEGRATION_APPROVAL
│ approved
COMPLETED
Any AWAITING_* → REJECTED (reject button)
Any AWAITING_* → re-runs same stage (revision button + feedback text)
Key Design Patterns (from agentic-patterns.com)
| Pattern | Where Applied |
|---|---|
| Plan-Then-Execute | PipelineMachine returns Action list; PipelineService executes |
| Discrete Phase Separation | Typed Pydantic contracts between every stage |
| Human-in-the-Loop Approval Framework | Approval buttons before each stage transition |
| Planner-Worker Separation | Machine plans, agents execute |
| Sub-Agent Spawning | PipelineService._get_agent() instantiates agents on demand |
| Verbose Reasoning Transparency | reasoning_trace field shown in every approval message |
| Specification-Driven Development | DesignerOutput is the contract ImplementerAgent must satisfy |
| Coding Agent CI Feedback Loop | TesterAgent reads GitHub Actions check statuses |
app/
├── main.py # FastAPI app + lifespan
├── config.py # All settings (pydantic-settings)
├── database.py # SQLite persistence (aiosqlite)
│
├── llm/ # LLM abstraction layer
│ ├── base.py # LLMProvider ABC
│ ├── factory.py # get_llm(), get_planning_llm()
│ ├── anthropic_provider.py
│ ├── prompt_builder.py # Centralised (system, user) prompt construction
│ └── prompts/ # System prompts per agent
│
├── models/
│ ├── pipeline.py # PipelineRun, PipelineStage enum
│ ├── contracts.py # Stage handoff Pydantic models
│ └── github.py # GitHub response models
│
├── pipeline/
│ ├── states.py # FSM transition matrix
│ ├── machine.py # PipelineMachine + Action dataclasses
│ └── agents/
│ ├── base.py # BaseAgent ABC
│ ├── openclaw_adapter.py # OpenClaw drop-in (agent_backend=openclaw)
│ ├── nanobot_adapter.py # Nanobot drop-in (agent_backend=nanobot)
│ └── planner/designer/implementer/tester/integrator.py
│
├── channels/ # Platform-agnostic channel abstraction
│ ├── base.py # ChannelProvider ABC + ChannelUpdate
│ ├── telegram.py # Bot API + inline keyboards
│ ├── whatsapp.py # Meta Cloud API + interactive buttons
│ └── slack.py # Slack Web API + Block Kit
│
├── voice/
│ ├── stt.py # OpenAI Whisper (transcription)
│ └── tts.py # OpenAI TTS + MP3→OGG conversion
│
├── integrations/
│ ├── github/
│ │ ├── client.py # GitHub REST API client (httpx)
│ │ └── operations.py # High-level ops: create_issue, open_pr, merge
│ ├── openclaw/
│ │ └── client.py # OpenClaw Gateway client wrapper
│ └── nanobot/
│ └── client.py # nanobot-ai provider wrapper
│
├── services/
│ ├── pipeline_service.py # Main orchestrator
│ ├── approval_service.py # Human-in-loop handler
│ └── voice_service.py # STT → pipeline → TTS
│
└── api/
├── webhooks.py # POST /webhooks/{telegram,whatsapp,slack}
├── admin.py # POST /pipelines (HTTP trigger, auth required)
├── pipeline_api.py # POST /api/pipelines (OpenClaw-facing routes, auth required)
└── health.py # GET /health
- Solo developer: Send voice notes describing features while commuting; approve PRs from your phone
- Small team: Automate boilerplate SDLC stages while humans focus on architecture decisions
- Rapid prototyping: Turn feature ideas into scaffolded code + tests + PRs in minutes
- Code review assistant: Each stage produces structured output reviewable via messaging apps
- Python 3.12+
- uv (
pip install uv) - ffmpeg (for voice note conversion):
brew install ffmpeg - A public HTTPS URL for webhooks (use ngrok for local dev)
cd /path/to/voiceable
uv synccp .env.example .envFill in .env:
# Required for SDLC agents
ANTHROPIC_API_KEY=sk-ant-...
# Required for voice (STT + TTS)
OPENAI_API_KEY=sk-...
# Required for GitHub operations
GITHUB_TOKEN=ghp_...
GITHUB_DEFAULT_OWNER=your-org
GITHUB_DEFAULT_REPO=your-repo
# Required for at least one messaging platform (see below)
TELEGRAM_BOT_TOKEN=...
# Your public URL (ngrok or production)
APP_BASE_URL=https://abc123.ngrok.io- Message @BotFather on Telegram →
/newbot - Copy the token →
TELEGRAM_BOT_TOKENin.env - Set
TELEGRAM_WEBHOOK_SECRETto any random string - Telegram webhook is auto-registered on startup
- Create a Meta Developer App with WhatsApp product
- Add
WHATSAPP_TOKEN,WHATSAPP_PHONE_NUMBER_ID,WHATSAPP_VERIFY_TOKEN - Register webhook URL:
https://your-url/webhooks/whatsapp - Subscribe to
messagesevents
- Create a Slack App with a bot token
- Enable Event Subscriptions:
message.channels→https://your-url/webhooks/slack - Enable Interactivity: request URL →
https://your-url/webhooks/slack - Add
SLACK_BOT_TOKENandSLACK_SIGNING_SECRET
Create a GitHub PAT with scopes:
repo(full control)workflow(for reading CI check statuses)
Skip this section if you are using in-process agents (VOICEABLE_AGENT_BACKEND=in_process, the default).
a. Install and run the OpenClaw Gateway
Follow the OpenClaw documentation to install and start the Gateway.
The Gateway should listen on ws://127.0.0.1:18789/gateway by default.
b. Define five agents in your Gateway config
Configure these agent IDs with their model assignments:
| Agent ID | Model | SDLC Stage |
|---|---|---|
planner |
anthropic/claude-opus-4-6 |
Planning |
designer |
anthropic/claude-opus-4-6 |
Design |
implementer |
anthropic/claude-sonnet-4-6 |
Implementation |
tester |
anthropic/claude-sonnet-4-6 |
Testing |
integrator |
anthropic/claude-haiku-4-5-20251001 |
Integration |
Agents can have minimal system text (e.g. "Return valid JSON") or none — the full prompt including the JSON schema constraint is sent by Voiceable each call.
c. Set env vars and enable
VOICEABLE_AGENT_BACKEND=openclaw
OPENCLAW_GATEWAY_WS_URL=ws://127.0.0.1:18789/gateway
VOICEABLE_API_KEY=your-secret-key # OpenClaw agents send this as X-Voiceable-Api-Keyd. Add openclaw-sdk to dependencies
Uncomment the openclaw-sdk line in pyproject.toml (pin the exact version you need),
then run uv sync.
Rollback: Set VOICEABLE_AGENT_BACKEND=in_process to revert to in-process agents instantly.
In-progress runs resume on the in-process path — no DB migration needed.
Skip this section if you are using in-process agents (VOICEABLE_AGENT_BACKEND=in_process).
a. Add nanobot-ai to dependencies
Uncomment the nanobot-ai line in pyproject.toml, then run uv sync.
b. Set env vars and enable
VOICEABLE_AGENT_BACKEND=nanobot
NANOBOT_PROVIDER=openrouter
NANOBOT_API_KEY=sk-or-...
NANOBOT_API_BASE= # optional; set for custom gateways
NANOBOT_MODEL=anthropic/claude-sonnet-4-6
NANOBOT_TIMEOUT=300NANOBOT_PROVIDER should be a valid nanobot provider key (for example:
openrouter, anthropic, openai, deepseek, gemini, or vllm).
# Development (with auto-reload)
uv run uvicorn app.main:app --reload --port 8000
# In another terminal, start ngrok
ngrok http 8000
# Copy the https URL → APP_BASE_URL in .env, restart servercurl -X POST http://localhost:8000/pipelines \
-H "Content-Type: application/json" \
-H "X-Voiceable-Api-Key: your-secret-key" \
-d '{
"goal": "Build a health check endpoint that returns uptime and version",
"platform": "telegram",
"chat_id": "YOUR_TELEGRAM_CHAT_ID",
"repo_owner": "your-org",
"repo_name": "your-repo"
}'# Start a run (returns immediately; pipeline runs in background)
curl -X POST http://localhost:8000/api/pipelines \
-H "X-Voiceable-Api-Key: your-secret-key" \
-H "Content-Type: application/json" \
-d '{"goal": "...", "platform": "telegram", "chat_id": "123"}'
# Poll run state
curl http://localhost:8000/api/pipelines/{run_id} \
-H "X-Voiceable-Api-Key: your-secret-key"
# Approve current stage
curl -X POST http://localhost:8000/api/pipelines/{run_id}/approve \
-H "X-Voiceable-Api-Key: your-secret-key"
# Submit revision
curl -X POST http://localhost:8000/api/pipelines/{run_id}/revision \
-H "X-Voiceable-Api-Key: your-secret-key" \
-H "Content-Type: application/json" \
-d '{"revision_notes": "Add error handling for edge cases"}'curl http://localhost:8000/healthSending a voice message:
- Open Telegram/WhatsApp/Slack
- Record a voice note describing the feature
- Send it to the bot
- The bot transcribes it and confirms: "Transcribed: Build a health check endpoint"
- The pipeline starts automatically
- Each approval message is also sent as a voice note summary
Text also works — send any text message as a feature request.
uv run python -m pytest tests/ -v19 tests covering FSM states, agent logic, Telegram parsing, and STT.
| Variable | Required | Description |
|---|---|---|
ANTHROPIC_API_KEY |
Yes | Claude API key (in-process agents) |
OPENAI_API_KEY |
Yes | Whisper STT + TTS |
GITHUB_TOKEN |
Yes | PAT with repo+workflow |
GITHUB_DEFAULT_OWNER |
Yes | Default GitHub org/user |
GITHUB_DEFAULT_REPO |
Yes | Default GitHub repo |
APP_BASE_URL |
Yes | Public HTTPS URL for webhooks |
VOICEABLE_API_KEY |
Recommended | Auth key for /pipelines and /api/pipelines routes |
TELEGRAM_BOT_TOKEN |
For Telegram | From @BotFather |
TELEGRAM_WEBHOOK_SECRET |
For Telegram | Random secret string |
WHATSAPP_TOKEN |
For WhatsApp | Meta access token |
WHATSAPP_PHONE_NUMBER_ID |
For WhatsApp | Meta phone number ID |
WHATSAPP_VERIFY_TOKEN |
For WhatsApp | Webhook verify token |
SLACK_BOT_TOKEN |
For Slack | xoxb-... bot token |
SLACK_SIGNING_SECRET |
For Slack | App signing secret |
TTS_VOICE |
No | Voice for TTS (default: nova) |
PLANNING_MODEL |
No | Override planner model |
IMPLEMENTATION_MODEL |
No | Override implementer model |
VOICEABLE_AGENT_BACKEND |
No | in_process (default), openclaw, or nanobot |
OPENCLAW_GATEWAY_WS_URL |
For OpenClaw | Gateway WebSocket URL |
OPENCLAW_API_KEY |
For OpenClaw | Optional Gateway auth token |
OPENCLAW_TIMEOUT |
No | Seconds per agent call (default: 300) |
NANOBOT_PROVIDER |
For Nanobot | Provider key (e.g. openrouter, anthropic) |
NANOBOT_API_KEY |
For Nanobot | API key used by selected Nanobot provider |
NANOBOT_API_BASE |
No | Optional provider base URL override |
NANOBOT_MODEL |
No | Optional model override for all stages |
NANOBOT_TIMEOUT |
No | Seconds per Nanobot call (default: 300) |
| Component | Technology |
|---|---|
| Web framework | FastAPI + uvicorn |
| LLM (in-process) | Anthropic Claude (opus-4-6, sonnet-4-6, haiku-4-5) |
| LLM (OpenClaw) | openclaw-sdk → OpenClaw Gateway → any model |
| LLM (Nanobot) | nanobot-ai LiteLLMProvider → OpenRouter/Anthropic/OpenAI/etc |
| STT | OpenAI Whisper (whisper-1) |
| TTS | OpenAI TTS (tts-1) |
| Audio conversion | ffmpeg via subprocess |
| Database | SQLite via aiosqlite |
| HTTP client | httpx (async) |
| Config | pydantic-settings |
| GitHub | REST API v3 (httpx) |
| Messaging | Telegram Bot API, Meta Cloud API, Slack Web API |
| Tests | pytest + pytest-asyncio |