Three-release UX polish pass on Real-life mode after the TAB-626 isolation redesign. Voice commands stop trying to drive RL turns (TAB-615), hook dedup eliminates duplicate Telegram cards from concurrent stop-hooks (TAB-644 hook-dedup), Connector reads auto-allow on first call (TAB-644 connector-allow), prompt formatting cleaned up so RL responses look like Telegram messages, and the answer-placement order is finally below the approval cards.
What landed
TAB-615 — Voice command suppression in Real-life mode. Voice transcription routes to a Code-mode planner that doesn't understand RL semantics. Until this fix, sending voice in RL mode would queue a phantom Code-mode plan that never fired. Now: voice in RL is detected at the Telegram input layer and routed to the RL workflow directly.
TAB-644 hook-dedup. Two simultaneous stop-hooks (parallel claudes both finishing within ms of each other) fired two Telegram approval cards for the same logical action. Fix: dedup window per (session, classification, target) for 3s.
TAB-644 Connector auto-allow. Read-only Connector tools (mcp__claude_ai_* Gmail-list-emails, Calendar-list-events, etc.) were asking for approval on every call. They're read-only and idempotent — no reason to gate them per call. Now auto-allow with toast notification.
TAB-644 format prompt. RL system prompt updated to emit clean Telegram-formatted responses (correct line breaks, emoji-friendly, no Code-mode markdown that Telegram parses badly).
TAB-644 answer placement. Response card now appears AFTER the approval cards in the Telegram thread, not before. Reading order is "approval cards → answer", matching the visual flow of how the conversation unfolded.
TAB-644 allow-toast gate. The "Auto-approved: X" toast now respects per-user mute preferences. Spam-prone for users with high tool-call rates.
Why these matter
After the TAB-626 isolation redesign (v2.3.136–v2.3.138), the RL workflow was structurally sound but the user-facing surface still had rough edges. This release range is the polish pass — small individual changes, big cumulative quality bump for the Telegram experience.
How you'll notice
Voice in RL: works the way you'd expect (your voice command becomes the RL turn, not a phantom Code plan).
Reading the thread: less visual noise, fewer duplicate cards, response below the approvals.
Connector tools: fewer interrupting approval prompts for the read-only ones; the write-side (send-email, create-event) still asks every time.
Tests
Hook dedup gets a multi-PID concurrency regression test. Connector auto-allow gets a per-tool-name read-classifier test. Format-prompt and answer-placement get rendered-output snapshot tests.
A unified hook-adapter now handles all approval protocol branches in the bridge server, replacing 18 hand-coded protocol paths with a single dispatch layer.
Improvements (TAB-568)
Hook-adapter wired into approval-bridge-server — The 18 separate protocol branches that handled different hook event types (tool calls, file writes, command execution, etc.) have been replaced by a single HookAdapter dispatch layer. Each hook type registers a handler, and the adapter routes incoming events automatically. This reduces the bridge server's approval logic from ~400 lines to ~80 lines.
A new CallbackRegistry.dispatch() system replaces the 37-case switch statement in the callback handler, making callback routing declarative and extensible.
Improvements (TAB-567)
CallbackRegistry.dispatch() wired in — The monolithic 37-case switch that routed Telegram callback queries has been replaced with a declarative CallbackRegistry. Each feature module registers its own callback patterns, and dispatch() routes incoming callbacks by prefix match. Adding a new callback type is now a one-line registration instead of editing a giant switch block.
improvement
CodePulse v2.3.69 — MessageRouter Decomposed into 5 Modules
The monolithic MessageRouter has been split into 5 focused feature modules, improving maintainability and making the approval pipeline easier to extend.
Improvements (TAB-566, Phase 2)
MessageRouter decomposed into 5 feature modules — The single 1,200-line MessageRouter class was split into CommandRouter, ApprovalRouter, CallbackRouter, NotificationRouter, and DelegateRouter. Each module owns one concern, making the codebase easier to navigate and reducing merge conflicts when multiple features touch the message pipeline.
Phase 0+1 of the MessageRouter decomposition introduces four reusable primitives: TTL-aware state container, typed callback dispatcher, session isolation helper, and normalized hook adapter.
Improvements (TAB-566, Phases 0+1)
TTL-aware generic state container — Replaces hand-rolled expiry maps scattered across ApprovalBridgeServer and PersistentCliBridge. Single implementation, single eviction schedule, fewer places where stale state can hide.
Typed callback dispatcher — Removes the copy-pasted callback handler scaffolding repeated across event types.
Session isolation helper — Standardizes the per-session scoping logic, so a future router module can't accidentally reach into another session's state.
Normalized hook protocol adapter — One abstraction layer between Claude Code hooks and the internal pipeline; downstream modules consume a stable shape instead of duplicating hook-format parsing.
These are the foundations for Phase 2 (MessageRouter split into 5 feature modules, shipped in v2.3.69).
Set MCP_CONNECTION_NONBLOCKING=1 in the CLI environment. MCP servers now connect in the background, saving 3-8 seconds on every delegate task start.
Improvements (TAB-550)
CLI spawn no longer waits for MCP server handshake — Claude Code v2.1.89 introduced MCP_CONNECTION_NONBLOCKING=1 to skip the synchronous MCP connection wait in headless mode. Without it, every CLI spawn blocked for the MCP handshake before the first message could be sent. Added MCP_CONNECTION_NONBLOCKING: '1' to the env builder in both cli-bridge.ts and persistent-cli-bridge.ts. MCP servers now connect in the background and are ready by the time the first tool call arrives. Task start time drops by 3 to 8 seconds, depending on how many MCP servers are configured.
MCP-action phrases in companion mode now auto-escalate to CLI execution. Seven Claude-native MCPs whitelisted by default. Reply button now appears on all text responses.
Improvements (TAB-546)
MCP-action phrases auto-escalate to CLI execution — Asking Claude to "check this in Linear" or "query Supabase" in companion mode used to return a dead-end simple_question classification with no tool access. A contextual regex now detects MCP-action phrases in simple_question intents — designed to avoid false positives like "linear algebra" or "what is supabase" — and routes them appropriately. In companion mode the router advises switching to delegate mode; in delegate or autonomous mode it escalates to handlePlanTask for full CLI execution.
Seven Claude-native MCPs whitelisted by default — Linear, GitHub, Cloudflare, Stripe, Supabase, Resend, and Netlify are now added to --allowedTools unconditionally. The whitelist entries are harmless if the corresponding MCP server is not connected.
Reply button now appears on every text response — The Reply button was previously only shown on question responses, which was an unintended side-effect of earlier UX tightening. Every text response is now consistently interactive.
improvement
CodePulse v2.3.56 — Setup Wizard Simplified
Setup wizard collapsed from 4 steps to 3 by removing the API key fields. Both keys remain accessible in the Configuration panel with descriptive hints.
Improvements
Setup wizard no longer asks for API keys — The first-run wizard asked new users for OpenAI and Anthropic API keys during initial setup, creating unnecessary friction. Premium users using the proxy do not need these keys. Free users do not need them for the core Telegram and Claude Code flow. Steps Welcome → Telegram → API Keys → Summary are condensed to Welcome → Telegram → Summary. The API key fields remain editable in the Configuration panel at any time, with contextual hints explaining that the OpenAI key is only for direct voice transcription fallback.
improvement
CodePulse v2.3.53 — Plan Cards Show the Real Git Branch
Plan cards now display the actual git branch detected at plan time instead of a Haiku-generated fake. Dead voice config entries also removed.
Improvements (TAB-538)
Plan cards no longer show a fake Haiku-generated branch — Since v2.3.49 stopped creating feature branches, the plan.branch field synthesized by Haiku was never backed by a real branch. Users saw invented names like chore/extract-latest-blog-article on the plan card while actually sitting on dev. Now gitManager.getStatus(activeDir) detects the real branch at plan time and the card displays it directly. The plan.branch field was replaced with a commitType field in the plan schema, removing vestigial branch generation from Haiku entirely.
Removed dead VOICE_ENABLED and VOICE_PROVIDER config — These two environment variables were never read after the voice engine rewrite. Cleaned up .env.example, config.ts, voice-engine.ts, and fixed a broken JSDoc comment in the process.
improvement
CodePulse v2.3.52 — Upgraded Transcription Model
Upgraded the voice transcription model from whisper-1 to gpt-4o-mini-transcribe on both the service and Cloudflare Worker proxy for higher accuracy at similar cost.
Improvements
Voice transcription upgraded to gpt-4o-mini-transcribe — Replaced the older whisper-1 model with OpenAI's newer gpt-4o-mini-transcribe on both the local service path and the Cloudflare Worker proxy. The new model provides noticeably higher accuracy on technical vocabulary, proper nouns, and code identifiers at similar per-minute cost. Both transcription entry points were updated to avoid model drift between the proxy and fallback paths.