Feishu
Feishu/Lark is an all-in-one collaboration platform where teams chat, share documents, manage calendars, and get work done together.
Status: production-ready for bot DMs + group chats. WebSocket is the default mode; webhook mode is optional.
Quick start
Section titled “Quick start”Run the channel setup wizard
Terminal window openclaw channels login --channel feishuChoose manual setup to paste an App ID and App Secret from Feishu Open Platform, or choose QR setup to create a bot automatically. If the domestic Feishu mobile app does not react to the QR code, rerun setup and choose manual setup.
After setup completes, restart the gateway to apply the changes
Terminal window openclaw gateway restart
Access control
Section titled “Access control”Direct messages
Section titled “Direct messages”Configure dmPolicy to control who can DM the bot:
"pairing"- unknown users receive a pairing code; approve via CLI"allowlist"- only users listed inallowFromcan chat (default: bot owner only)"open"- allow public DMs only whenallowFromincludes"*"; with restrictive entries, only matching users can chat"disabled"- disable all DMs
Approve a pairing request:
openclaw pairing list feishuopenclaw pairing approve feishu <CODE>Group chats
Section titled “Group chats”Group policy (channels.feishu.groupPolicy):
| Value | Behavior |
|---|---|
"open" | Respond to all messages in groups |
"allowlist" | Only respond to groups in groupAllowFrom or explicitly configured under groups.<chat_id> |
"disabled" | Disable all group messages; explicit groups.<chat_id> entries do not override this |
Default: allowlist
Mention requirement (channels.feishu.requireMention):
true- require @mention (default)false- respond without @mention- Per-group override:
channels.feishu.groups.<chat_id>.requireMention - Broadcast-only
@alland@_allare not treated as bot mentions. A message that mentions both@alland the bot directly still counts as a bot mention.
Group configuration examples
Section titled “Group configuration examples”Allow all groups, no @mention required
Section titled “Allow all groups, no @mention required”{ channels: { feishu: { groupPolicy: "open", }, },}Allow all groups, still require @mention
Section titled “Allow all groups, still require @mention”{ channels: { feishu: { groupPolicy: "open", requireMention: true, }, },}Allow specific groups only
Section titled “Allow specific groups only”{ channels: { feishu: { groupPolicy: "allowlist", // Group IDs look like: oc_xxx groupAllowFrom: ["oc_xxx", "oc_yyy"], }, },}In allowlist mode, you can also admit a group by adding an explicit groups.<chat_id> entry. Explicit entries do not override groupPolicy: "disabled". Wildcard defaults under groups.* configure matching groups, but they do not admit groups by themselves.
{ channels: { feishu: { groupPolicy: "allowlist", groups: { oc_xxx: { requireMention: false, }, }, }, },}Restrict senders within a group
Section titled “Restrict senders within a group”{ channels: { feishu: { groupPolicy: "allowlist", groupAllowFrom: ["oc_xxx"], groups: { oc_xxx: { // User open_ids look like: ou_xxx allowFrom: ["ou_user1", "ou_user2"], }, }, }, },}Get group/user IDs
Section titled “Get group/user IDs”Group IDs (chat_id, format: oc_xxx)
Section titled “Group IDs (chat_id, format: oc_xxx)”Open the group in Feishu/Lark, click the menu icon in the top-right corner, and go to Settings. The group ID (chat_id) is listed on the settings page.

User IDs (open_id, format: ou_xxx)
Section titled “User IDs (open_id, format: ou_xxx)”Start the gateway, send a DM to the bot, then check the logs:
openclaw logs --followLook for open_id in the log output. You can also check pending pairing requests:
openclaw pairing list feishuCommon commands
Section titled “Common commands”| Command | Description |
|---|---|
/status | Show bot status |
/reset | Reset the current session |
/model | Show or switch the AI model |
Troubleshooting
Section titled “Troubleshooting”Bot does not respond in group chats
Section titled “Bot does not respond in group chats”- Ensure the bot is added to the group
- Ensure you @mention the bot (required by default)
- Verify
groupPolicyis not"disabled" - Check logs:
openclaw logs --follow
Bot does not receive messages
Section titled “Bot does not receive messages”- Ensure the bot is published and approved in Feishu Open Platform / Lark Developer
- Ensure event subscription includes
im.message.receive_v1 - Ensure persistent connection (WebSocket) is selected
- Ensure all required permission scopes are granted
- Ensure the gateway is running:
openclaw gateway status - Check logs:
openclaw logs --follow
QR setup does not react in the Feishu mobile app
Section titled “QR setup does not react in the Feishu mobile app”- Rerun setup:
openclaw channels login --channel feishu - Choose manual setup
- In Feishu Open Platform, create a self-built app and copy its App ID and App Secret
- Paste those credentials into the setup wizard
App Secret leaked
Section titled “App Secret leaked”- Reset the App Secret in Feishu Open Platform / Lark Developer
- Update the value in your config
- Restart the gateway:
openclaw gateway restart
Advanced configuration
Section titled “Advanced configuration”Multiple accounts
Section titled “Multiple accounts”{ channels: { feishu: { defaultAccount: "main", accounts: { main: { appId: "cli_xxx", appSecret: "xxx", name: "Primary bot", tts: { providers: { openai: { voice: "shimmer" }, }, }, }, backup: { appId: "cli_yyy", appSecret: "yyy", name: "Backup bot", enabled: false, }, }, }, },}defaultAccount controls which account is used when outbound APIs do not specify an accountId.
accounts.<id>.tts uses the same shape as messages.tts and deep-merges over
global TTS config, so multi-bot Feishu setups can keep shared provider
credentials globally while overriding only voice, model, persona, or auto mode
per account.
Message limits
Section titled “Message limits”textChunkLimit- outbound text chunk size (default:2000chars)mediaMaxMb- media upload/download limit (default:30MB)
Streaming
Section titled “Streaming”Feishu/Lark supports streaming replies via interactive cards. When enabled, the bot updates the card in real time as it generates text.
{ channels: { feishu: { streaming: true, // enable streaming card output (default: true) blockStreaming: true, // opt into completed-block streaming }, },}Set streaming: false to send the complete reply in one message. blockStreaming is off by default; enable it only when you want completed assistant blocks flushed before the final reply.
Quota optimization
Section titled “Quota optimization”Reduce the number of Feishu/Lark API calls with two optional flags:
typingIndicator(defaulttrue): setfalseto skip typing reaction callsresolveSenderNames(defaulttrue): setfalseto skip sender profile lookups
{ channels: { feishu: { typingIndicator: false, resolveSenderNames: false, }, },}ACP sessions
Section titled “ACP sessions”Feishu/Lark supports ACP for DMs and group thread messages. Feishu/Lark ACP is text-command driven - there are no native slash-command menus, so use /acp ... messages directly in the conversation.
Persistent ACP binding
Section titled “Persistent ACP binding”{ agents: { list: [ { id: "codex", runtime: { type: "acp", acp: { agent: "codex", backend: "acpx", mode: "persistent", cwd: "/workspace/openclaw", }, }, }, ], }, bindings: [ { type: "acp", agentId: "codex", match: { channel: "feishu", accountId: "default", peer: { kind: "direct", id: "ou_1234567890" }, }, }, { type: "acp", agentId: "codex", match: { channel: "feishu", accountId: "default", peer: { kind: "group", id: "oc_group_chat:topic:om_topic_root" }, }, acp: { label: "codex-feishu-topic" }, }, ],}Spawn ACP from chat
Section titled “Spawn ACP from chat”In a Feishu/Lark DM or thread:
/acp spawn codex --thread here--thread here works for DMs and Feishu/Lark thread messages. Follow-up messages in the bound conversation route directly to that ACP session.
Multi-agent routing
Section titled “Multi-agent routing”Use bindings to route Feishu/Lark DMs or groups to different agents.
{ agents: { list: [ { id: "main" }, { id: "agent-a", workspace: "/home/user/agent-a" }, { id: "agent-b", workspace: "/home/user/agent-b" }, ], }, bindings: [ { agentId: "agent-a", match: { channel: "feishu", peer: { kind: "direct", id: "ou_xxx" }, }, }, { agentId: "agent-b", match: { channel: "feishu", peer: { kind: "group", id: "oc_zzz" }, }, }, ],}Routing fields:
match.channel:"feishu"match.peer.kind:"direct"(DM) or"group"(group chat)match.peer.id: user Open ID (ou_xxx) or group ID (oc_xxx)
See Get group/user IDs for lookup tips.
Per-user agent isolation (Dynamic Agent Creation)
Section titled “Per-user agent isolation (Dynamic Agent Creation)”Enable dynamicAgentCreation to automatically create isolated agent instances for each DM user. Each user gets their own:
- Independent workspace directory
- Separate
USER.md/SOUL.md/MEMORY.md - Private conversation history
- Isolated skills and state
This is essential for public bots where you want each user to have their own private AI assistant experience.
Quick setup
Section titled “Quick setup”{ channels: { feishu: { dmPolicy: "open", allowFrom: ["*"], dynamicAgentCreation: { enabled: true, workspaceTemplate: "~/.openclaw/workspace-{agentId}", agentDirTemplate: "~/.openclaw/agents/{agentId}/agent", }, }, }, session: { // Critical: makes each user's DM their "main session" // Automatically loads USER.md / SOUL.md / MEMORY.md // For stronger isolation, use "per-channel-peer" instead dmScope: "main", },}How it works
Section titled “How it works”When a new user sends their first DM:
- The channel generates a unique
agentId=feishu-{user_open_id} - Creates a new workspace at
workspaceTemplatepath - Registers the agent and creates a binding for this user
- The workspace helper ensures bootstrap files (
AGENTS.md,SOUL.md,USER.md, etc.) on first access - Routes all future messages from this user to their dedicated agent
Configuration options
Section titled “Configuration options”| Setting | Description | Default |
|---|---|---|
channels.feishu.dynamicAgentCreation.enabled | Enable automatic per-user agent creation | false |
channels.feishu.dynamicAgentCreation.workspaceTemplate | Path template for dynamic agent workspaces | ~/.openclaw/workspace-{agentId} |
channels.feishu.dynamicAgentCreation.agentDirTemplate | Agent directory name template | ~/.openclaw/agents/{agentId}/agent |
channels.feishu.dynamicAgentCreation.maxAgents | Maximum number of dynamic agents to create | unlimited |
Template variables:
{agentId}- the generated agent ID (e.g.,feishu-ou_xxxxxx){userId}- the sender’s Feishu open_id (e.g.,ou_xxxxxx)
Session scope
Section titled “Session scope”session.dmScope controls how direct messages are mapped to agent sessions. This is a global setting that affects all channels.
| Value | Behavior | Best for |
|---|---|---|
"main" | Each user’s DM maps to their agent’s main session | Single-user bots where you want USER.md / SOUL.md to auto-load |
"per-channel-peer" | Each (channel + user) combination gets a separate session | Public multi-user bots needing stronger isolation |
Tradeoff: Using "main" enables automatic bootstrap file loading (USER.md, SOUL.md, MEMORY.md), but means all DMs across all channels share the same session key pattern. For public multi-user bots where isolation matters more than bootstrap auto-loading, consider "per-channel-peer" and manage bootstrap files manually.
{ session: { // For single-user personal bots: enables auto bootstrap loading dmScope: "main",
// For public multi-user bots: stronger isolation // dmScope: "per-channel-peer", },}Typical multi-user deployment
Section titled “Typical multi-user deployment”{ channels: { feishu: { appId: "cli_xxx", appSecret: "xxx", dmPolicy: "open", allowFrom: ["*"], groupPolicy: "open", requireMention: true, dynamicAgentCreation: { enabled: true, workspaceTemplate: "~/.openclaw/workspace-{agentId}", agentDirTemplate: "~/.openclaw/agents/{agentId}/agent", }, }, }, session: { // Choose dmScope based on your isolation needs: // "main" for bootstrap auto-loading, "per-channel-peer" for stronger isolation dmScope: "main", }, bindings: [], // Empty - dynamic agents auto-bind}Verification
Section titled “Verification”Check gateway logs to confirm dynamic creation is working:
feishu: creating dynamic agent "feishu-ou_xxxxxx" for user ou_xxxxxxworkspace: /Users/you/.openclaw/workspace-feishu-ou_xxxxxxfeishu: dynamic agent created, new route: agent:feishu-ou_xxxxxx:mainList all created workspaces:
ls -la ~/.openclaw/workspace-*- Workspace isolation: Each user gets their own workspace directory and agent instance. Users cannot see each other’s conversation history or files within the normal messaging flow.
- Security boundary: This is a messaging-context isolation mechanism, not a hostile co-tenant security boundary. The agent process and host environment are shared.
bindingsshould be empty: Dynamic agents auto-register their own bindings- Upgrade path: Existing manual bindings continue to work alongside dynamic agents
session.dmScopeis global: This affects all channels, not just Feishu
Configuration reference
Section titled “Configuration reference”Full configuration: Gateway configuration
| Setting | Description | Default |
|---|---|---|
channels.feishu.enabled | Enable/disable the channel | true |
channels.feishu.domain | API domain (feishu or lark) | feishu |
channels.feishu.connectionMode | Event transport (websocket or webhook) | websocket |
channels.feishu.defaultAccount | Default account for outbound routing | default |
channels.feishu.verificationToken | Required for webhook mode | - |
channels.feishu.encryptKey | Required for webhook mode | - |
channels.feishu.webhookPath | Webhook route path | /feishu/events |
channels.feishu.webhookHost | Webhook bind host | 127.0.0.1 |
channels.feishu.webhookPort | Webhook bind port | 3000 |
channels.feishu.accounts.<id>.appId | App ID | - |
channels.feishu.accounts.<id>.appSecret | App Secret | - |
channels.feishu.accounts.<id>.domain | Per-account domain override | feishu |
channels.feishu.accounts.<id>.tts | Per-account TTS override | messages.tts |
channels.feishu.dmPolicy | DM policy | allowlist |
channels.feishu.allowFrom | DM allowlist (open_id list) | [BotOwnerId] |
channels.feishu.groupPolicy | Group policy | allowlist |
channels.feishu.groupAllowFrom | Group allowlist | - |
channels.feishu.requireMention | Require @mention in groups | true |
channels.feishu.groups.<chat_id>.requireMention | Per-group @mention override; explicit IDs also admit the group in allowlist mode | inherited |
channels.feishu.groups.<chat_id>.enabled | Enable/disable a specific group | true |
channels.feishu.dynamicAgentCreation.enabled | Enable automatic per-user agent creation | false |
channels.feishu.dynamicAgentCreation.workspaceTemplate | Path template for dynamic agent workspaces | ~/.openclaw/workspace-{agentId} |
channels.feishu.dynamicAgentCreation.agentDirTemplate | Agent directory name template | ~/.openclaw/agents/{agentId}/agent |
channels.feishu.dynamicAgentCreation.maxAgents | Maximum number of dynamic agents to create | unlimited |
channels.feishu.textChunkLimit | Message chunk size | 2000 |
channels.feishu.mediaMaxMb | Media size limit | 30 |
channels.feishu.streaming | Streaming card output | true |
channels.feishu.blockStreaming | Completed-block reply streaming | false |
channels.feishu.typingIndicator | Send typing reactions | true |
channels.feishu.resolveSenderNames | Resolve sender display names | true |
Supported message types
Section titled “Supported message types”Receive
Section titled “Receive”- ✅ Text
- ✅ Rich text (post)
- ✅ Images
- ✅ Files
- ✅ Audio
- ✅ Video/media
- ✅ Stickers
Inbound Feishu/Lark audio messages are normalized as media placeholders instead
of raw file_key JSON. When tools.media.audio is configured, OpenClaw
downloads the voice-note resource and runs shared audio transcription before the
agent turn, so the agent receives the spoken transcript. If Feishu includes
transcript text directly in the audio payload, that text is used without another
ASR call. Without an audio transcription provider, the agent still receives a
<media:audio> placeholder plus the saved attachment, not the raw Feishu
resource payload.
- ✅ Text
- ✅ Images
- ✅ Files
- ✅ Audio
- ✅ Video/media
- ✅ Interactive cards (including streaming updates)
- ⚠️ Rich text (post-style formatting; doesn’t support full Feishu/Lark authoring capabilities)
Native Feishu/Lark audio bubbles use the Feishu audio message type and require
Ogg/Opus upload media (file_type: "opus"). Existing .opus and .ogg media
is sent directly as native audio. MP3/WAV/M4A and other likely audio formats are
transcoded to 48kHz Ogg/Opus with ffmpeg only when the reply requests voice
delivery (audioAsVoice / message tool asVoice, including TTS voice-note
replies). Ordinary MP3 attachments stay regular files. If ffmpeg is missing or
conversion fails, OpenClaw falls back to a file attachment and logs the reason.
Threads and replies
Section titled “Threads and replies”- ✅ Inline replies
- ✅ Thread replies
- ✅ Media replies stay thread-aware when replying to a thread message
For groupSessionScope: "group_topic" and "group_topic_sender", native
Feishu/Lark topic groups use the event thread_id (omt_*) as the canonical
topic session key. If a native topic starter event omits thread_id, OpenClaw
hydrates it from Feishu before routing the turn. Normal group replies that
OpenClaw turns into threads keep using the reply root message ID (om_*) so the
first turn and follow-up turn stay in the same session.
Related
Section titled “Related”- Channels Overview - all supported channels
- Pairing - DM authentication and pairing flow
- Groups - group chat behavior and mention gating
- Channel Routing - session routing for messages
- Security - access model and hardening