Yuyao Huang (Sam) ed70588d95 docs: 添加飞书 Bot 开发指南文档
添加详细的飞书 Bot 开发指南文档,涵盖 SDK 初始化、消息收发、文件上传、WebSocket 长连接等实战经验
2026-03-29 19:59:31 +08:00

PhoneWork

Feishu bot that lets users control Claude Code CLI from their phone.

Architecture

PhoneWork uses a Router + Host Client architecture that supports both single-machine and multi-host deployments:

┌─────────────────┐         ┌──────────┐  WebSocket   ┌────────────────────────────────────┐
│  Feishu App     │         │  Feishu  │◄────────────►│          Router (public VPS)       │
│  (User's Phone) │◄───────►│  Cloud   │              │  - Feishu event handler            │
└─────────────────┘         └──────────┘              │  - Router LLM (routing only)       │
                                                      │  - Node registry + active node map │
                                                      └───────────┬────────────────────────┘
                                                                  │ WebSocket (host clients connect in)
                                                      ┌───────────┴────────────────────────┐
                                                      │                                    │
                                           ┌──────────▼──────────┐           ┌────────────▼────────┐
                                           │   Host Client A     │           │   Host Client B     │
                                           │   (home-pc)         │           │   (work-server)     │
                                           │  - Mailboy LLM      │           │  - Mailboy LLM      │
                                           │  - CC sessions      │           │  - CC sessions      │
                                           │  - Shell / files    │           │  - Shell / files    │
                                           └─────────────────────┘           └─────────────────────┘

Key design decisions:

  • Host clients connect TO the router (outbound WebSocket) — NAT-transparent
  • A user can be registered on multiple nodes simultaneously
  • The router LLM decides which node to route each message to
  • The node mailboy LLM handles the full orchestration loop
  • Each node maintains its own conversation history per user

Deployment modes:

  • Standalone (python standalone.py): Runs router + host client at localhost. Same architecture, simpler setup for single-machine use.
  • Multi-host: Router on a public VPS, host clients behind NAT on different machines.

Components:

Module Purpose
standalone.py Single-process entry point: runs router + host client together
router/main.py FastAPI app factory, mounts /ws/node endpoint, can be run directly
shared/protocol.py Wire protocol for router-host communication
router/nodes.py Node registry, connection management, user-to-node mapping
router/ws.py WebSocket endpoint for host clients, heartbeat, message routing
router/rpc.py Request correlation with asyncio.Future, timeout handling
router/routing_agent.py Single-shot routing LLM to decide which node handles each message
host_client/main.py WebSocket client connecting to router, message handling, reconnection
host_client/config.py Host client configuration loader
bot/handler.py Receives Feishu events via long-connection WebSocket
bot/feishu.py Sends text/file replies back to Feishu
bot/commands.py Slash command handler (/new, /status, /shell, /remind, /tasks, /nodes, /node)
orchestrator/agent.py LangChain agent with per-user history + direct/smart mode + direct Q&A
orchestrator/tools.py Tools: session management, shell, file ops, web search, scheduler, task status
agent/manager.py Session registry with persistence, idle timeout, and auto-background tasks
agent/pty_process.py Runs claude -p headlessly, manages session continuity via --resume
agent/task_runner.py Background task runner with Feishu notifications
agent/scheduler.py Reminder scheduler with persistence
agent/audit.py Audit log of all interactions

Flow: User message → Feishu WebSocket → Handler → (passthrough or LLM) → Session Manager → claude -p → Response back to Feishu


Feishu App Setup

1. Create App

Go to Feishu Open Platform → Create App → Custom App.

Record the App ID and App Secret from the Credentials page.

2. Enable Bot Capability

App Features → Bot → Enable.

3. Subscribe to Events (Long-connection mode)

Event Subscriptions → Request URL tab:

  • Switch to "Use long connection to receive events" (长连接接收事件)
  • No public URL required

Add event subscription:

Event Event Type
Receive messages im.message.receive_v1

4. Required Permissions (API Scopes)

Go to Permissions & Scopes and add the following:

Permission API Scope Used For
Read private messages sent to the bot im:message (read) Receiving user messages via WebSocket
Send messages im:message:send_as_bot Sending text replies
Upload files im:resource Uploading files before sending
Send messages in private chats im:message (write) Sending file messages

Minimal scope list to request:

im:message
im:message:send_as_bot
im:resource

Note: im:resource covers both file upload (im.v1.file.create) and sending file-type messages. Without it, send_file() will fail with a permission error.

5. Publish App

After adding all permissions:

  1. Version Management → Create a new version → Submit for review (or self-publish if in the same org)
  2. Install the app to your workspace

Configuration

Copy and fill in credentials:

cp keyring.example.yaml keyring.yaml

keyring.yaml fields:

FEISHU_APP_ID: cli_xxxxxxxxxxxxxxxx
FEISHU_APP_SECRET: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

OPENAI_BASE_URL: https://open.bigmodel.cn/api/paas/v4/
OPENAI_API_KEY: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
OPENAI_MODEL: glm-4.7

# Server configuration
# Only used in router mode (python -m router.main) or standalone mode (python standalone.py)
# Default: 8000
PORT: 8000

# Root directory for all project sessions (absolute path)
# Only used in standalone mode (python standalone.py)
# In router mode (python -m router.main), this field is ignored
WORKING_DIR: C:/Users/yourname/projects

# Allowlist of Feishu open_ids that may use the bot.
# Leave empty to allow all users.
ALLOWED_OPEN_IDS:
  - ou_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

# Optional: 秘塔AI Search API key for web search functionality
# Get your key at: https://metaso.cn/search-api/api-keys
METASO_API_KEY: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

# Optional: Multi-host mode configuration
# Set ROUTER_SECRET for authentication between router and host clients
ROUTER_SECRET: your-shared-secret-for-router-host-auth

Host Client Configuration (for multi-host mode)

Copy and fill in credentials:

cp host_config.example.yaml host_config.yaml

Create host_config.yaml on each host client machine:

NODE_ID: home-pc
DISPLAY_NAME: Home PC
ROUTER_URL: ws://192.168.1.100:8000/ws/node
ROUTER_SECRET: <shared_secret>

OPENAI_BASE_URL: https://open.bigmodel.cn/api/paas/v4/
OPENAI_API_KEY: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
OPENAI_MODEL: glm-4.7

WORKING_DIR: C:/Users/me/projects
METASO_API_KEY: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

# Which Feishu open_ids this node serves
SERVES_USERS:
  - ou_abc123def456

Determining ROUTER_URL

ROUTER_URL is the WebSocket address of the machine running the router (python main.py).

Scenario Value
Router and host client on the same LAN ws://192.168.x.x:8000/ws/node
Router on a public VPS (no TLS) ws://your-server-ip:8000/ws/node
Router behind a reverse proxy with TLS wss://yourdomain.com/ws/node

To find the router machine's LAN IP on Windows: ipconfig → look for IPv4 Address under your active adapter.

The router binds to 0.0.0.0:8000, so any IP or hostname that reaches that machine on port 8000 will work.

Determining ROUTER_SECRET

ROUTER_SECRET is a shared secret that authenticates host client connections. Generate it once on any machine:

python -c "import secrets; print(secrets.token_hex(32))"

Copy the output. Set the same value in:

  • keyring.yaml on the router machine (under ROUTER_SECRET)
  • host_config.yaml on every host client machine (under ROUTER_SECRET)

If the secrets don't match, the router will reject the connection with code 4001.

In standalone mode (python standalone.py), the secret is auto-generated at startup and never needs to be configured.


Installation & Run

Requirements: Python 3.11+, Claude Code CLI installed and authenticated.

python -m venv .venv
source .venv/Scripts/activate   # Windows
# source .venv/bin/activate     # Linux/macOS

pip install -r requirements.txt

Standalone mode (single machine)

Runs router + host client in one process. This is the normal setup for personal use.

cp keyring.example.yaml keyring.yaml
# Fill in keyring.yaml, then:
python standalone.py

Multi-host mode

Router (public VPS or any reachable machine — runs the Feishu bot):

# keyring.yaml must have ROUTER_SECRET set
python -m router.main

Host client (your dev machine behind NAT — runs Claude Code):

# Fill in host_config.yaml with ROUTER_URL and ROUTER_SECRET, then:
python -m host_client.main

Generate a shared secret for ROUTER_SECRET:

python -c "import secrets; print(secrets.token_hex(32))"

Set the same value in keyring.yaml on the router and host_config.yaml on each host client.

Health check

GET /health

Bot Commands

Command Description
/new <dir> [msg] Create a new Claude Code session in <dir>
/new <dir> [msg] --timeout N Create with custom CC timeout (seconds)
/new <dir> [msg] --idle N Create with custom idle timeout (seconds)
/status Show your sessions and current mode
/switch <n> Switch active session to number <n> from /status
/close [n] Close active session (or session <n>)
/direct Direct mode: messages go straight to Claude Code (no LLM overhead)
/smart Smart mode: messages go through LLM for intelligent routing (default)
/shell <cmd> Run a shell command directly (bypasses LLM)
/remind <time> <msg> Set a reminder (e.g., /remind 10m check build)
/tasks List background tasks with status
/nodes List connected host nodes (multi-host mode)
/node <name> Switch active node (multi-host mode)
/help Show command reference

Message Routing Modes

Smart mode (default): Messages are analyzed by the LLM, which decides whether to create a new session, send to an existing one, or ask for clarification. Useful when you want the bot to understand natural language requests.

Direct mode: Messages go straight to the active Claude Code session, bypassing the LLM. Faster and more predictable, but requires an active session. Use /direct to enable.

Claude Code Commands

Claude Code slash commands (like /help, /clear, /compact, /cost) are passed through to Claude Code when you have an active session. Bot commands (/new, /status, /switch, etc.) are handled by the bot first.


Features

Prototype Consolidation (Milestone 1)

Core Reliability

  • Message splitting - Long responses automatically split into multiple messages instead of getting cut off
  • Concurrent handling - Multiple users can message the bot simultaneously without conflicts
  • Session persistence - Active sessions survive server restarts (saved to disk)
  • Direct mode - Messages go straight to Claude Code, skipping the LLM for faster responses

Better Interaction

  • Slash commands - Direct control via /new, /status, /switch, /close, /direct, /smart
  • Multi-session switching - Multiple projects open simultaneously, switch between them
  • Interactive cards - Session status displayed in Feishu message cards

Operational Quality

  • Health checks - /health endpoint shows WebSocket status and can test Claude Code connectivity
  • Auto-reconnection - WebSocket automatically reconnects if the connection drops
  • Configurable timeouts - Each session can have custom idle and execution timeout settings
  • Audit logging - All conversations logged to files for debugging and accountability

Security

  • User allowlist - Configure which Feishu users are allowed to use the bot
  • Session isolation - Each user can only see and access their own sessions
  • Path sandboxing - Sessions can only run inside the allowed working directory, blocking path traversal attacks

Versatile Assistant (Milestone 2)

Direct Q&A

  • Ask general knowledge questions without creating a Claude Code session
  • The LLM answers directly using its own knowledge (e.g., "what is a Python generator?")
  • Automatic detection of question-like messages

Shell Access

  • Execute shell commands remotely via /shell or through the LLM
  • Safety guards block destructive commands (rm -rf /, sudo rm, mkfs, etc.)
  • Configurable timeout (max 120 seconds)

File Operations

  • Read files - View file content with line numbers
  • Write files - Create or append to files
  • List directories - Browse project structure
  • Search content - Grep-like search across text files
  • Send files - Deliver files directly to Feishu chat

Background Tasks

  • Long-running tasks (timeout > 60s) automatically run in background
  • Immediate acknowledgment with task ID
  • Feishu notification on completion
  • Track task status with /tasks command
  • Search the web via 秘塔AI Search (requires METASO_API_KEY)
  • Fetch and extract content from URLs
  • Ask questions with RAG-powered answers
  • Supports multiple scopes: webpage, paper, document, video, podcast

Scheduling & Reminders

  • Set one-time reminders: /remind 10m check the build
  • Schedule recurring reminders
  • Notifications delivered to Feishu
  • Persistent across server restarts

Multi-Host Architecture (Milestone 3)

Deployment Options

Single-Machine Mode:

python standalone.py

Runs both router and host client in one process. Identical UX to pre-M3 setup.

Router Mode (Public VPS):

# Set ROUTER_SECRET in keyring.yaml
python -m router.main

Runs only the router: Feishu handler + routing LLM + node registry.

Host Client Mode (Behind NAT):

# Create host_config.yaml with ROUTER_URL and ROUTER_SECRET
python -m host_client.main

Connects to router via WebSocket, runs full mailboy stack locally.

Node Management

  • /nodes — View all connected host nodes with status
  • /node <name> — Switch active node for your user
  • Automatic routing: LLM decides which node handles each message
  • Health monitoring: Router tracks node heartbeats
  • Reconnection: Host clients auto-reconnect on disconnect

Security

  • Shared secret authentication between router and host clients
  • User isolation: Each node only serves configured users
  • Path sandboxing: Sessions restricted to WORKING_DIR
S
Description
No description provided
Readme
685 KiB
Languages
Python 100%