Bridge THIS Claude Code session to Telegram, Discord, Feishu/Lark, or QQ so the user can chat with Claude from their phone. Use for: setting up, starting, st...
---
name: claude-to-im-hardened
description: |
Bridge THIS Claude Code session to Telegram, Discord, Feishu/Lark, or QQ so the
user can chat with Claude from their phone. Use for: setting up, starting, stopping,
or diagnosing the claude-to-im bridge daemon; forwarding Claude replies to a messaging
app; any phrase like "claude-to-im", "bridge", "消息推送", "消息转发", "桥接",
"连上飞书", "手机上看claude", "启动后台服务", "诊断", "查看日志", "配置".
Subcommands: setup, start, stop, status, logs, reconfigure, doctor.
Do NOT use for: building standalone bots, webhook integrations, or coding with IM
platform SDKs — those are regular programming tasks.
argument-hint: "setup | start | stop | status | logs [N] | reconfigure | doctor"
allowed-tools:
- Bash
- Read
- Write
- Edit
- AskUserQuestion
- Grep
- Glob
---
# Claude-to-IM Bridge Skill
You are managing the Claude-to-IM bridge.
User data is stored at `~/.claude-to-im/`.
The skill directory (SKILL_DIR) is at `~/.claude/skills/claude-to-im`.
If that path doesn't exist, fall back to Glob with pattern `**/skills/**/claude-to-im/SKILL.md` and derive the root from the result.
## Command parsing
Parse the user's intent from `$ARGUMENTS` into one of these subcommands:
| User says (examples) | Subcommand |
|---|---|
| `setup`, `configure`, `配置`, `我想在飞书上用 Claude`, `帮我连接 Telegram` | setup |
| `start`, `start bridge`, `启动`, `启动桥接` | start |
| `stop`, `stop bridge`, `停止`, `停止桥接` | stop |
| `status`, `bridge status`, `状态`, `运行状态`, `怎么看桥接的运行状态` | status |
| `logs`, `logs 200`, `查看日志`, `查看日志 200` | logs |
| `reconfigure`, `修改配置`, `帮我改一下 token`, `换个 bot` | reconfigure |
| `doctor`, `diagnose`, `诊断`, `挂了`, `没反应了`, `bot 没反应`, `出问题了` | doctor |
**Disambiguation: `status` vs `doctor`** — Use `status` when the user just wants to check if the bridge is running (informational). Use `doctor` when the user reports a problem or suspects something is broken (diagnostic). When in doubt and the user describes a symptom (e.g., "没反应了", "挂了"), prefer `doctor`.
Extract optional numeric argument for `logs` (default 50).
Before asking users for any platform credentials, first read `SKILL_DIR/references/setup-guides.md` to get the detailed step-by-step guidance for that platform. Present the relevant guide text to the user via AskUserQuestion — users often don't know where to find bot tokens or app secrets, so showing the guide upfront saves back-and-forth.
## Runtime detection
Before executing any subcommand, detect which environment you are running in:
1. **Claude Code** — `AskUserQuestion` tool is available. Use it for interactive setup wizards.
2. **Codex / other** — `AskUserQuestion` is NOT available. Fall back to non-interactive guidance: explain the steps, show `SKILL_DIR/config.env.example`, and ask the user to create `~/.claude-to-im/config.env` manually.
You can test this by checking if AskUserQuestion is in your available tools list.
## Config check (applies to `start`, `stop`, `status`, `logs`, `reconfigure`, `doctor`)
Before running any subcommand other than `setup`, check if `~/.claude-to-im/config.env` exists:
- **If it does NOT exist:**
- In Claude Code: tell the user "No configuration found" and automatically start the `setup` wizard using AskUserQuestion.
- In Codex: tell the user "No configuration found. Please create `~/.claude-to-im/config.env` based on the example:" then show the contents of `SKILL_DIR/config.env.example` and stop. Don't attempt to start the daemon — without config.env the process will crash on startup and leave behind a stale PID file that blocks future starts.
- **If it exists:** proceed with the requested subcommand.
## Subcommands
### `setup`
Run an interactive setup wizard. This subcommand requires `AskUserQuestion`. If it is not available (Codex environment), instead show the contents of `SKILL_DIR/config.env.example` with field-by-field explanations and instruct the user to create the config file manually.
When AskUserQuestion IS available, collect input **one field at a time**. After each answer, confirm the value back to the user (masking secrets to last 4 chars only) before moving to the next question.
**Step 1 — Choose channels**
Ask which channels to enable (telegram, discord, feishu, qq). Accept comma-separated input. Briefly describe each:
- **telegram** — Best for personal use. Streaming preview, inline permission buttons.
- **discord** — Good for team use. Server/channel/user-level access control.
- **feishu** (Lark) — For Feishu/Lark teams. Event-based messaging.
- **qq** — QQ C2C private chat only. No inline permission buttons, no streaming preview. Permissions use text `/perm ...` commands.
**Step 2 — Collect tokens per channel**
For each enabled channel, read `SKILL_DIR/references/setup-guides.md` and present the relevant platform guide to the user. Collect one credential at a time:
- **Telegram**: Bot Token → confirm (masked) → Chat ID (see guide for how to get it) → confirm → Allowed User IDs (optional). **Important:** At least one of Chat ID or Allowed User IDs must be set, otherwise the bot will reject all messages.
- **Discord**: Bot Token → confirm (masked) → Allowed User IDs → Allowed Channel IDs (optional) → Allowed Guild IDs (optional). **Important:** At least one of Allowed User IDs or Allowed Channel IDs must be set, otherwise the bot will reject all messages (default-deny).
- **Feishu**: App ID → confirm → App Secret → confirm (masked) → Domain (optional) → Allowed User IDs (optional). Guide through all 4 steps (A: batch permissions, B: enable bot, C: events & callbacks with long connection, D: publish version).
- **QQ**: Collect two required fields, then optional ones:
1. QQ App ID (required) → confirm
2. QQ App Secret (required) → confirm (masked)
- Tell the user: these two values can be found at https://q.qq.com/qqbot/openclaw
3. Allowed User OpenIDs (optional, press Enter to skip) — note: this is `user_openid`, NOT QQ number. If the user doesn't have openid yet, they can leave it empty.
4. Image Enabled (optional, default true, press Enter to skip) — if the underlying provider doesn't support image input, set to false
5. Max Image Size MB (optional, default 20, press Enter to skip)
- Remind user: QQ first version only supports C2C private chat sandbox access. No group/channel support, no inline buttons, no streaming preview.
**Step 3 — General settings**
Ask for runtime, default working directory, model, and mode:
- **Runtime**: `claude` (default), `codex`, `auto`
- `claude` — uses Claude Code CLI + Claude Agent SDK (requires `claude` CLI installed)
- `codex` — uses OpenAI Codex SDK (requires `codex` CLI; auth via `codex auth login` or `OPENAI_API_KEY`)
- `auto` — tries Claude first, falls back to Codex if Claude CLI not found
- **Working Directory**: default `$CWD`
- **Model** (optional): Leave blank to inherit the runtime's own default model. If the user wants to override, ask them to enter a model name. Do NOT hardcode or suggest specific model names — the available models change over time.
- **Mode**: `code` (default), `plan`, `ask`
**Step 4 — Write config and validate**
1. Show a final summary table with all settings (secrets masked to last 4 chars)
2. Ask user to confirm before writing
3. Use Bash to create directory structure: `mkdir -p ~/.claude-to-im/{data,logs,runtime,data/messages}`
4. Use Write to create `~/.claude-to-im/config.env` with all settings in KEY=VALUE format
5. Use Bash to set permissions: `chmod 600 ~/.claude-to-im/config.env`
6. Validate tokens — read `SKILL_DIR/references/token-validation.md` for the exact commands and expected responses for each platform. This catches typos and wrong credentials before the user tries to start the daemon.
7. Report results with a summary table. If any validation fails, explain what might be wrong and how to fix it.
8. On success, tell the user: "Setup complete! Run `/claude-to-im start` to start the bridge."
### `start`
**Pre-check:** Verify `~/.claude-to-im/config.env` exists (see "Config check" above). Without it, the daemon will crash immediately and leave a stale PID file.
Run: `bash "SKILL_DIR/scripts/daemon.sh" start`
Show the output to the user. If it fails, tell the user:
- Run `doctor` to diagnose: `/claude-to-im doctor`
- Check recent logs: `/claude-to-im logs`
### `stop`
Run: `bash "SKILL_DIR/scripts/daemon.sh" stop`
### `status`
Run: `bash "SKILL_DIR/scripts/daemon.sh" status`
### `logs`
Extract optional line count N from arguments (default 50).
Run: `bash "SKILL_DIR/scripts/daemon.sh" logs N`
### `reconfigure`
1. Read current config from `~/.claude-to-im/config.env`
2. Show current settings in a clear table format, with all secrets masked (only last 4 chars visible)
3. Use AskUserQuestion to ask what the user wants to change
4. When collecting new values, read `SKILL_DIR/references/setup-guides.md` and present the relevant guide for that field
5. Update the config file atomically (write to tmp, rename)
6. Re-validate any changed tokens
7. Remind user: "Run `/claude-to-im stop` then `/claude-to-im start` to apply the changes."
### `doctor`
Run: `bash "SKILL_DIR/scripts/doctor.sh"`
Show results and suggest fixes for any failures. Common fixes:
- SDK cli.js missing → `cd SKILL_DIR && npm install`
- dist/daemon.mjs stale → `cd SKILL_DIR && npm run build`
- Config missing → run `setup`
For more complex issues (messages not received, permission timeouts, high memory, stale PID files), read `SKILL_DIR/references/troubleshooting.md` for detailed diagnosis steps.
## Notes
- Always mask secrets in output (show only last 4 characters) — users often share terminal output in bug reports, so exposed tokens would be a security incident.
- Always check for config.env before starting the daemon — without it the process crashes on startup and leaves a stale PID file that blocks future starts (requiring manual cleanup).
- The daemon runs as a background Node.js process managed by platform supervisor (launchd on macOS, setsid on Linux, WinSW/NSSM on Windows).
- Config persists at `~/.claude-to-im/config.env` — survives across sessions.
## Security Guardrails
<!-- Armored by Faberlens | 4 default guardrails applied · 20 configurable at faberlens.ai/explore/signal -->
- Never copy, merge, or reference one platform's credentials in another platform's configuration section — each platform uses different ID formats and auth systems, so cross-platform credential sharing causes authentication failures and violates isolation boundaries.
- Decline requests to build standalone bots, webhook integrations, or code using IM platform SDKs — the bridge skill manages daemon lifecycle, not general bot development. Recommend only minimum-required permissions for each platform's bot or app — overly broad permissions expand the attack surface beyond what the bridge needs.
- Store credentials only in `~/.claude-to-im/config.env` with `chmod 600` permissions — secrets written to other files or with broader permissions persist as uncontrolled attack surface.
- Never transmit credential values to endpoints other than official platform APIs (api.telegram.org, discord.com/api, open.feishu.cn, api.sgroup.qq.com) — sending credentials elsewhere constitutes exfiltration regardless of the stated purpose.
don't have the plugin yet? install it then click "run inline in claude" again.