"Use Herdres to operate the Herdr-to-Telegram bridge: install and configure it, set up per-agent forum topics, send/interrupt/queue messages to agent panes, read status and reports, manage child bots, drive the macOS cockpit, and run maintenance like cleanup-duplicates. Use when a user wants to control or set up Herdr agents over Telegram. This is herdres (the Telegram bridge), NOT herdr (the terminal multiplexer)."
Resources
27Install
npx skillscat add luminexord/herdres Install via the SkillsCat registry.
herdres — operator skill
This root SKILL.md is a self-contained, single-file entrypoint you can install on its own (drop it at ~/.codex/skills/herdres/SKILL.md or ~/.claude/skills/herdres/SKILL.md). The canonical package — this file plus deeper reference docs references/{SETUP,COMMANDS,TOPICS,TURN_FEED,MANAGED_BOTS,COCKPIT,SAFETY}.md — lives at skills/herdres/ in the luminexord/herdres repo. Read those for depth when available; everything needed to operate herdres safely is inline below.
Not
herdr. This skill operates herdres, the Herdr↔Telegram bridge — unrelated to theherdrskill (the terminal multiplexer,HERDR_ENV=1). Do not substitute one for the other.
herdres mirrors each running Herdr agent into a Telegram forum supergroup: every pane (or space) gets its own topic, pane output streams in, and your replies route back to the right pane. this skill lets you install and configure that bridge, pick per-agent vs per-space topics, send/interrupt/queue instructions, read reports and decisions, manage per-agent child bots, drive the macOS cockpit, and run maintenance — all fail-closed.
before doing anything, confirm ~/.config/herdres/herdres.env exists and herdres resolves on PATH (or ~/.local/bin/herdres). if it is not installed yet, go to Quick install. if it is, go to Before acting.
Quick install
the headline path. do not skip preflight, do not write Telegram state until verify passes, and you MUST NOT invent or scavenge credentials — the bot token, chat ID, and allowed-user IDs come from the user.
preflight. detect the OS: Linux uses systemd (
systemctl --user), macOS uses launchd (no user systemd). checkpython3 --versionis >= 3.11. confirm Herdr is running (herdr --version;herdrmust be onPATHor setHERDR_BIN); 0.7.0+ is recommended — older herdr works in degraded mode (timer-only, no instant plugin trigger; see step 5). if~/.config/herdres/herdres.envalready exists, do not clobber it — edit it and skip the installer's copy step.guided Telegram setup — you MUST pause and ask the user. the bot token, chat ID, and allowed-user IDs are user-supplied secrets: you MUST NOT invent them or copy them from another app's config (e.g. an existing Hermes bot token) without explicit approval — reusing a token another process already long-polls breaks the one-
getUpdates-consumer rule (see Safety rules). Always prefer a dedicated bot. if you cannot ask the user, stop and report what is needed rather than guessing. walk the user through these steps and validate what they paste back:- a. message @BotFather, run
/newbot, copy the bot token →TELEGRAM_BOT_TOKEN. Validate: shape is<digits>:<base64-ish>, e.g.123456:ABC-.... Then in @BotFather set the bot's Group Privacy to OFF (/setprivacy→ pick the bot → Disable) — otherwise it only sees/commandsand mentions, so plain-text topic replies won't reach panes and the chat ID is hard to fetch. - b. create a group, open Group Settings, and turn on Topics (this makes it a forum supergroup). herdres refuses any chat that is not a forum-enabled supergroup.
- c. add the bot to the group and promote it to Administrator with Manage Topics — grant both at once (otherwise preflight fails closed twice: once for admin, once for
can_manage_topics). - d. get the supergroup chat ID →
HERDR_TELEGRAM_TOPICS_CHAT_ID. Validate: it is negative and starts with-100…. (Easiest: add @RawDataBot or @getidsbot briefly, then remove it.) - e. get your own user ID (a positive integer) → first entry of
TELEGRAM_ALLOWED_USERS. Validate: numeric, positive.
- a. message @BotFather, run
run the installer from the repo checkout: Linux
./install-user.sh; macOS./install-macos.sh. This installs theherdresCLI, the gateway, the env file (copied from.env.example, never clobbering an existing one), the Herdr plugin manifest, and the service units / launchd agents.- the CLI lands at
~/.local/bin/herdresand the installer does not editPATH. ifherdresis "command not found", addexport PATH="$HOME/.local/bin:$PATH"to your shell profile, or call it as~/.local/bin/herdres. the service and plugin use absolute paths, so this only affects you typingherdres.
- the CLI lands at
write the three required env vars in
~/.config/herdres/herdres.env. Fastest and safest: runherdres setup— it prompts for the token (no echo), chat ID, and allowed users, validates each, runs preflight, then writes the file at mode0600. It refuses unattended runs without--bot-token/--chat-id/--allowed-users, and never silently reuses the Hermes token (it demands--reuse-hermes-tokenor a typedreuse). If you write the file by hand instead:TELEGRAM_BOT_TOKEN=123456:ABC-yourBotToken HERDR_TELEGRAM_TOPICS_CHAT_ID=-1001234567890 TELEGRAM_ALLOWED_USERS=123456789the first allowed-user id is treated as the owner. everything else has safe defaults. strongly recommend setting
HERDR_TELEGRAM_TOPICS_PER_AGENT=1here too (one clean topic per pane — see Before acting).enable the service + link the plugin.
- Linux:
systemctl --user daemon-reload && systemctl --user enable --now herdres.timer - macOS:
launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/com.gaijinjoe.herdres.plist(plus the gateway and, if wanted, cockpit plists) - both:
herdr plugin link ~/.local/share/herdres/herdres-pluginthenherdres plugin-enable— needs herdr 0.7.0+. on older herdr, skip this (the timer still reconciles at its interval) and setHERDR_BINto the bundledherdr_turn_adapter.pyifherdr pane turnis missing.
- Linux:
verify (non-destructive first):
HERDR_TELEGRAM_TOPICS_DRY_RUN=1 herdres sync # preflight, no Telegram writes herdres sync # real run; a topic should appear herdres probe --thread-id <id> # optional: confirm rich delivery into a topica clean run prints a JSON result and, with Herdr panes up, topics appear in the supergroup. preflight surfaces config errors as fail-closed JSON (
CHAT_ID is required,must be a forum-enabled supergroup,bot is not an administrator,bot lacks can_manage_topics).handoff. open a pane topic and try
/help,/status, then/send hello. you are live.
Deeper install detail — service files, the standalone gateway, the turn-adapter fallback, state/lock locations — is in the packaged references/SETUP.md.
Before acting
- confirm config + service.
~/.config/herdres/herdres.envexists with the three required vars, and the timer/launchd agent is enabled (it is the slow repair path; keep it on even with plugin events). if anything is missing, go to Quick install. - identify the topic mode. read
HERDR_TELEGRAM_TOPICS_PER_AGENT:1= one topic per pane (recommended; unambiguous),0= one topic per space (multiple panes can share a thread). the flag is read at runtime by every entry point, so set it inherdres.env— the one file all contexts load. switching modes is a clean-slate reset of topic mappings. depth inreferences/TOPICS.md. - reply inside the pane thread. to control a pane, reply inside its topic — text routes to that exact pane with no
/sendprefix. in per-space mode a top-level message only routes when the topic has exactly one live pane (or you picked one with/agents); otherwise herdres fails closed (Reply inside a pane thread so I know which Herdr pane to control.).
Core operations
these are the highest-frequency commands, typed inside a pane's forum topic. an agent runs one turn at a time, so a command to a busy agent can only queue or interrupt — never inject mid-turn.
/send <text>— forward as the agent's next instruction; idle → submitted now, busy → queued for the turn boundary (never lost)./send! <text>(aliases/interrupt,/isend) — interrupt a running turn (Esc, wait for idle), then deliver; on an idle agent it just delivers./keys <keys>— send raw key names to the pane (e.g./keys ctrl-c,/keys escape enter)./status,/report— resend the latest clean report or pending question for this pane./raw [lines]— sanitized raw visible pane output (default 80, max 160) when the clean report is not enough./choices— resend the active decision prompt and its inline buttons./new <codex|claude|kimi|omp|devin>— split a new pane in this space and launch that agent./agents— in a per-space topic, pick which agent your messages address (sets a ~10-min active pane); repliesOnly one agent herein per-agent mode./voice shared|per_agent— switch this space's Telegram voice (single shared bot vs per-agent bots); per-space and reversible./debug— show the topic↔pane mapping (pane id, topic, route) for troubleshooting.- any other
/command(e.g./goal,/clear,/model) is forwarded to the agent CLI as-is. Long/multiline input is staged to an owner-only inbound file so the full text reaches the pane.
Full table, idle-vs-busy semantics, plain-text routing, and the inbound-file rule are in the packaged references/COMMANDS.md.
Topics, turn feed, managed bots, cockpit
Topics. Topic granularity is one env var. Per-agent (=1) gives each pane its own clean thread, status icon, and unambiguous reply target; per-space (=0) collapses a workspace into one thread (multiple agents share it, /agents picks which to address) and forces the multi-pane fail-closed rule. Topic status shows as a per-topic icon (⚡️ working, ☕️ idle, ✅ done, ❗️ blocked, ‼️ error, 🧠 idle-but-still-on-a-/goal). Backfill many topics with HERDR_TELEGRAM_TOPICS_MAX_CREATES=20 herdres sync. Depth: references/TOPICS.md.
Turn feed. HERDR_TELEGRAM_TOPICS_TURN_FEED=1 (default) renders only Herdr's structured last-turn (submitted instruction + final answer) via herdr pane turn <pane_id> --last --format json — no TUI chrome, spinners, or thinking leaks. It supports live streaming drafts and structured pending_decision buttons, and ships a herdr_turn_adapter.py fallback for builds without pane turn. When the turn is unavailable, herdres sends nothing (it never scrapes the terminal). Depth: references/TURN_FEED.md.
Managed bots / One Space, One Voice. By default a space speaks with one voice: a single manager bot posts for every agent, and you address a specific agent by replying to its message or with /agents. Per-agent bot identities (Herdr Codex, Herdr Claude, …) are an opt-in, per-space, reversible upgrade governed by HERDR_TELEGRAM_TOPICS_MANAGED_BOTS: its code default is 0, but the shipped .env.example sets =1, so a standard install has the feature on (with an offer card); set =0 for pure shared voice. /voice shared|per_agent is the per-space control; voice_mode persists across resets, and existing multibot deployments auto-migrate to per_agent. When on, the gateway runs one worker per token; add each child bot to the group. references/MANAGED_BOTS.md.
Cockpit (macOS only). A launchd + tailscale serve Mini App that mirrors the live herdr TUI (xterm.js, touch key bar) into Telegram — the hands-on companion to the ambient bot. Fail-closed on tailnet + Telegram initData for the owner id only. references/COCKPIT.md.
Maintenance
herdres sync— force one reconciliation pass (create/update topics, post pending reports). Driven by the timer; safe to run by hand. Non-blocking lock.herdres cleanup-duplicates— report legacy duplicate topics (same pane mapped twice), read-only. Then--deleteto remove them. Always inspect first; it never deletes a live topic, only a proven-dead closed-pane duplicate. Old topics from a mode flip are not touched — delete those by hand.herdres probe [--thread-id <id>]— send a throwaway rich message and delete it, to confirm wiring and bot permissions into a topic.
Safety rules
These are load-bearing and fail-closed. Honor them when operating on a user's behalf.
- One
getUpdatesconsumer per bot token (hard Telegram limit). Never run a Hermes poller andherdres-gatewayon the sameTELEGRAM_BOT_TOKEN; pick one inbound path. Outbound-onlysync/eventare always safe alongside it. The gateway runs exactly one worker per token (manager + each child), so managed bots do not violate this. - Multi-pane space topics fail closed. herdres routes only when the target pane is unambiguous. If it replies
Reply inside a pane thread…, do not retry the same way — reply inside the specific pane thread or use/send. - Never key-drive Claude multi-question / review wizards from Telegram. Only structured
pending_decisionbuttons and explicitHERDRES_CHOICESblocks are safe;pending_interactionand visible-TUI prompts stay read-only. For an unstructured choice, answer in the Herdr pane directly. - No send retries. Transient/network send failures are not re-fired (avoids duplicates). Do not tight-loop
herdres syncor re-post — the timer reconciles status, icons, and cards on the next tick.
Full rules — owner-only gate, state ownership, cleanup guarantees, preflight — are in the packaged references/SAFETY.md.
When unsure
- run
herdreswith no subcommand for usage, or/helpinside a pane topic for the pane command list. - run
herdres probe --thread-id <id>to test wiring, orHERDR_TELEGRAM_TOPICS_DRY_RUN=1 herdres syncto preflight with no Telegram writes. - read the packaged reference for the area in question:
references/{SETUP,COMMANDS,TOPICS,TURN_FEED,MANAGED_BOTS,COCKPIT,SAFETY}.mdin theluminexord/herdresrepo.