| name | bot-setup |
| description | Install, configure, run, and operate the public Claude/Codex Telegram bot.
Use when a user asks to set up the bot, configure autostart, explain commands,
troubleshoot runtime issues, or choose language/engine/topic settings.
|
Bot Setup
This skill is the operator playbook for the public Telegram bot. It must stay
generic and public-safe: no real tokens, private paths, private IDs, or personal
deployment assumptions.
First Ask
Before changing files, ask the user:
- Which bot UI language: English (
en) or Russian (ru)?
- Which engine should be the default for project topics: Claude Code or Codex?
- Should the bot run as a foreground dev process or as a systemd service with
autostart and restart-on-failure?
- Private chat only, or a Telegram supergroup with forum topics?
If the user asked for a full setup and does not answer, choose conservative
defaults: BOT_LANG=en, default engine claude, systemd for a server, and
private chat first.
Requirements
Verify these before running the bot:
- Python 3.12 or newer.
uv installed and available on PATH.
- Telegram bot token from
@BotFather.
- The user's Telegram numeric user ID from
@userinfobot.
- Claude Code and/or Codex CLI installed on the same machine. The bot can work
with either one installed. It prefers Claude Code by default, but if the
configured topic engine is missing and the other engine is installed, it
switches the topic to the available engine.
tmux if the user wants persistent TUI sessions.
- Optional: Deepgram API key for voice transcription.
Useful checks:
python3 --version
uv --version
command -v claude || true
command -v codex || true
command -v tmux || true
Install
From the repository root:
uv sync
cp .env.example .env
cp topic_config.example.json topic_config.json
Edit .env. Required values:
TELEGRAM_BOT_TOKEN: token from @BotFather.
ALLOWED_USER_IDS: JSON array with the user's Telegram numeric ID.
BOT_LANG: en or ru.
PROJECT_ROOT: usually ..
DEFAULT_CWD: usually . for the public bot.
FILE_CACHE_DIR: usually ./data.
TOPIC_CONFIG_PATH: usually ./topic_config.json.
TMUX_SESSIONS_DIR: usually ./tmux_sessions.
CC_MAX_TURNS: default turn limit for Claude Code.
CC_INACTIVITY_KILL_SEC: inactivity timeout before killing a stuck process.
Set BOT_LANG=ru for Russian UI. The language is read at process startup, so
restart the bot after changing it.
For voice transcription, create a Deepgram account, generate an API key, set it
as DEEPGRAM_API_KEY in .env, and restart the bot. Leave it empty to disable
voice messages.
Foreground Run
Use this for local testing:
uv run telegram-bot
Open Telegram and send /start.
Telegram Forum Setup
Private chat works for simple use. For project workflows, use a Telegram
supergroup with forum topics:
- Create a bot with
@BotFather and copy its token into .env.
- Create a Telegram group or supergroup and enable forum topics in the group
settings.
- Add the bot to the group as an admin with rights to read messages, send
messages, manage topics, and send media/documents.
- Create topics manually in Telegram, or ask the local agent to use the
topic-setup skill to create/configure one through the Telegram Bot API.
When a new forum topic appears, the running bot auto-registers it in
topic_config.json with generic defaults: mode=free, cwd=null,
mcp_config=null, and no explicit engine. Runtime prefers claude; if Claude
Code is missing but Codex is installed, it starts with Codex and persists
engine=codex for that topic. If neither CLI exists, the bot still starts and
tells the user to install Claude Code or Codex.
Systemd Autostart
Use systemd on a Linux server when the bot should start on boot and restart if
it crashes.
Create /etc/systemd/system/telegram-bot.service:
[Unit]
Description=Claude/Codex Telegram Bot
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=REPLACE_WITH_LINUX_USER
WorkingDirectory=REPLACE_WITH_ABSOLUTE_REPO_PATH
EnvironmentFile=REPLACE_WITH_ABSOLUTE_REPO_PATH/.env
ExecStart=REPLACE_WITH_UV_PATH run telegram-bot
Restart=on-failure
RestartSec=5
StartLimitBurst=5
StartLimitIntervalSec=60
TimeoutStopSec=15
KillMode=process
NoNewPrivileges=true
ProtectKernelTunables=true
ProtectKernelModules=true
ProtectControlGroups=true
StandardOutput=journal
StandardError=journal
SyslogIdentifier=telegram-bot
[Install]
WantedBy=multi-user.target
Install it with real values:
APP_DIR="$(pwd)"
UV_BIN="$(command -v uv)"
USER_NAME="$(whoami)"
tmp_unit="$(mktemp)"
sed \
-e "s#REPLACE_WITH_LINUX_USER#${USER_NAME}#g" \
-e "s#REPLACE_WITH_ABSOLUTE_REPO_PATH#${APP_DIR}#g" \
-e "s#REPLACE_WITH_UV_PATH#${UV_BIN}#g" \
docs/systemd/telegram-bot.service.template >"${tmp_unit}"
sudo install -m 0644 "${tmp_unit}" /etc/systemd/system/telegram-bot.service
rm -f "${tmp_unit}"
If no template file exists, write the unit manually from the example above.
Then run:
sudo systemctl daemon-reload
sudo systemctl enable telegram-bot
sudo systemctl start telegram-bot
sudo systemctl status telegram-bot
journalctl -u telegram-bot -f
If the bot dies, Restart=on-failure starts it again after five seconds. If it
crashes repeatedly more than five times in sixty seconds, systemd stops retrying
until the operator fixes the cause and runs sudo systemctl reset-failed telegram-bot && sudo systemctl start telegram-bot.
KillMode=process lets tmux sessions survive a bot restart; the bot can restore
or resume them on startup.
Topic Config
Private chat works without custom topic config. For supergroup forums, each
topic can have its own runtime:
{
"topics": {
"42": {
"name": "My Project",
"type": "project",
"mode": "free",
"cwd": "/absolute/path/to/project",
"mcp_config": "/absolute/path/to/project/.mcp.json",
"stream_mode": "live",
"exec_mode": "tmux",
"engine": "codex",
"model": null
}
}
}
Fields:
type: assistant for generic chats, project for project-bound topics.
mode: public prompt mode. Use free as the standard project/general prompt.
The bundled task mode is only an example of a second prompt mode; users can
replace it with their own prompt file and topic mode if they want a different
workflow.
Both public prompt modes have the same generic bot MCP send-tool whitelist:
send_message, send_image, and send_document.
cwd: absolute working directory for the agent; null uses DEFAULT_CWD.
mcp_config: absolute MCP config path; null uses the generated bot MCP config.
stream_mode: verbose, live, or minimal.
exec_mode: subprocess for one-off assistant tasks where the user does
not need a persistent agent process, or tmux for full development sessions
with persistent context, TUI snapshots, /resume, and /tui.
engine: claude or codex.
model: optional provider model override, or null.
For creating or wiring forum topics, use the topic-setup skill in this repo.
topic-setup can create a Telegram forum topic when the bot token is available
and the bot is an admin with topic rights, then update topic_config.json with
the chosen cwd, engine, execution mode, stream mode, and optional model.
Do not document extra public prompt modes unless the corresponding public prompt
files are intentionally added in the same release.
Commands
/start: show the basic keyboard and verify the bot responds.
/new: reset the current topic session. In tmux mode, clears logical context
while keeping the tmux session alive.
/clear: alias for /new.
/cancel: cancel current processing. Use before changing mode if work is in
progress.
/mode: choose execution transport. regular/subprocess is best for
one-off assistant tasks where a persistent agent process is unnecessary;
tmux is best for full development work, persistent context, TUI snapshots,
/resume, and /tui.
/engine: choose Claude Code or Codex for the current forum topic. It resets
the active session when switching.
/stream: choose progress delivery. verbose sends many event messages,
live edits one progress buffer, minimal focuses on final answers.
/resume: in tmux mode, pick a saved Claude/Codex session for the topic cwd.
/tui: show a current tmux TUI snapshot with controls.
/tail: alias for /tui.
/kill: stop the active tmux session and free resources.
When unsure: use /mode → regular for short requests, /mode → tmux for real
coding tasks, /stream → live for daily use, and /kill when an old tmux
session is no longer needed.
Smoke Checks
Run:
uv run ruff check .
uv run ruff format --check .
uv run mypy src/ mcp-servers/bot/server.py
uv run pytest
PYTHONDONTWRITEBYTECODE=1 uv run python -c "import telegram_bot; import telegram_bot.__main__; print('ok')"
Runtime checks:
- Send
/start in Telegram.
- Send a short text message.
- If using forum topics, create a project topic, verify it appears in
topic_config.json, and check that the selected engine matches an installed
CLI.
- Ask the bot in that topic to help configure the topic, or run the local agent
with
topic-setup.
- If using systemd, restart it and check
journalctl -u telegram-bot -f.
Troubleshooting
- Bot does not answer: check
TELEGRAM_BOT_TOKEN, ALLOWED_USER_IDS, service
logs, and network access.
- Russian/English text did not change: set
BOT_LANG=en or BOT_LANG=ru and
restart the process.
- Claude or Codex not found: install at least one CLI for the same Linux user
that runs systemd, use a PATH where systemd can find it, then restart the
bot. If both are installed, topics prefer Claude Code unless configured
otherwise.
- Voice messages do not transcribe: create a Deepgram API key, set
DEEPGRAM_API_KEY in .env, and restart.
/mode, /engine, /stream, /resume do nothing in private chat: these are
forum-topic settings.
/resume unavailable: switch the topic to tmux mode and start a session.
- Tmux does not start: install
tmux, check resource limits, and inspect
service logs.
- Agent cannot send files/messages through MCP: verify
mcp-servers/bot/start.sh
exists, .mcp.bot.json generation is not blocked, and runtime env contains
bot token/chat/thread values.