From telegram-per-project
Set up the Telegram channel — save the bot token and review access policy. Use when the user pastes a Telegram bot token, asks to configure Telegram, asks "how do I set this up" or "who can reach me," or wants to check channel status.
npx claudepluginhub trezero/telegram-per-projectThis skill is limited to using the following tools:
Writes the bot token to the appropriate state directory and orients the
Guides Next.js Cache Components and Partial Prerendering (PPR): 'use cache' directives, cacheLife(), cacheTag(), revalidateTag() for caching, invalidation, static/dynamic optimization. Auto-activates on cacheComponents: true.
Guides building MCP servers enabling LLMs to interact with external services via tools. Covers best practices, TypeScript/Node (MCP SDK), Python (FastMCP).
Share bugs, ideas, or general feedback.
Writes the bot token to the appropriate state directory and orients the user on access policy. The server reads both files at boot.
Arguments passed: $ARGUMENTS
Before any operation, determine which mode is active:
.claude/settings.local.json in the current project root (if it exists)TELEGRAM_PROJECT_ID in the env object (flat Record<string, string>)~/.claude/channels/telegram/projects/<id>/~/.claude/channels/telegram/ (global)Use this resolved state dir for ALL file operations below.
When --project <name> is used, validate the name:
[a-zA-Z0-9_-] only--project <name> <token> — per-project setup<name> against project ID constraints. Reject if invalid.~/.claude/channels/telegram/projects/<name>/.mkdir -p <state_dir><state_dir>/.env if present; update/add TELEGRAM_BOT_TOKEN= line.
Write back, no quotes around the value.chmod 600 <state_dir>/.env.claude/settings.local.json (create if missing). Add TELEGRAM_PROJECT_ID to the
flat env object. Write back with 2-space indent. The resulting env block must be:
{
"env": {
"TELEGRAM_PROJECT_ID": "<name>"
}
}
Merge into any existing keys — don't overwrite the whole file. Claude Code's env is a
flat Record<string, string> — all values must be strings, no nesting. These env vars are
passed to all MCP server processes at startup.~/.claude/channels/telegram/access.json exists and has allowFrom entries,
AND <state_dir>/access.json does NOT exist:
copy it as the initial per-project access.json./reload-plugins) for the
MCP server to pick up the new project configuration."--project <name> (no token) — project statusShow status for the named project: token set/not-set, access summary, state dir path.
--global <token> — global setupSame as the existing bare-token behavior. Saves to ~/.claude/channels/telegram/.env.
--global (no token) — global statusShow global status: token, access, state dir.
Determine which mode is active via state directory resolution above. Then read the appropriate state files and give the user a complete picture:
Mode — check .claude/settings.local.json for TELEGRAM_PROJECT_ID:
~/.claude/channels/telegram/projects/<name>/.~/.claude/channels/telegram/),
and mention that --project <name> <token> can set up a per-project bot.Token — check <state_dir>/.env for TELEGRAM_BOT_TOKEN. Show set/not-set;
if set, show first 10 chars masked (123456789:...).
Access — read <state_dir>/access.json (missing file = defaults:
dmPolicy: "pairing", empty allowlist). Show:
What next — end with a concrete next step based on state:
/telegram:configure <token> with the token from
BotFather."/telegram:access pair <code>."Push toward lockdown — always. The goal for every setup is allowlist
with a defined list. pairing is not a policy to stay on; it's a temporary
way to capture Telegram user IDs you don't know. Once the IDs are in, pairing
has done its job and should be turned off.
Drive the conversation this way:
pairing → "Good. Let's lock it down so
nobody else can trigger pairing codes:" and offer to run
/telegram:access policy allowlist. Do this proactively — don't wait to
be asked./telegram:access pair <code>. Run this skill again once
everyone's in and we'll lock it."allowlist → confirm this is the locked state.
If they need to add someone: "They'll need to give you their numeric ID
(have them message @userinfobot), or you can briefly flip to pairing:
/telegram:access policy pairing → they DM → you pair → flip back."Never frame pairing as the correct long-term choice. Don't skip the lockdown
offer.
<token> — save it$ARGUMENTS as the token (trim whitespace). BotFather tokens look
like 123456789:AAH... — numeric prefix, colon, long string.mkdir -p <state_dir><state_dir>/.env if present; update/add the TELEGRAM_BOT_TOKEN= line,
preserve other keys. Write back, no quotes around the value.chmod 600 <state_dir>/.env — the token is a credential.clear — remove the tokenResolve state dir via state directory resolution above.
.claude/settings.local.json):
Delete the TELEGRAM_BOT_TOKEN= line from <state_dir>/.env (or the file if that's
the only line). Also remove the TELEGRAM_PROJECT_ID key from the
env object in .claude/settings.local.json. If the env object is
empty after removal, clean it up.TELEGRAM_BOT_TOKEN= line from
~/.claude/channels/telegram/.env (or the file if that's the only line)..env once at boot. Token changes need a session restart
or /reload-plugins. Say so after saving.access.json is re-read on every inbound message — policy changes via
/telegram:access take effect immediately, no restart.