Anthropic cut off subscription access for OpenClaw on April 4, 2026. Within two weeks, the community shipped at least seven Telegram-Claude Code bridges. That's impressive. But a bridge is not an orchestrator.
A bridge lets you talk to Claude Code from your phone. An orchestrator lets you send "write a blog about context rotation" from your phone and have six agents — research, SEO, writer, editor, image generator, publisher — execute a pipeline with quality gates, feedback loops, and session persistence. Without blocking your main session.
I've been running both. The bridge part (Claude Code Channels on a GCP VM) has been live since March. The orchestration layer — a Python worker daemon with directory-based agent isolation — has been in testing for about a week. The underlying patterns come from VNX Orchestration, which has been in production for nine months.
This post is the full architecture. What works, what breaks, what I'd do differently. If you've built something similar or want to, I'd genuinely like to hear about it.
What OpenClaw actually solved
Before we bury it, let's be fair about what OpenClaw did well:
- Multi-channel messaging: WhatsApp, Telegram, Discord, Signal, iMessage, Slack, MS Teams — one config, all platforms
- Conversation memory: context persistence across sessions, personalization
- Skill marketplace: community-built extensions
- Multi-model routing: Claude, GPT, local models through one interface
- Zero-config setup:
npm install -g openclaw && openclaw setupand you're running
That's a real product. The problem wasn't the features — it was the architecture. OpenClaw captured OAuth tokens from your Claude subscription and proxied requests through its backend. When Anthropic changed the billing model, heavy users were running $1,000-$5,000/day on $200 Max plans. Anthropic stopped eating the difference.
The result: OpenClaw still works, but now on pay-as-you-go billing — up to 50x more expensive for heavy users.
The community response: seven bridges and counting
The community moved fast. Here's what exists today:
| Project | Builder | What it does | Key differentiator |
|---|---|---|---|
| ccgram | alexei-led | tmux bridge for Claude, Codex, Gemini CLI | Multi-agent, parallel sessions, pip/brew install |
| CCBot | six-ddc | Telegram-tmux bridge | 1 topic = 1 window. Built itself using itself |
| OpenACP | Open-ACP org | Agent Client Protocol bridge | Telegram/Discord/Slack, open standard (note: ACP may route through API, not subscription — verify billing before use) |
| claudecode-telegram | Han Xiao | Python bridge + Cloudflare Tunnel | Stop hooks, async operation |
| claude-code-telegram | RichardAtCT | Full Telegram bot | Session persistence, remote access |
| oh-my-claudecode | sigridjineth | Multi-agent framework | Dozens of specialized agents, monitoring HUD |
| Claude Code Channels | Anthropic | Official Telegram/Discord plugin | Native, no wrapper, subscription-covered |
VentureBeat called Channels "the OpenClaw killer." That's half right. Channels gives you a messaging interface to Claude Code — but so do all seven projects above.
What none of them give you is orchestration.
Where bridges stop and orchestration starts
A bridge solves I/O: you type in Telegram, Claude Code responds. That's valuable — I use Channels as my primary interface daily.
But when I say "write a blog about context rotation," I don't want a single Claude session to do everything sequentially. I want:
- A research agent with Perplexity MCP access to find sources
- An SEO agent with keyword matrices to optimize structure
- A blog-writer agent with my tone of voice rules and Strapi format
- An editor agent that runs an 8-point quality audit
- An image agent with Excalidraw MCP to create diagrams
- A publisher agent that commits and pushes to the website repo
Each with focused context. Each isolated. With async quality gates between steps where I approve or request changes — from my phone, while walking the dog.
That's not a bridge problem. That's an orchestration problem.
The architecture
Vincent (Telegram — voice, text, photo)
|
v
@VNXwriter_bot (Claude Channels — Opus 4.6, 1M context)
|
|-- SHORT task? --> Execute directly in session
| (comments, ideas, quick questions)
|
|-- LONG task? --> INSERT into Supabase system.tasks
| Reply: "Queued. You can keep talking."
|
v
Supabase system.tasks (shared state)
|
v
Worker Daemon (systemd, 24/7)
|
|-- Max 2 concurrent workers
|
|-- For each task:
| cd agents/{type} && claude -p "{prompt}" \
| --output-format stream-json --verbose
| (Popen + read_events_with_timeout() for live streaming)
|
|-- Pipeline tasks run multi-step:
| Step 1: agents/research/ --> research-brief.md
| Step 2: agents/seo/ --> seo-brief.md
| Step 3: agents/blog-writer/ --> index.md
| [QUALITY GATE: notify via Telegram, wait for "ok"]
| Step 4: agents/editor/ --> editor-report.md
| Step 5: agents/images/ --> cover.png
| [QUALITY GATE: notify via Telegram]
| Step 6: agents/publisher/ --> git push
|
v
Vincent replies "ok" / "edit: more examples" / "no"
|
v
n8n Router catches reply --> updates task --> daemon resumesFour components, each with one job:
- Channels (@VNXwriter_bot) = the brain. Classifies incoming messages, handles short tasks conversationally, routes long tasks to the queue
- Worker daemon = the muscles. Spawns
claude -pworkers viasubprocess.Popen(), streams events in real time, monitors completion, sends Telegram notifications. Currently polls Supabase every 10s — Supabase Realtime subscriptions for zero-latency pickup is on the roadmap - n8n (@VNXagent_bot) = the senses. Webhooks, crons, monitoring, feedback routing from Telegram replies back to the queue
- Supabase = the nervous system. Shared state between all components. Task queue, session IDs, pipeline progress, message-to-task mapping
The key insight: an agent is a directory
This is design decision D3 from the Agent OS architecture: an agent is a directory with a CLAUDE.md file.
assistant/agents/
├── research/
│ ├── CLAUDE.md # Research methodology, source validation rules
│ └── .mcp.json # Perplexity MCP, Brave Search
│
├── seo/
│ ├── CLAUDE.md # Keyword research, SERP analysis
│ └── references/ # Keyword matrix, content gaps
│
├── blog-writer/
│ ├── CLAUDE.md # Strapi format, SEO structure, tone of voice
│ └── references/
│ ├── product-marketing-context.md -> (symlink)
│ └── tone-of-voice.md -> (symlink)
│
├── editor/
│ ├── CLAUDE.md # 8-point quality audit checklist
│ └── references/
│
├── images/
│ ├── CLAUDE.md # Cover images, diagram creation
│ └── .mcp.json # Excalidraw MCP
│
├── publisher/
│ ├── CLAUDE.md # Git branch, commit, push
│ └── references/
│
├── linkedin/
│ └── CLAUDE.md # LinkedIn post format, hook patterns
│
└── discussion/
└── CLAUDE.md # Comment writing (HN, LinkedIn, Reddit)When the daemon spawns a worker, it runs:
cd agents/blog-writer && claude -p "Write a blog about context rotation. \
Research brief: {output from previous step}" \
--output-format stream-json --verboseThe stream-json --verbose flag is important — without --verbose, Claude Code CLI 2.1.92+ produces zero streaming events. The daemon uses subprocess.Popen() with read_events_with_timeout() to consume events as they arrive, writing them to an NDJSON EventStore. This gives you live progress streaming to a dashboard while the agent works — not just "in progress" and "done."
Claude Code automatically loads CLAUDE.md from the working directory. The blog-writer agent gets tone of voice rules, Strapi format requirements, and SEO structure guidelines — without loading the 42 other skills that the Channels session carries.
This is the same pattern that CrewAI uses (role + backstory), AutoGen (system_message), and LangGraph (node-level prompts) — but without any framework. Just directories and the Claude CLI. The philosophical foundation is Glass Box Governance: every agent has a bounded role, and no entity does more than one job.
Why this matters:
- Each agent has focused context (not 42 skills competing for attention)
- MCP servers are per-agent (research gets Perplexity, images gets Excalidraw)
- Testing is trivial:
cd agents/research && claude -p "test query" - Adding a new agent = creating a new directory with a CLAUDE.md
- No framework lock-in. No dependencies. Just the filesystem
📖 Read also: Decision-Making Architecture: Why Autonomous Agents Need Governance — Why separating decision authority from execution prevents cascading failures.
Pipeline definitions
Each task type maps to a pipeline — a sequence of agent steps with optional quality gates:
PIPELINES = {
"blog": [
{"agent": "research", "prompt": "Research {topic}", "gate": False},
{"agent": "seo", "prompt": "SEO analysis for {topic}", "gate": False},
{"agent": "blog-writer", "prompt": "Write blog. Brief: {prev}", "gate": True},
{"agent": "editor", "prompt": "Review: {prev}", "gate": False},
{"agent": "images", "prompt": "Create images for: {prev}", "gate": False},
{"agent": "publisher", "prompt": "Publish: {prev}", "gate": True},
],
"linkedin": [
{"agent": "research", "prompt": "Research {topic}", "gate": False},
{"agent": "linkedin", "prompt": "Write post. Brief: {prev}", "gate": True},
],
}At each quality gate, the daemon pauses, sends a Telegram notification with a summary, and waits. I reply "ok" to approve, "edit: more concrete examples" to revise, or "no" to reject.
The feedback loop uses --resume:
claude -p --resume <session_id> "Add more concrete examples to section 3"The agent picks up with full context from the previous session. No re-reading the entire blog. No lost state.
What honestly breaks
I've been running this for about a week in its current form. The Channels bridge has been stable since March. The worker daemon orchestration layer is newer and has known issues. Here's the honest list.
1. Crash recovery (being built)
If the daemon crashes while a worker is mid-task, that task stays in_progress forever. The fix — read_events_with_timeout() with lease heartbeat renewal, plus a health monitor that detects orphaned workers and auto-restarts with a retry budget — is actively being built as F31 "Headless Worker Resilience." The timeout protection and heartbeat components are already tested. The full health monitor is in progress.
2. Threading model is fragile
The daemon uses a global active_workers counter with a threading lock. If a worker thread gets OOM-killed before reaching the finally block, the counter never decrements. The daemon thinks all worker slots are full and stops dispatching. A process-based model where dead workers are detectable via PID would be more robust.
3. No gate timeout
If I don't respond to a quality gate notification (sleeping, phone off, vacation), the pipeline hangs indefinitely. The fix is obvious — auto-reminder after 2 hours, escalation after 8, optional auto-approve for low-risk steps after 24 — but it's not built yet.
4. --dangerously-skip-permissions is too broad
The current daemon gives every agent full shell/file/network access. On a 24/7 VM, this is a security concern. Each agent should have scoped permissions via allowedTools in their CLAUDE.md — the research agent gets Read + WebSearch, the publisher gets only Bash for git commands. Not implemented yet.
5. JSON parsing (fixed)
claude -p can write non-JSON to stdout on auth failures or rate limits. The naive json.loads(result.stdout) crashes. This is already solved in the SubprocessAdapter: read_events() wraps JSON parsing in try/except with warning logging — malformed lines are skipped, not crashed on. Proven in burn-in: 279 events parsed, 0 crashes.
6. Rate limits on Max subscription
Spawning too many concurrent workers hits rate limits. I've seen 5-hour cooldown windows during intensive use. The mitigation: max 2 concurrent workers and scheduling heavy pipelines during off-peak hours.
7. Two-bot confusion
@VNXagent_bot (n8n automations) and @VNXwriter_bot (Channels) both send Telegram messages. Replying to the wrong bot's message means feedback doesn't route correctly. A single-bot architecture with routing logic would be cleaner.
8. Real-time progress (built, wiring in progress)
The full streaming pipeline is built and validated: read_events() writes events to an NDJSON EventStore, an SSE endpoint streams them live, and a dashboard page renders events in real-time with color-coded types (thinking, tool_use, text, result). Burn-in: 12/12 scenarios passed, 279 events streamed and archived. The daemon just needs to use SubprocessAdapter.deliver() instead of raw subprocess.run() — about 20 lines of code difference — and live progress comes for free. That wiring is in progress.
What's proven vs. what's new
Let me be precise about maturity levels:
| Component | Maturity | Evidence |
|---|---|---|
| CLI subprocess pattern | 9 months production | 4 patterns documented, formal audit |
| Claude Code Channels | ~3 weeks stable | Daily use, 9+ days continuous uptime on current session |
| tmux orchestration (VNX) | 9 months production | 1,100+ receipts, 860+ sessions, context rotation at scale |
| SubprocessAdapter + EventStore | Validated | 90+ tests, 12/12 burn-in scenarios PASS |
| Event type normalization | Validated | 19 tests. CLI types (system/assistant) mapped to dashboard types (thinking/tool_use) |
| Stream archive (audit trail) | Validated | 6 tests. Events archived per dispatch to NDJSON files |
| Timeout + heartbeat protection | Validated | 7 tests. read_events_with_timeout() prevents infinite blocking |
| Directory-based agent isolation | ~1 week testing | 5/5 validation tests on GCP VM |
| Worker daemon + pipelines | ~1 week testing | Architecture validated, not production-hardened |
| Quality gate feedback loop | Design stage | Telegram notification works, reply routing fragile |
The pipeline from "Telegram message" to "blog published" works end-to-end. But I haven't stress-tested it with 50 concurrent tasks or run it unattended for a month. The honest assessment: the architecture is sound, the individual components are proven, but the integration layer is young.
The numbers
| Metric | Value |
|---|---|
| Monthly cost | ~€235 (€200 Max subscription + €35 GCP e2-standard-2) |
| GCP VM specs | 2 vCPU, 8GB RAM, 100GB SSD |
| RAM per worker | ~400MB active (process lives short, no permanent pressure) |
| Max concurrent workers | 2 (rate limit constraint) |
| Blogs produced in April | 25+ (via Channels, not yet via daemon pipeline) |
| Skills available | 42+ (blog, LinkedIn, research, SEO, marketing, sales) |
| Syncthing files synced | 73,000+ (MacBook to VM, bidirectional) |
| Current session uptime | 9 days continuous |
Compare to OpenClaw post-ban: API billing for equivalent usage would run $1,000-$5,000/day for heavy agentic workloads. My setup does the same work for €235/month — but requires a GCP VM, tmux knowledge, and comfort with systemd services. For a deeper breakdown of where the tokens go, see how I achieved 87% token reduction through intelligent routing.
Migration mapping: OpenClaw to Claude Code
If you're coming from OpenClaw, here's what maps to what:
| OpenClaw feature | Claude Code equivalent | Complexity |
|---|---|---|
| Telegram/Discord messaging | Claude Code Channels (official plugin) | Low — claude --channels plugin:telegram@claude-plugins-official |
| WhatsApp/Signal | Not available (Channels supports Telegram, Discord + iMessage) | N/A |
| Conversation memory | Session resume via --resume <session_id> | Medium |
| Skills marketplace | CLAUDE.md files in agent directories | Medium — no marketplace, you write your own |
| Multi-model routing | Provider command builder (Pattern D) | Medium |
| Web browsing | MCP servers (Brave Search, Perplexity) | Low |
| File access + shell | Built into Claude Code | Free |
| One-click setup | Manual: GCP VM + tmux + systemd + Claude login | High |
| Multi-agent pipelines | Worker daemon + directory-based agents | High — you build this yourself |
The honest gap: OpenClaw's multi-channel support is unmatched. If you need WhatsApp, Signal, and Slack from one config, Claude Code Channels doesn't do that — it covers Telegram, Discord, and iMessage. OpenACP supports more platforms, but it uses the Agent Client Protocol which may route through the Anthropic API rather than your CLI subscription — verify the billing implications before committing.
How to start (condensed)
If you want to build something similar, start with step 1 and add layers as needed.
Step 1: Bridge (30 minutes)
# On a GCP VM or any always-on Linux box
# Install Claude Code, login with Max subscription
claude --channels plugin:telegram@claude-plugins-official
# Run in tmux for persistence
tmux new -s channels
claude --channels plugin:telegram@claude-plugins-official
# Ctrl-B D to detachYou now have a Telegram bot connected to Claude Code with full filesystem access. This is already more capable than OpenClaw for single-user use — your bot can read files, run commands, use MCP servers.
Step 2: Agent directories (2 hours)
Create focused agent roles:
mkdir -p agents/{research,blog-writer,editor}
# Research agent
cat > agents/research/CLAUDE.md << 'EOF'
You are a research agent. Find 5-10 credible sources on the given topic.
Output a structured brief with citations, key statistics, and counter-arguments.
EOF
# Test it
cd agents/research && claude -p "Research: context rotation in AI agents"Step 3: Worker daemon (half day)
Build a daemon that polls a task queue and spawns claude -p in agent directories. The simplest version is ~80 lines of Python: poll queue, subprocess.run() in agent directory, update status, send notification. But in production you'll need timeout protection, heartbeat renewal, and crash recovery — which is why the VNX repo provides a SubprocessAdapter with deliver_via_subprocess() (~150 lines) that has all of this built in. Start simple, but don't ship the simple version.
Step 4: Pipelines and quality gates (ongoing)
This is where it gets interesting and where I'm still iterating. Multi-step pipelines, feedback loops via --resume, gate timeouts, crash recovery — the architecture is designed but not all of it is hardened.
What's next
The worker daemon is phase 0 of a larger plan. The direction is what I'm calling Agent OS — a unified orchestration substrate that supports multiple domains (coding, business, regulated) under one shared infrastructure with domain-specific governance profiles.
The five features on the immediate roadmap:
- Headless Worker Resilience (F31, in progress): timeout protection, health monitor, auto-restart with retry budget, subprocess receipts — all in one feature
- Headless T1 Backend Developer (F32): first terminal to go fully subprocess-based, no tmux
- Dashboard domain filter (F33): agent names replace terminal IDs (T1/T2/T3), domain filter tabs
- Skill context inlining (F34): agent CLAUDE.md prepended to prompts automatically
- End-to-end certification (F35): dispatch → stream → archive → receipt → gate → dashboard, verified
The SubprocessAdapter that powers this — event streaming, NDJSON archival, session ID extraction — already exists, is tested (90+ tests, 12/12 burn-in), and is open source.
📖 Read also: Traceability as Architecture: Every AI Decision Gets a Receipt — How receipts make multi-agent pipelines debuggable and auditable.
If you're building this too
I found seven community projects doing step 1 (bridges). I haven't found anyone doing step 2 (orchestration with agent isolation and pipelines) on top of Claude Code CLI.
If you are — or want to — I'd like to hear about it. Not to compete, but because this design space is wide open and I'm learning from what others build. The directory-based agent isolation pattern is simple enough that ten different people could implement it ten different ways, and we'd all learn something.
You can find me on LinkedIn or check out the VNX Orchestration repo on GitHub.
Frequently asked questions
Vincent van Deth
AI Strategy & Architecture
I build production systems with AI — and I've spent the last six months figuring out what it actually takes to run them safely at scale.
My focus is AI Strategy & Architecture: designing multi-agent workflows, building governance infrastructure, and helping organisations move from AI experiments to auditable, production-grade systems. I'm the creator of VNX, an open-source governance layer for multi-agent AI that enforces human approval gates, append-only audit trails, and evidence-based task closure.
Based in the Netherlands. I write about what I build — including the failures.