Loading...
Loading...

View Source Code
github.com/Danm72
Connect on LinkedIn
linkedin.com/in/d-malone
Follow on Twitter/X
x.com/danmalone_mawla
Share this article
CLAUDE.md and MCP servers. What I didn't have: access to those same contexts from my phone, agents that run while I sleep, and agents that talk to each other. OpenClaw + Telegram adds all three without replacing what already works. Here's the step-by-step guide, including every config example and bug fix along the way.In my last post, I explored the idea of Mission Control — a coordination layer for AI agent squads. I built a dashboard spike with Kanban boards, heartbeats, and squad state. It helped me think clearly, but it exposed the wrong bottleneck.
I looked at the landscape — Zapier, Make, Lindy.ai, Relevance AI, n8n — plus a lot of indie dashboard experiments that fizzled out.
The question that cut through it:
What does a dashboard give me that I don't already get from running Claude Code locally?
For my setup, not much. I already had visibility via terminal output, session logs, and git history.
What I actually lacked was:
Here's the current setup on my laptop. Each folder is a git repo with a CLAUDE.md, MCP servers, and supporting code:
| Folder | Purpose | Key Tools | OpenClaw Agent |
|---|---|---|---|
| Accounts | Bookkeeping, invoicing, reconciliation | Xero MCP | 💰 Fin |
| Tasks & Goals | Client management, task tracking, planning, SOPs | Gmail, Notion MCP, Granola MCP, calendar CLI | 📋 Goaly |
| Home Automation | Smart home control, automations, sensors | Home Assistant MCP | 🏠 Homey |
| Blog | Content pipeline, drafts, publishing | Content skills, git | — (future) |
| Website | dan-malone.com dev and deployment | Next.js tooling, Vercel | — (future) |
CLAUDE.md mapping Notion databases, schemas, and workflows. At the desk, it's savage. Claude can triage inbox, flag overdue tasks, prep calls, and draft weekly plans.
For deep work, this setup is exactly what I want: terminal-first, high-context, and flexible.
The friction starts when I'm away. I want to check status from my phone, get overdue alerts, or run Monday planning before coffee. I also want Goaly to ask Homey a question without me acting as the middleman.

| Mode | When | Interface | What You Get |
|---|---|---|---|
| Deep work | At the desk | Claude Code terminal | Agent swarms, compound engineering, brainstorm/plan/work workflows, file editing |
| On the go | Away from desk | Telegram on phone | Quick queries, status checks, approvals |
| Always-on | 24/7 | Heartbeats + crons | Scheduled workflows, monitoring, notifications |
At the desk, Claude Code still does the heavy lifting.
On the go, the same context is available in Telegram.
Always-on handles scheduled work whether I'm online or not.
And there is one capability that's genuinely new: cross-context collaboration. OpenClaw agents can message each other with sessions_send, so Goaly can ask Homey for a quick check instead of waiting for me.

Here's what the always-on mode looks like in practice — two agents handling their scheduled workflows overnight:

I'd been running Claudette 🦝 on OpenClaw since January for smart-home control. When I expanded to multiple specialists, these were the features that mattered in practice.
| Feature | What It Means |
|---|---|
| Forum supergroup support | Each agent gets their own topic thread |
| Multi-account | Multiple bots in one group, routed to different agents |
| DM and group policies | Control where each bot responds |
| Streaming responses | Partial message updates as the agent thinks |
| Media handling | Images, documents, voice messages |
Forum topics made this sane. Instead of one noisy group chat, each bot owns a topic. Homey lives in Home. Goaly lives in Tasks. You jump to the thread you need and talk to the right agent.
SOUL.md, memory, and session storeThis is what made my dashboard spike redundant. OpenClaw already includes persistence:
| Mechanism | Use Case | Example |
|---|---|---|
| Heartbeats | Routine monitoring at configurable intervals | Check sensors, flag anomalies |
| Cron jobs | Scheduled rituals (isolated sessions, configurable model) | Monday planning, daily inbox triage |
| Hooks | Event-driven triggers | Respond to webhooks, process incoming data |
mcporter call notion.query_database '{"database_id": "abc123"}'
So I could keep my existing MCP investments instead of rebuilding tooling.
Agents can talk to each other via sessions_send, but only if explicitly allowed in the agentToAgent config. You control who can message whom. No agent goes rogue broadcasting to siblings it shouldn't know about.
Enough philosophy. Here's exactly how I set it up.
The starting point: a single Claudette 🦝 agent running on OpenClaw inside a Proxmox container. One Telegram bot, one massive context, one set of tools. As OpenClaw added multi-agent routing features, the opportunity became clear — split Claudette's responsibilities into specialized agents.
The first decision was architectural: multiple Telegram bots (one per agent) vs. one bot with per-topic system prompts.
Multiple bots won:
| Factor | Single Bot | Multiple Bots |
|---|---|---|
| Isolation | Shared context, shared sessions | Own workspace, own sessions |
| Identity | One name in chat | Each bot has its own @mention |
| Tooling | All tools loaded always | Domain-specific tools per agent |
| Communication | N/A (same agent) | sessions_send for cross-domain |
| Extensibility | Config changes | New bot + workspace + binding |

And here's what it looks like in Telegram — one forum, four bots, each owning their topic:

Four agents, each with a distinct personality defined in a SOUL.md file:
"You know this home better than anyone."
Practical, reliable. Like a building superintendent who actually cares. Controls Home Assistant — automations, sensors, devices, climate. Cautious with security devices (locks, alarms) — confirms before toggling.
Be practical, not flashy. When someone says "it's cold," adjust the heating.
When a sensor goes offline, flag it. Don't over-explain — just handle it.
"You keep things moving."
Organized, proactive. Like a chief of staff who actually gets things done. Manages tasks, goals, client relationships, email, calendar, meeting notes.
Be proactive, not reactive. Don't wait to be asked. If a deadline is
approaching, flag it. If a task is overdue, surface it.
"The numbers don't lie, and neither do you."
Precise, trustworthy. Like an accountant who actually enjoys spreadsheets. Handles bookkeeping, accounts reconciliation, invoicing, expense categorization.
Be precise above all else. Numbers must be right. Double-check calculations.
Verify amounts. A small error in finance becomes a big problem later.
Each agent knows its boundaries — and who to hand off to:
Know your limits. For tasks and goals, hand off to Goaly. For smart home,
that's Homey. For general stuff, Claudette (main).
Before creating new bots, I recommend a 5-minute preflight:
openclaw.json and workspace foldersUsed BotFather to create three new bots:
| Bot | Username | Agent |
|---|---|---|
| Homey | @HomeyBot | Home Assistant |
| Goaly | @GoalyBot | Tasks & Goals |
| Fin | @FinBot | Finance |
| Topic | Thread ID |
|---|---|
| General | 1 |
| Finance | 2 |
| Home | 4 |
| Tasks | 5 |
The existing Claudette setup used a simple single-bot Telegram config:
{
"channels": {
"telegram": {
"enabled": true,
"botToken": "<CLAUDETTE_TOKEN>",
"dmPolicy": "pairing",
"groupPolicy": "allowlist",
"streamMode": "partial"
}
}
}
This needed to become a multi-account structure. Three major additions to openclaw.json:
{
"agents": {
"defaults": {
"model": { "primary": "anthropic/claude-opus-4-6" }
},
"list": [
{ "id": "main", "default": true, "name": "Claudette",
"workspace": "/root/.openclaw/workspace" },
{ "id": "home", "name": "Home Assistant",
"workspace": "/root/.openclaw/workspace-home",
"identity": { "name": "Homey", "emoji": "🏠" } },
{ "id": "tasks", "name": "Tasks & Goals",
"workspace": "/root/.openclaw/workspace-tasks",
"identity": { "name": "Goaly", "emoji": "📋" } },
{ "id": "finance", "name": "Finance",
"workspace": "/root/.openclaw/workspace-finance",
"identity": { "name": "Fin", "emoji": "💰" } }
]
}
}
{
"bindings": [
{ "agentId": "home", "match": { "channel": "telegram", "accountId": "home" } },
{ "agentId": "tasks", "match": { "channel": "telegram", "accountId": "tasks" } },
{ "agentId": "finance", "match": { "channel": "telegram", "accountId": "finance" } }
]
}
The main agent doesn't need a binding — it's the default fallback.
Each bot account gets its own groups config. The key pattern: requireMention: true at the group level (quiet in General unless @mentioned), requireMention: false for its own topic (responds freely).
{
"channels": {
"telegram": {
"enabled": true,
"streamMode": "partial",
"accounts": {
"default": {
"botToken": "<CLAUDETTE_TOKEN>",
"groups": { "-100374...": { "enabled": true, "requireMention": true } }
},
"home": {
"botToken": "<HOMEY_TOKEN>",
"groups": { "-100374...": {
"enabled": true, "requireMention": true,
"topics": { "4": { "requireMention": false } }
}}
}
}
}
}
}
{
"tools": {
"agentToAgent": { "enabled": true, "allow": ["main", "home", "tasks", "finance"] },
"sessions": { "visibility": "all" }
}
}
agentToAgent.enabled AND sessions.visibility: "all" are required. The first enables the feature; the second lets agents actually see each other's sessions. Without both, session discovery fails and you'll get No session found errors.openclaw workspace init to scaffold new agent workspaces with template files (SOUL.md, IDENTITY.md, AGENTS.md, TOOLS.md, USER.md). Each workspace is fully isolated:
~/.openclaw/
├── workspace/ # Claudette (main)
├── workspace-home/ # Homey
├── workspace-tasks/ # Goaly
└── workspace-finance/ # Fin
Since Homey was taking over Home Assistant duties from Claudette, we gave Homey a head start — Claudette's entire memory, session history, and secrets were copied over:
| What | Details |
|---|---|
| Memory files | Daily notes, HA changes log, heating monitor, shopping list |
| Secrets | Google OAuth credentials, gog CLI env |
| Sessions | 23 JSONL files, keys remapped from agent:main:* to agent:home:* |
| Config | USER.md, TOOLS.md, HEARTBEAT.md |
Goaly's workspace is unique — it's backed by an existing GitHub repo that's also used directly from other machines. The repo contains:
CLAUDE.md with full Notion database mappings (database IDs, column schemas, workflows)clients/ directory with folders for each client containing comms logs, docs, and memory.mcp.json with Notion and Granola MCP configurations{
"mcpServers": {
"notion": {
"command": "npx -y @notionhq/notion-mcp-server",
"env": { "OPENAPI_MCP_HEADERS": "..." }
},
"granola": { "type": "http", "url": "https://mcp.granola.ai/mcp" },
"notion-http": { "type": "http", "url": "https://mcp.notion.com/mcp" }
}
}
The AGENTS.md was updated with a critical step 0 — sync before anything else:
## Every Session
Before doing anything else:
0. Run `git pull --rebase origin main` to sync workspace
1. Read `SOUL.md` — this is who you are
Fin got the basic scaffold — SOUL.md, IDENTITY.md, AGENTS.md — with plans to add Xero API integration later. No memory, no secrets. Sometimes a fresh start is right.
Six bugs in one afternoon. Here's what broke and why.
agents.defaults.model: Invalid input: expected object, received string
We'd set the model as a plain string. OpenClaw expects an object:
// Wrong
"model": "anthropic/claude-opus-4-6"
// Right
"model": { "primary": "anthropic/claude-opus-4-6" }
Quick fix once we found the config reference.
channels.telegram.groups.*.topics.*.label: Unrecognized key
We'd added "label" keys to topic configs for readability. OpenClaw's schema is strict — valid topic keys are: requireMention, skills, systemPrompt, enabled, groupPolicy, allowFrom. That's it.
When agents.list exists, OpenClaw's fallback order is:
"default": trueWe'd listed home first without giving main explicit default: true. The implicit "main" got displaced.
This was the nastiest bug. The groups config was at the top level of channels.telegram, making it global across all bot accounts. Every bot saw every topic as "respond freely."
groups config INTO each channels.telegram.accounts.<id> section. Per-account, not global.

Session Send: with label finance, timeout 30 failed:
No session found with label: finance
This had two independent causes:
Cause 1:tools.sessions.visibility defaults to "tree" — agents can only see their own session tree. Even with agentToAgent.enabled: true, agents couldn't find each other's sessions.
Cause 2: Target agents had never been activated. They had no main session to receive messages on.
Fixes:
sessions.visibility: "all" (the hidden requirement)openclaw agent --agent <id> --message "System init"openclaw agent --agent home --message \
"Use sessions_send to send a message to the finance agent
session key agent:finance:main. Say: Hey Fin, testing comms."
Fin replied: "Received loud and clear, Homey!"
When setting up Goaly, we copied Claudette's memory files into the workspace.
The .gitignore only excluded memory/heartbeat-state.json — not the entire memory/ directory. The git sync cron job (running every 15 minutes) auto-committed and pushed everything.
.gitignore to exclude all agent-specific files:
# Agent-specific (not shared)
memory/
SOUL.md
IDENTITY.md
AGENTS.md
TOOLS.md
USER.md
HEARTBEAT.md
MEMORY.md
config/mcporter.json
.openclaw/
.secrets/
Ran git rm --cached to untrack files while keeping them on disk. Pushed cleanup.
.gitignore right BEFORE the first sync runs.Since Goaly's workspace is also used from other machines, we needed bidirectional sync. The solution: a cron-based script.
#!/bin/bash
# /usr/local/bin/openclaw-git-sync.sh
WORKSPACE="${1:?Usage: $0 /path/to/workspace}"
AGENT_NAME="${2:-openclaw}"
cd "$WORKSPACE" || exit 1
# Stash → pull --rebase → pop → add -A → commit → push
git stash
git pull --rebase origin main
git stash pop
git add -A
if ! git diff --cached --quiet; then
git commit -m "sync: auto-commit from $AGENT_NAME"
git push origin main
fi
Cron: */15 * * * * /usr/local/bin/openclaw-git-sync.sh /root/.openclaw/workspace-tasks goaly
Goaly's HEARTBEAT.md also includes a git sync check on each heartbeat (catches changes between cron runs) plus a Notion inbox check for overdue tasks.
Telegram Forum Supergroup
├─ General Topic → All bots: @mention required
├─ 🏠 Home Topic → Homey responds freely
├─ 📋 Tasks Topic → Goaly responds freely
└─ 💰 Finance Topic → Fin responds freely
Inter-agent communication (via sessions_send):
Homey ↔ Goaly ↔ Fin ↔ Claudette
Workspaces:
workspace/ → Claudette (general, default)
workspace-home/ → Homey (HA tools, inherited memory)
workspace-tasks/ → Goaly (Notion + Granola MCPs, git-synced)
workspace-finance/ → Fin (basic, Xero pending)
Always-on:
Heartbeats → Sensor monitoring, anomaly detection
Crons → Scheduled rituals (inbox triage, weekly planning)
Hooks → Event-driven triggers (webhooks, notifications)

model must be an object, not a string — { "primary": "provider/model" }default: true explicitly on your main agentgroups config — never at the top-level channels.telegramsessions.visibility: "all" is the hidden requirement for inter-agent communication.gitignore right before auto-sync — agent memory and config must be excluded from shared reposThe team is running. Four agents, four topics, one forum. But this is just the foundation. The roadmap:
| Priority | What | Why |
|---|---|---|
| Now | Xero integration for Fin | Bookkeeping without spreadsheets |
| Now | Email triage via Goaly | Morning inbox summary at 8 AM |
| Next | Meeting prep automation | Goaly pulls Granola notes + Notion context before calls |
| Next | Monday morning planning ritual | Weekly priorities, overdue flags, client check-ins |
| Later | More agents | Research agent, content agent, client-specific agents |
| Later | MCPorter HTTP MCP validation | Confirm Goaly's Granola and Notion HTTP transports |
From one raccoon controlling my lights, to orchestrating agents with bash scripts, to exploring coordination dashboards, to persistent AI staff on Telegram. Each step taught me something about what actually matters in multi-agent systems.
sessions_send for cross-domain handoffs. Same context, three modes.Explore the Full Code
Star the repo to stay updated
Let's Connect
Follow for more smart home content
Follow on Twitter/X
x.com/danmalone_mawla
Continue reading similar content

I replaced my lead capture form with an AI conversation. You chat about your project, the AI extracts structured data in real time, and you walk away with a 12-page branded PDF brief. No forms. No wizards. Just a conversation.

I wanted a repeatable way to turn project context into polished 30-40 second launch videos. This is the architecture, quality loop, and hard lessons from building the video engine.

A viral post about 10 AI agents coordinating like a real team got 3.5M views. I'm building the platform that gives every OpenClaw user the same power.