Telegram Topics
Scope: Telegram forum topics only. Prefer the single configured Telegram account/group when exactly one exists.
Trusted sources only:
openclaw.jsonconfig.- Live Telegram Bot API responses.
$WORKDIRfor locating active project directories when creating coding/OpenCode topics.
Never use OpenClaw topic-name/session caches for topic discovery, drift, cleanup, or deletion. Cache may be empty on a new machine and may retain manually deleted topics.
Config map:
agents.list: available agents and models/skills.agents.list[].runtime.type="acp": ACP/OpenCode-capable configured agents, e.g.opencode.channels.telegram.accounts.<account>.groups.<forumId>: configured forum group andtopics; topic keys are Telegrammessage_thread_idstrings. Topic entries are schema-restricted routing options only; do not add descriptive fields there.bindings: route peer<forumId>:topic:<topicId>to an agent.bindings[].type="acp"creates persistent ACP/OpenCode conversation bindings; this top-level binding is sufficient for ACP topics.- Telegram forum group id is
-100{peerID}.
Topic kinds:
- General/root topic: topic
1; Telegram's built-in topic. It always exists in a forum group and cannot be deleted. - OpenClaw ops topics: normal OpenClaw chat, e.g.
main,fast,ops; use route topics. - Coding/OpenCode topics: Telegram topics bound to persistent ACP sessions, usually
agentId: opencode, withacp.cwdset to a project directory under$WORKDIR. A project may have many topics; names must include a short unique suffix.
Why there is no drift sync
Telegram Bot API cannot list all forum topics. Therefore OpenClaw cannot safely discover topics that a user created manually in Telegram. Do not implement or fake drift discovery. Manual topics are intentionally ignored; if a topic should be managed, create it through the ops agent / OpenClaw flow so its returned topicId can be added to config.
Utility commands
The helper intentionally has only three user-facing operations:
scripts/topic_config.py check
scripts/topic_config.py add <topicId> --agent <agentId> [--name <topicName>]
scripts/topic_config.py add <topicId> --kind acp --agent opencode --project <projectName> [--task <shortTask>] [--name <topicName>]
scripts/topic_config.py delete <topicIds>
Where <topicIds> for delete may be comma-separated, e.g. 7,58,67.
remove is kept only as a backwards-compatible alias for delete; prefer delete in docs and answers.
Check
Run before edits:
scripts/topic_config.py check
It probes all configured topics and prints JSON with:
ok: configured topics confirmed live in Telegram.missingInTelegram: configured non-General topics Telegram reports as missing.protectedGeneralTopicNotTouched: topic1oddities; never delete this route automatically.probeErrorsNotTouched: ambiguous errors; do not edit config from these.
The probe intentionally sends a silent probe message into each configured topic and immediately deletes it, because Telegram Bot API has no read-only topic lookup and sendChatAction can incorrectly return success for manually deleted topics.
To check one known topic without probing everything:
scripts/topic_config.py check --topic <topicId>
Create route topic / add routing
For normal OpenClaw topics:
- Create the topic through OpenClaw, preferably via
ops:messagetool withaction="topic-create",channel="telegram",accountId,chatId,name. - Route returned
topicId:scripts/topic_config.py add <topicId> --agent <agentId> [--name <topicName>] [--account ...] [--chat ...]. - Restart/reload OpenClaw after config edits when possible.
- Reply with topic name/id and agent id.
Create OpenCode / ACP project topic
Use this when the user asks for an OpenCode/coding agent topic for a project.
- Identify the source project directory:
- If the user gives an explicit path, use it as
--cwdafter verifying it exists. - If the user names a project, search immediate child directories under
$WORKDIR. - Match exact normalized directory names first; fuzzy substring matches are acceptable only when unique.
- If nothing matches or multiple projects match, ask the user to choose. Do not guess.
- If the user gives an explicit path, use it as
- Pick one ASCII slug that will be used consistently as Telegram topic name, git branch name, and worktree directory suffix:
- If the user provided a topic name or branch/worktree name, treat it as the common name for all three.
- Transliterate Cyrillic and slugify to lowercase ASCII with hyphens, e.g. project
foo+белый лис→foo-beliy-lis. - If no name/task is provided, generate an English slug; do not generate Russian defaults.
- Create a git worktree from the source project main branch under
$WORKDIRnamed<project-name>-<topic-slug>; do not work in the source project directory. - Create the Telegram forum topic using the same slug as its name:
messagetool withaction="topic-create",channel="telegram",accountId,chatId,name. - Add persistent ACP binding for the returned topic id. The ACP
cwdmust point at the worktree, not the source project:
scripts/topic_config.py add <topicId> --kind acp --agent opencode --project <projectName> [--task <shortTask>] [--name <topicOrBranchSlug>]
If project resolution is ambiguous or no project matches, ask the user. With an explicit choice/path, rerun:
scripts/topic_config.py add <topicId> --kind acp --agent opencode --cwd /abs/path/to/source-project [--task <shortTask>] [--name <topicOrBranchSlug>]
For ACP topics, the required config change is a top-level binding shaped like this. Keep it schema-valid: acp may contain mode, cwd, label, and optionally backend only.
{
type: "acp",
agentId: "opencode",
match: {
channel: "telegram",
accountId: "group",
peer: { kind: "group", id: "-1001234567890:topic:42" }
},
acp: {
mode: "persistent",
cwd: "/path/from/WORKDIR/project-topic-slug",
label: "project-topic-slug"
}
}
When converting an already-created normal OpenClaw topic to ACP, remove any stale normal route binding for the same peer and clear/remove the normal topics.<topicId>.agentId route; the ACP binding owns that conversation.
Delete topic + routing
Topic 1 is Telegram's built-in General/root topic. It always exists in a forum group and cannot be deleted. Never suggest deleting topic 1, never call delete 1, and never let cleanup remove its OpenClaw routing even if a probe looks odd.
When the user asks to delete a topic, the intended final state is:
- the Telegram forum topic is deleted/closed in Telegram;
- OpenClaw config routing/bindings for that topic are removed; and
- if the topic has an ACP worktree binding, remove that git worktree and then delete its local branch when safe.
Never delete the source project directory. Only remove the worktree path recorded in the ACP binding acp.cwd; infer the branch from that live worktree when it still exists. If the worktree was already removed earlier, that is OK; still remove the Telegram topic and config binding. In the final reply, say what was deleted: Telegram topic only, config binding, worktree, and/or branch.
Do not treat config-only deletion as complete for an explicit user delete request. For non-General topics, first delete the topic in Telegram via the Telegram UI or Bot API deleteForumTopic, then remove OpenClaw routing/bindings explicitly:
scripts/topic_config.py delete <topicIds>
Examples:
scripts/topic_config.py delete 7
scripts/topic_config.py delete 7,58,67
If Telegram deletion fails or cannot be verified, say the task is blocked/partial and do not claim the topic was deleted just because config was edited.
Cleanup workflow
There is no automatic cleanup command. Cleanup is a human-confirmed workflow:
- Run
scripts/topic_config.py check. - Inspect
missingInTelegram. - Show the user the exact stale topic ids and names that would be removed from OpenClaw config.
- Ask for explicit confirmation before any config edit.
- Only after confirmation, run
scripts/topic_config.py delete <topicIds>.
Do not delete topic 1. If check reports topic 1 under protectedGeneralTopicNotTouched, treat that as a probe/config oddity, not as cleanup input.
If check reports probeErrorsNotTouched, do not edit config from that result; investigate the Telegram/API error first.
delete/removedeletes non-General configured topics from Telegram first via Bot APIdeleteForumTopic; only after Telegram reports success or already-missing does it remove the topic route/bindings fromopenclaw.json. If Telegram deletion fails, config must remain untouched and the result must saytelegram_delete_failed.
OpenCode / oh-my-opencode agent selection
For coding ACP topics in this setup, the ACP harness id remains opencode; do not change the OpenClaw agentId to sisyphus. sisyphus is an internal opencode/oh-my-opencode agent.
Do not set the acpx command to opencode --agent=sisyphus acp: current opencode exposes --agent for normal/run/TUI flows, but opencode acp has its own option parser and does not accept that flag. Keep the ACP command override as:
{
"plugins": {
"entries": {
"acpx": {
"config": {
"agents": {
"opencode": {
"command": "env OPENCODE_DEFAULT_AGENT=sisyphus opencode acp"
}
}
}
}
}
}
}
Agent selection for ACP should be forced with the environment variable consumed by oh-my-opencode runtime resolution: OPENCODE_DEFAULT_AGENT=sisyphus. Keep opencode.json default_agent and oh-my-opencode default_run_agent as sisyphus too, but do not rely on CLI --agent for ACP.