cd /news/ai-agents/coding-agents-over-telegram-part-2-f… Β· home β€Ί topics β€Ί ai-agents β€Ί article
[ARTICLE Β· art-26457] src=dev.to β†— pub= topic=ai-agents verified=true sentiment=Β· neutral

Coding Agents over Telegram, Part 2: From Zero to an Agent That Answers

A developer built a coding agent that responds to Telegram messages and drives a tmux pane on a local machine. The setup uses OpenClaw as a Telegram gateway, pinned Node.js and pnpm versions, and a readiness check script. The guide provides both a fast automated path and a manual step-by-step approach for wiring Telegram, the local box, and the agent together.

read11 min publishedJun 13, 2026

This is the one post in the series you do, not just read. By the end you'll have a single Telegram topic where you type a message and a coding agent answers and drives a tmux pane on your own box. That's the entire goal, nothing more. Memory, monitors, tool servers, and the supervisor all come later; none of them are needed to get an agent answering you.

Budget ~30–45 minutes. If you only do one thing, do the Fast path, then prove it with the readiness gate. Everything below the gate is manual explanation and debugging you can skip until you need it.

The Telegram wiring is the mechanical part; the real failures hide in local state. Confirm every line before you start:

tmux

, and shell access that survives disconnects (you'll leave a gateway running).mybox:1.1

). Write it down; you'll hard-code it into the agent's instructions.Pin these. "It runs on Node" is not enough; the gateway is sensitive to the runtime.

Component Pinned version Notes
Node.js 24.11.1
The gateway is built against Node 24; newer majors can fail the native build.
Package manager pnpm 11.2.2
OpenClaw's packageManager field. corepack fetches it for you.
OpenClaw
github.com/openclaw/openclaw , pinned commit (tested on 2026.5.27 )
Pin a commit or tag; don't track main for a setup everyone must reproduce.
Coding agent opencode, installed and authenticated Pin the version your team standardizes on.
Node manager nvm
This guide assumes nvm; adapt the commands if you use asdf or system Node.

Two scripts do the whole local setup. Grab them from the gist, then run them around the Telegram steps:

curl -fsSL "https://gist.githubusercontent.com/jerilkuriakose/cd0f8353aac74e47c591111b758943e9/raw/setup-openclaw.sh" -o setup-openclaw.sh
curl -fsSL "https://gist.githubusercontent.com/jerilkuriakose/7cf94af3e96526f9f14d0c28b6c26b69/raw/ready-check.sh" -o ready-check.sh
chmod +x setup-openclaw.sh ready-check.sh

OPENCLAW_BOT_TOKEN="<BOT_TOKEN>" OPENCLAW_BOT_ACCOUNT="my-bot" ./setup-openclaw.sh


AGENT_ID=my-agent PANE=mybox:1.1 ./ready-check.sh

setup-openclaw.sh

pins Node 24.11.1 and pnpm 11.2.2 (via nvm and corepack), clones and builds github.com/openclaw/openclaw

, and launches the gateway. ready-check.sh

runs the readiness gate for you. Prefer to understand each step, or hit a snag? Follow the manual path.

Three parts: the Telegram side, the box side, then wiring them together.

You must be the group's creator, so do these from your own Telegram account:

@BotFather

β†’ /newbot

β†’ name it β†’ save the project-a

).You also need your own numeric Telegram user ID for the allowlist. Easiest: message @userinfobot

and it replies with your ID. (Alternatively, it appears in the gateway log as the sender once messages start flowing in the next step.)

The gateway has to know about your bot before it can poll Telegram, so write a minimal valid config first. Create ~/.openclaw/openclaw.json

with just the bot account. Use strict JSON (no comments, no trailing commas) because that's exactly what the gateway parses and what you'll validate against:

{
  "channels": {
    "telegram": {
      "enabled": true,
      "accounts": {
        "<your-bot-account>": {
          "botToken": "<BOT_TOKEN>"
        }
      }
    }
  }
}

Lock it down and validate before launching:

chmod 600 ~/.openclaw/openclaw.json
python3 -c "import json; json.load(open('$HOME/.openclaw/openclaw.json')); print('JSON OK')"

Get OpenClaw and build it. It's open source. Pin the runtime, clone, install with the corepack

-provided pnpm, and build:

nvm install 24.11.1 && nvm use 24.11.1
corepack enable && corepack prepare pnpm@11.2.2 --activate

git clone https://github.com/openclaw/openclaw.git ~/repos/openclaw
cd ~/repos/openclaw
pnpm install
pnpm build                  # takes a few minutes

Now launch the gateway in its own tmux session so it survives your disconnect:

pnpm gateway:watch          # launches the gateway and manages its own tmux session

Find your log path (it differs by config), then confirm the gateway came up and the bot is polling:

ls -t /tmp/openclaw/openclaw-*.log | tail -1          # default location
grep -a 'gateway ready' <your-log-path> | tail -1     # expect a recent line

The log directory is locked down (

0700

), so read it from the shell, not an editor's file browser.This initial launch, and any laterlogging

orplugins.load

change, needs a gateway (re)start. The group/topic/routing edits in the next section hot-reload, no restart needed.

Config lives in ~/.openclaw/openclaw.json

. The gateway hot-reloads routing/topic/channel edits; no restart needed for these. We do this in two phases because you need the chat and topic IDs from the log, and the only way to make them appear is to let messages through first.

Phase 1: find the chat ID and open the group temporarily.

With the gateway now polling, send a message in your topic. It gets blocked (the group isn't configured yet), which conveniently logs the chat ID:

grep -a 'not-allowed' <your-log-path> | tail -1

Add a groups

block to your account so messages flow and topic IDs get logged. This is a fragment; merge the groups

key into the account you already created, keeping the file strict JSON:

"groups": {
  "<CHAT_ID>": { "groupPolicy": "open", "requireMention": false }
}

Save. The gateway hot-reloads (no restart).

Keep the open window tiny.groupPolicy: "open"

letsanyone in the groupdrive a shell-capable agent. The group must be private with only you in it, and this is a momentary bootstrap step: switch toallowlist

(Phase 2) as soon as you've harvested the topic IDs, before adding anyone else or doing real work.

Phase 1b: harvest topic thread IDs. Send a message in each topic (label them by text so you can tell them apart, since topic IDs are not sequential by creation order), then:

grep -ao 'Inbound message telegram:group[^"]*' <your-log-path> | sort -u

Phase 2: lock it down and route the topic to an agent. Now switch the group to an allowlist (owner-only), add yourself, map the topic to an agent, and declare that agent. Strict JSON, merged into your config:

"channels": {
  "telegram": {
    "enabled": true,
    "accounts": {
      "<your-bot-account>": {
        "botToken": "<BOT_TOKEN>",
        "groups": {
          "<CHAT_ID>": {
            "groupPolicy": "allowlist",
            "allowFrom": ["<YOUR_TELEGRAM_USER_ID>"],
            "requireMention": false,
            "topics": {
              "<TOPIC_THREAD_ID>": { "agentId": "<your-agent-id>" }
            }
          }
        }
      }
    }
  }
},
"agents": {
  "list": [
    {
      "id": "<your-agent-id>",
      "workspace": "~/.openclaw/workspace-<name>",
      "agentDir": "~/.openclaw/agents/<name>"
    }
  ]
}

requireMention: false

lets you type naturally instead of prefixing every message with an @mention

. allowFrom

with only your user ID is what stops anyone else in the group from driving a shell-capable agent. It's your numeric Telegram ID, kept as a quoted string as the config expects (for example, ["123456789"]

).

Give the agent its instructions. This is the step that makes status

, send

, and restart

work; the agent's behavior comes entirely from the files in its workspace

. Create the workspace directory first (the agentDir

must be unique per agent; the gateway creates it on first run):

mkdir -p ~/.openclaw/workspace-<name>

Then put this in ~/.openclaw/workspace-<name>/AGENTS.md

, a minimal command contract:


You are bound to tmux pane `<PANE>`, an interactive coding-agent session.

## Hard rules
- ALL tmux operations target `<PANE>`. Never touch any other session.
- Read with `tmux capture-pane -t <PANE> -p`; write with `tmux send-keys -t <PANE> ...`.
- Strip ANSI codes before relaying pane output to Telegram.
- After send-keys, wait a few seconds before re-capturing; replies aren't instant.
- Confirm before any destructive action EXCEPT the explicit "restart" command below.

## Common phrasings β†’ actions
| User says | You do |
|---|---|
| "status" / "what's in tmux?" | capture `<PANE>`, strip ANSI, summarize the last ~60 lines |
| "send `<msg>`" | `send-keys -t <PANE> -l -- "<msg>"`, then Enter, wait, capture |
| "compact" / "new session" | send `/compact` or `/new` to the pane |
| "interrupt" / "stop it" | confirm, then send `C-c` |
| "restart" | run the restart sequence below (no confirmation) |

## Decision / option routing
You are a relay, not the owner of the work in the pane. If your previous reply
summarized options/questions from the agent (e.g. "A/B", "yes/no", "Proceed?"),
then short replies like `A`, `B`, `yes`, `no`, `do it`, `sorry A` are answers
**for the pane**: forward them verbatim; do not act on them yourself. Only act
locally when explicitly addressed ("you do option A").

## Restart sequence (no confirmation)
1. Resolve the exact session id first (do not blindly "continue", which can reopen the wrong session).
2. Exit the agent's UI cleanly and wait until you actually see a shell prompt.
3. Relaunch with EXACTLY this command, resuming that session id: `<your-launch-command> --resume <session_id>`
4. Capture and report whether it came back up.

## Safety rails (applied to anything you relay)
- Production: strict read-only. Never relay mutations.
- Never relay pushes/merges to shared branches.
- Shared infra (gateways, API gateways): never mutate without explicit human approval.

Replace

<PANE>

and the restart command with your exact values; leave them vague and the agent will improvise and can lose your session. This single fileisyour agent; the workspace can contain justAGENTS.md

to start.

Required: validate before you trust the save. An invalid openclaw.json

is dangerous: on a restart the gateway rejects it, auto-restores the last-known-good, and the watch process exits (that is, an outage). Editing a running gateway is safer (a bad edit is reverted with no downtime), but never restart on an unvalidated config. Every time:

python3 -c "import json; json.load(open('$HOME/.openclaw/openclaw.json')); print('JSON OK')"

cp ~/.openclaw/openclaw.json /tmp/oc-check.json && chmod 600 /tmp/oc-check.json
OPENCLAW_CONFIG_PATH=/tmp/oc-check.json pnpm openclaw doctor --non-interactive   # expect Errors: 0
rm -f /tmp/oc-check.json

grep -a 'config hot reload applied' <your-log-path> | tail -3

You are not done when the config saves. You're done when you have evidence the whole path works. Verify all five; this is exactly what you'll confirm to the session organizer:

status

in your topic; you get a response (not silence).

   tmux capture-pane -t <PANE> -p | tail -n 40

You should see your text injected into the coding agent.

   ls -t ~/.openclaw/agents/<name>/sessions/*topic-<TOPIC_THREAD_ID>* 2>/dev/null

groupPolicy: "allowlist"

, your ID in allowFrom

, and requireMention: false

; you're no longer in open

mode from Phase 1.If all five hold, you're ready for the session. Capture a redacted screenshot/log snippet of #1–#2 as your "I'm ready" artifact, and redact the log excerpt too (it carries chat IDs, thread IDs, your user ID, and message text), not just the screenshot.

Recovery first. If a restart took the gateway down, your edit wasn't lost; the gateway auto-restored the last-known-good and saved your version alongside it. Recover from ~/.openclaw/openclaw.json.clobbered.*

(also check .last-good

/ .bak

), fix the cause, validate (above), then restart:

nvm use 24.11.1
tmux kill-session -t openclaw-gateway-watch-main
cd ~/repos/openclaw && pnpm gateway:watch
grep -a 'gateway ready' <your-log-path> | tail -1
Symptom Cause Fix
Bot silent; log shows "reason":"not-allowed"
Group not configured, or you're not in allowFrom
Add the group; put your numeric ID in allowFrom (or use open while testing)
Bot only replies when @mention ed
requireMention defaulting to true
Set requireMention: false
Bot doesn't see messages at all Telegram privacy mode on a non-admin bot Make the bot a group admin
Topic IDs never appear in the log Messages blocked before topic resolution Open the group (Phase 1) first, then re-send
getUpdates 409 Conflict
Same bot token polled by two gateways One gateway per token; kill the duplicate poller
Config edit "vanished" / gateway down after restart Invalid JSON at startup β†’ auto-restore β†’ watch exits Recover from .clobbered.* ; validate; restart
Agent replies but the pane does nothing Wrong <PANE> , or the coding agent isn't running there
Fix the pane target; relaunch the agent in that pane

This is a public-internet bot with shell reach. Treat it that way:

openclaw.json

. chmod 600

@BotFather

.allowFrom

.You do not need any of this to finish the readiness gate; it all comes in Part 4 / the session:

AGENTS.md

already handles status

/send

/restart

/option replies prompt-driven; the router just makes it faster and stricter)ops

agent (box-wide shell). One relay + one pane is the whole assignment.24 hours out, confirm you can tick all five readiness items and post your redacted "ready" artifact. If you're blocked, send your symptom plus your Node/pnpm versions and the last few gateway log lines (redacted) so it can be sorted before we're all in the room.

Part 3 is the operating contract: what to type, what not to type, and how to supervise the agent safely once it's answering you.

── more in #ai-agents 4 stories Β· sorted by recency
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain β€” perfect for shipping the agent you just read about.

$git push zahid main
β†’ Live at https://your-agent.zahid.host βœ“
Get free account β†’ Pricing
from €0/mo Β· no card required
LIVE [news/coding-agents-over-t…] indexed:0 read:11min 2026-06-13 Β· β€”