Make your AI coding assistant actually finish the job. Self-reflection and task verification for OpenCode - the open-source AI coding agent.
AI coding assistants often:
- Stop before the task is truly complete
- Miss edge cases or skip steps
- Say "done" when tests are failing
- Require constant human supervision
This plugin adds a judge layer that automatically evaluates task completion and forces the agent to continue until the work is actually done. Plus, get notified on Telegram when long-running tasks finish - and reply back via text or voice.
| Plugin | Description |
|---|---|
| reflection.ts | Judge layer that verifies task completion and forces agent to continue if incomplete |
| tts.ts | Text-to-speech + Telegram notifications with two-way communication |
| worktree-status.ts | Git worktree status tool for checking dirty state, branch, and active sessions |
- Automatic task verification - Judge evaluates completion after each agent response
- Self-healing workflow - Agent receives feedback and continues if work is incomplete
- Telegram notifications - Get notified when tasks finish, reply via text or voice
- Local TTS - Hear responses read aloud (Coqui XTTS, Chatterbox, macOS)
- Voice-to-text - Reply to Telegram with voice messages, transcribed by local Whisper
# Install plugins
mkdir -p ~/.config/opencode/plugin && \
curl -fsSL -o ~/.config/opencode/plugin/reflection.ts \
https://raw.githubusercontent.com/dzianisv/opencode-plugins/main/reflection.ts && \
curl -fsSL -o ~/.config/opencode/plugin/tts.ts \
https://raw.githubusercontent.com/dzianisv/opencode-plugins/main/tts.ts && \
curl -fsSL -o ~/.config/opencode/plugin/telegram.ts \
https://raw.githubusercontent.com/dzianisv/opencode-plugins/main/telegram.ts && \
curl -fsSL -o ~/.config/opencode/plugin/worktree-status.ts \
https://raw.githubusercontent.com/dzianisv/opencode-plugins/main/worktree-status.ts
# Install required dependencies
cat > ~/.config/opencode/package.json << 'EOF'
{
"dependencies": {
"@opencode-ai/plugin": "1.1.36",
"@supabase/supabase-js": "^2.49.0"
}
}
EOF
cd ~/.config/opencode && bun installThen restart OpenCode.
┌─────────────────────────────────────────────────────────────────────────────┐
│ OpenCode Plugins │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────────┐ ┌──────────────────┐ ┌──────────────────────┐ │
│ │ reflection.ts │ │ tts.ts │ │ worktree-status.ts │ │
│ │ │ │ │ │ │ │
│ │ • Judge layer │ │ • Local TTS │ │ • Git dirty check │ │
│ │ • Task verify │ │ • Whisper STT │ │ • Branch status │ │
│ │ • Auto-continue │ │ • Telegram notif │ │ • Active sessions │ │
│ └──────────────────┘ └────────┬─────────┘ └──────────────────────┘ │
│ │ │
│ ┌──────────────┼──────────────┐ │
│ ▼ ▼ ▼ │
│ ┌──────────────┐ ┌────────────┐ ┌──────────────────────┐ │
│ │ TTS Engines │ │telegram.ts │ │ Supabase Backend │ │
│ │ │ │ (helper) │ │ │ │
│ │ • Coqui XTTS │ │ │ │ • Edge Functions │ │
│ │ • Chatterbox │ │ • Notifier │ │ • PostgreSQL + RLS │ │
│ │ • macOS say │ │ • Supabase │ │ • Realtime subscr. │ │
│ └──────────────┘ └────────────┘ └──────────────────────┘ │
└─────────────────────────────────────────────────────────────────────────────┘
Note: telegram.ts is a helper module (not a standalone plugin) that provides Telegram notification functions used by tts.ts.
Evaluates task completion after each agent response and provides feedback if work is incomplete.
- Trigger:
session.idleevent fires when agent finishes responding - Context Collection: Extracts task, AGENTS.md, tool calls, agent output
- Judge Session: Creates separate hidden session via OpenCode Sessions API for unbiased evaluation
- Verdict: PASS → toast notification | FAIL → feedback injected into chat
- Continuation: Agent receives feedback and continues working
- OpenCode Sessions API: Uses OpenCode's session management to create isolated judge sessions
- Project-aware evaluation: Reads
AGENTS.mdand skills to understand project-specific policies, testing requirements, and deployment rules - Rich context: Task description, last 10 tool calls, agent response, and project guidelines
- Automatic trigger on session idle
- Non-blocking async evaluation with polling (supports slow models like Opus 4.5)
- Max 16 attempts per task to prevent loops
- Infinite loop prevention (skips judge sessions)
- Auto-reset counter when user provides new feedback
Constants in reflection.ts:
const MAX_ATTEMPTS = 16 // Max reflection attempts per task (auto-resets on new user feedback)
const JUDGE_RESPONSE_TIMEOUT = 180_000 // 3 min timeout for judge
const POLL_INTERVAL = 2_000 // Poll every 2s
const STUCK_CHECK_DELAY = 30_000 // Check if agent stuck 30s after reflection feedback
const STUCK_NUDGE_DELAY = 15_000 // Nudge agent 15s after compressionThe judge session receives:
- User's original task - What was requested
- AGENTS.md content (first 1500 chars) - Project-specific policies, testing requirements, deployment checklist, and development workflows
- Last 10 tool calls - What actions the agent took
- Agent's final response (first 2000 chars) - What the agent reported
This allows the judge to verify compliance with project-specific rules defined in AGENTS.md and related skills, such as:
- Required testing procedures
- Build/deployment steps
- Code quality standards
- Security policies
- Documentation requirements
Text-to-speech with Telegram integration for remote notifications and two-way communication.
| Engine | Quality | Speed | Setup |
|---|---|---|---|
| Coqui XTTS v2 | Excellent | 2-5s | Auto-installed, Python 3.9+ |
| Chatterbox | Excellent | 2-5s | Auto-installed, Python 3.11 |
| macOS say | Good | Instant | None |
~/.config/opencode/tts.json:
{
"enabled": true,
"engine": "coqui",
"coqui": {
"model": "xtts_v2",
"device": "mps",
"serverMode": true
},
"telegram": {
"enabled": true,
"uuid": "<your-uuid>",
"sendText": true,
"sendVoice": true,
"receiveReplies": true
}
}/tts Toggle on/off
/tts on Enable
/tts off Disable
Two-way communication: receive notifications when tasks complete, reply via text or voice.
┌─────────────────────────────────────────────────────────────────────────────┐
│ OUTBOUND (Task Complete) │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ OpenCode ──► TTS Plugin ──► Supabase Edge ──► Telegram API ──► User │
│ │ │ (send-notify) │
│ │ │ │
│ │ ┌────┴────┐ │
│ │ │ Convert │ WAV → OGG (ffmpeg) │
│ │ │ audio │ │
│ │ └─────────┘ │
│ │ │
│ Stores reply context (session_id, uuid) in telegram_reply_contexts table │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────────┐
│ INBOUND (User Reply) │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ TEXT REPLY: │
│ User ──► Telegram ──► Webhook ──► telegram_replies table │
│ (Edge Fn) │ │
│ │ Supabase Realtime │
│ ▼ │
│ TTS Plugin ──► OpenCode Session │
│ (promptAsync) │
│ │
│ VOICE REPLY: │
│ User ──► Telegram ──► Webhook ──► Download audio ──► telegram_replies │
│ (voice) (Edge Fn) (base64) │ │
│ │ Realtime │
│ ▼ │
│ TTS Plugin ──► Whisper STT ──► OpenCode │
│ (local) (transcribe) │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
-
Generate UUID:
uuidgen | tr '[:upper:]' '[:lower:]'
-
Subscribe via Telegram:
- Open @OpenCodeMgrBot
- Send:
/start <your-uuid>
-
Configure plugin (
~/.config/opencode/tts.json):{ "telegram": { "enabled": true, "uuid": "<your-uuid>", "receiveReplies": true } } -
Install ffmpeg (for voice messages):
brew install ffmpeg
| Command | Description |
|---|---|
/start <uuid> |
Subscribe with your UUID |
/stop |
Unsubscribe |
/status |
Check subscription |
All backend code is in supabase/ - self-hostable.
-- Maps UUID → Telegram chat_id
telegram_subscribers (
uuid UUID PRIMARY KEY,
chat_id BIGINT NOT NULL,
is_active BOOLEAN DEFAULT TRUE,
notifications_sent INTEGER DEFAULT 0
)
-- Stores reply context for two-way communication
telegram_reply_contexts (
id UUID PRIMARY KEY,
chat_id BIGINT NOT NULL,
uuid UUID REFERENCES telegram_subscribers(uuid),
session_id TEXT NOT NULL,
expires_at TIMESTAMPTZ DEFAULT (NOW() + INTERVAL '24 hours'),
is_active BOOLEAN DEFAULT TRUE
)
-- Incoming replies (text and voice)
telegram_replies (
id UUID PRIMARY KEY,
uuid UUID REFERENCES telegram_subscribers(uuid),
session_id TEXT NOT NULL,
reply_text TEXT, -- NULL for voice before transcription
is_voice BOOLEAN DEFAULT FALSE,
audio_base64 TEXT, -- Base64 audio for voice messages
voice_file_type TEXT, -- 'voice', 'video_note', 'video'
voice_duration_seconds INTEGER,
processed BOOLEAN DEFAULT FALSE
)| Function | Purpose | Auth |
|---|---|---|
telegram-webhook |
Handles Telegram updates, stores replies | No JWT (Telegram calls it) |
send-notify |
Receives notifications from plugin | JWT optional |
-- Service role: full access (Edge Functions)
-- Anon role: SELECT for realtime, UPDATE via RPC
-- Secure function for marking replies processed
CREATE FUNCTION mark_reply_processed(p_reply_id UUID)
RETURNS BOOLEAN
SECURITY DEFINER -- Bypasses RLSPlugin subscribes to telegram_replies table changes:
supabase.channel('telegram_replies')
.on('postgres_changes', {
event: 'INSERT',
schema: 'public',
table: 'telegram_replies',
filter: `uuid=eq.${uuid}`
}, handler)# 1. Link to your Supabase project
supabase link --project-ref <your-project>
# 2. Push migrations
supabase db push
# 3. Deploy functions
supabase functions deploy telegram-webhook --no-verify-jwt
supabase functions deploy send-notify
# 4. Set secrets
supabase secrets set TELEGRAM_BOT_TOKEN=<token>
# 5. Configure webhook
curl "https://api.telegram.org/bot<TOKEN>/setWebhook?url=https://<project>.supabase.co/functions/v1/telegram-webhook"
# 6. Update tts.json with your serviceUrlLocal speech-to-text for voice message transcription.
- Telegram voice message received by webhook
- Audio downloaded and stored as base64 in
telegram_replies - Plugin receives via Supabase Realtime
- Local Whisper server transcribes audio
- Transcribed text forwarded to OpenCode session
Auto-started on first voice message:
- Location:
~/.config/opencode/opencode-helpers/whisper/ - Port: 8787 (configurable)
- Model:
baseby default (configurable)
{
"whisper": {
"enabled": true,
"model": "base",
"device": "auto",
"port": 8787
}
}~/.config/opencode/
├── package.json # Plugin dependencies (bun install)
├── opencode.json # OpenCode config
├── tts.json # TTS + Telegram config
├── plugin/
│ ├── reflection.ts # Reflection plugin (judge layer)
│ ├── tts.ts # TTS plugin (speech + Telegram)
│ ├── telegram.ts # Telegram helper module (used by tts.ts)
│ └── worktree-status.ts # Git worktree status tool
├── node_modules/ # Dependencies (@supabase/supabase-js)
└── opencode-helpers/
├── coqui/ # Coqui TTS server
│ ├── venv/
│ ├── tts.sock
│ └── server.pid
├── chatterbox/ # Chatterbox TTS server
│ ├── venv/
│ ├── tts.sock
│ └── server.pid
└── whisper/ # Whisper STT server
├── venv/
├── whisper_server.py
└── server.pid
# Clone
git clone https://github.com/dzianisv/opencode-plugins
cd opencode-plugins
# Install dependencies
npm install
# Type check
npm run typecheck
# Run tests
npm test
# Deploy to local OpenCode
npm run install:global# Unit tests
npm test
# E2E tests (requires OpenCode server)
OPENCODE_E2E=1 npm run test:e2e
# Manual TTS test
npm run test:tts:manual- OpenCode v1.0+
- TTS: macOS (for
say), Python 3.9+ (Coqui), Python 3.11 (Chatterbox) - Telegram voice: ffmpeg (
brew install ffmpeg) - Dependencies:
bun(OpenCode installs deps from package.json)
| Without Reflection Plugin | With Reflection Plugin |
|---|---|
| Agent says "done" but tests fail | Agent runs tests, sees failures, fixes them |
| You manually check every response | Automatic verification after each response |
| Context switching interrupts your flow | Get notified on Telegram, reply hands-free |
| Agent stops at first attempt | Up to 3 self-correction attempts |
| Hope it worked | Know it worked |
- OpenCode - Open-source AI coding agent (required)
- Claude Code - Anthropic's AI coding assistant
- Cursor - AI-powered code editor
opencode ai-coding-assistant llm-agent task-verification self-reflection autonomous-coding telegram-bot text-to-speech whisper developer-tools productivity ai-automation
Contributions welcome! Please read the AGENTS.md for development guidelines.
MIT
Built for developers who want their AI to finish the job.