Use when adding a new specialized OpenClaw agent to a gateway deployment (a repo-reviewer, a notifier, or an on-demand assistant reachable via Telegram). Encodes the decision order, the directory + CI-sync layout, the one-bot/one-topic Telegram routing, and two non-obvious verified runtime constraints (forum-topic file delivery and web-search providers) so you don't re-derive them per agent. Triggers on "add an OpenClaw agent", "new OpenClaw bot", "create an agent that runs on the gateway".
Install
npx skillscat add igor1309/ai-labs/add-openclaw-agent Install via the SkillsCat registry.
Add an OpenClaw Agent
A decision-ordered checklist for adding a specialized agent to an OpenClaw gateway.
It is a process + pointers guide, not a copy of the deployment's facts — the
concrete host, bot, supergroup, topic, and chat IDs live in the deployment's own
docs and are read fresh from there (see Sources of truth at the end). Do not
hardcode those values into an agent definition or into this skill.
Mental model
A specialized agent is a definition that lives in your repo and a runtime
owned by the gateway:
- The definition is a directory (
agent/agent.md+ supporting*.md). CI rsyncsagent/**to the gateway's per-agent workspace, renamingagent.md→AGENTS.md
(OpenClaw loads workspaceAGENTS.mdas the system prompt). - The runtime — schedule, listener, credentials, checkout path — is the gateway's
concern. The agent definition must not assume a runtime layout beyond what it is
handed.
Keep the agent's standard (the rubric/prompt it applies) read fresh from its
source where practical, rather than vendoring a copy that will drift.
Decide first (these change the shape)
- Trigger mode.
- Inbound-only — runs only when messaged in Telegram (
@-mention in its
topic). Simplest: no cron wrapper, no suppression gate, no heartbeat. - Scheduled — a
/etc/cron.dwrapper invokes it on a cadence. Never use the
gateway scheduler (openclaw cron add) for anything that must survive a restart
— those jobs are wiped on every gateway restart. System/etc/cron.donly. - Both — inbound + scheduled (needs a suppression gate so a manual run
doesn't collide with the next tick).
- Inbound-only — runs only when messaged in Telegram (
- Does it write to a repo? A reviewer opens PRs (needs
ghwrite scope, a
branch convention, an auto-merge-forbidden rule). A self-contained assistant
(e.g. research) writes nothing — its only output is the message/file it returns. - Output channel + size. A short status fits a normal text reply. A long
artifact (a report) needs file delivery — see the Forum-topic file delivery
constraint below before promising "I'll attach a file."
Layout
agents/<agent-name>/
├── agent/
│ ├── agent.md # system prompt → deployed as AGENTS.md
│ └── *.md # notification-spec / suppression-policy / etc. as needed
├── runtime/ # ONLY if scheduled — cron wrapper + /etc/cron.d entry
│ └── cron/
├── docs/
│ └── log.md
├── README.md
└── TODO.mdCI sync
Add .github/workflows/<agent-name>-sync.yml modeled on an existing*-agent-sync.yml: on push to the default branch touching agents/<agent-name>/agent/**,
rsync agent/** to the gateway workspace and mv agent.md AGENTS.md. Reuse the
existing deploy SSH key secret.
runtime/**is NOT CI-synced. Cron wrappers are hand-deployed (scp +chmod 700).
A wrapper edit in the repo does not reach the host until someone re-deploys it.
Telegram routing (shared-bot convention)
One bot, one forum-supergroup, one topic per agent:
- Inbound routes per topic via
channels.telegram.accounts.<acct>.groups.<chatId>.topics.<threadId>.agentId,
withgroupPolicy: "allowlist"andrequireMention: true(@-mention the bot
in the topic to trigger that topic's agent). - Register the agent in
openclaw.jsonagents.list({id, workspace}); add the
inbound topic binding only if it answers inbound (a cron-only agent is registered
without a binding). - Find a topic's
threadIdby copying any message link in the topic:t.me/c/<chat>/<threadId>/<msg>— the middle segment is thethreadId. WithrequireMention: true, OpenClaw does not log the threadId for skipped non-mention
posts, so use this link trick, not the inbound logs. - The bot must be admin in the supergroup (privacy mode otherwise hides
non-mention posts). The General topic (threadId=1) must omitmessage_thread_idon sends — Telegram rejectsthread_id=1.
Two verified runtime constraints (don't re-derive)
Forum-topic file delivery — the agent's message tool can't do it
In a Telegram forum topic (is_forum: true), OpenClaw auto-disables the
agent's message tool (disableMessageTool=true) — not overridable bychannels.telegram.actions.sendMessage or tools.allow (OpenClaw issue #31368,
closed won't-fix). And even outside topics the message tool only sends
image/audio/video/sticker via mediaUrl — not generic documents.
To deliver a document (a .md/.pdf report) into a topic, the agent must shell
out: write the file, then call the Telegram Bot API sendDocument itself via
its exec tool, passing chat_id + message_thread_id (documents up to 50 MB).
This is the same deterministic Bot API pattern scheduled wrappers use forsendMessage. The openclaw message send --channel telegram --thread-id <topic> --media <file> CLI is the documented workaround but is image/audio/video-oriented,
so prefer raw sendDocument for a true document. A short text summary can still ride
the normal reply channel; only the file needs the shell path.
Web research — web_fetch is free, web_search needs a provider
web_fetch— plain HTTP GET, HTML→markdown, no key, on by default. Good
for reading a known URL (official site, docs, changelog). No JS execution.web_search— enabled by default but needs a provider selected.
Key-required: Brave, Tavily, Exa, Firecrawl, Perplexity, Gemini, Grok, Kimi.
Key-free: DuckDuckGo, Codex Hosted Search, SearXNG, Parallel (free), Ollama.
On a Codex-harness deployment (codex/*model over OpenAI OAuth), prefer
Codex Hosted Search — it rides existing auth, no new key. Confirm/settools.web.search.provideron the live config.
VPS wiring + the maintenance rule
Wiring the agent on the host (config edit, binding, cron, new topic) is an
approval-required, SSH-authorized step. Any live change to gateway config
(openclaw.json, bindings, cron, sudoers, the unit, scripts) MUST be mirrored to
the deployment's external inventory docs (migration.md + dated log.md) in the
same change. SSH to the live host requires explicit per-session authorization
naming the host.
Checklist
- Trigger mode chosen (inbound / scheduled / both).
- Repo-writing vs. self-contained decided (PR scope +
ghscope if writing). - Output channel sized; if a file → the
sendDocument-via-execpath is in the
agent'sagent.md. -
agents/<name>/laid out;agent/agent.mdwritten;runtime/only if scheduled. -
<name>-sync.ymladded; deploy key reused. - Registered in
agents.list; inbound topic binding added (if inbound); new topic
created;threadIdcaptured. - Web provider confirmed (Codex Hosted Search or other) if the agent browses.
- Live change mirrored to inventory
migration.md+log.md; agents register in
the repo's agentsREADME.md/dashboards.
Sources of truth (read these for the concrete IDs — do not copy them here)
- The deployment's
agents/README.md,agents/runbook.md,agents/gotchas.md—
the shared-bot/supergroup/topic IDs, routing caveats, and per-agent registry. - The inventory
vps/OpenClaw/README.md,CLAUDE.md,gotchas.md,agent-cron-jobs.md— host/access, config layout, cron mechanism, live state. - An existing agent of the closest shape (a reviewer, or an inbound-only assistant)
as the structural template.