Feishu Integration: Setup, Features, and Configuration for OpenClaw
This page covers the OpenClaw Feishu/Lark plugin, including bot DMs, group chats, streaming cards, and tools for docs and wikis. It guides developers through setup via wizard, QR code, or manual configuration.
Read this when
- You want to connect a Feishu/Lark bot
- You are configuring the Feishu channel
OpenClaw integrates with Feishu/Lark, the all-in-one collaboration platform, via the official @openclaw/feishu plugin. This enables bot DMs, group chats, streaming card replies, and tools for Feishu docs, wikis, drives, and Bitable.
Status: bot DMs and group chats are production-ready. WebSocket serves as the default event transport, requiring no public URL; webhook mode remains optional.
Quick start
Note
OpenClaw 2026.5.29 or later is required. Verify with
openclaw --version. To upgrade, useopenclaw update.
Run the channel setup wizard
openclaw channels login --channel feishu
If the @openclaw/feishu plugin is absent, this installs it, then guides you through configuration:
- Manual setup: provide an App ID and App Secret from Feishu Open Platform (
https://open.feishu.cn) or Lark Developer (https://open.larksuite.com). - QR setup: scan a QR code within the Feishu app to generate a bot automatically. This approach restricts DMs to your own account (
dmPolicy: "allowlist"with youropen_id).
The wizard also prompts for the API domain (Feishu or Lark) and the group policy. Should the domestic Feishu mobile app ignore the QR code, rerun setup and opt for manual setup.
After setup completes, restart the gateway to apply the changes
openclaw gateway restart
Inbound durability
Before agent dispatch, OpenClaw durably queues authenticated im.message.receive_v1 and drive.notice.comment_add_v1 envelopes. In webhook mode, the durable 200 carries x-openclaw-delivery-accepted: durable; verification challenges, non-durable event types, and error responses leave out the marker, letting reverse proxies enforce it to tell durable acceptance apart from a generic 200. Pending or retryable events persist across a Gateway restart, stay serialized per chat or document, and rely on Feishu's event ID to block duplicate queue entries while the active or retained completion record is present.
When a WebSocket event cannot be stored after bounded retries, OpenClaw shuts that socket and initiates a fresh authenticated connection, rather than moving past an uncommitted turn. Other Feishu event types, such as reactions and VC meeting invitations, follow their standard event paths and do not get this durable-queue guarantee.
Access control
Direct messages
Set channels.feishu.dmPolicy (default: pairing) to determine who may DM the bot:
| Value | Behavior |
|---|---|
"pairing" | Unknown users get a pairing code; approve it via CLI |
"allowlist" | Only users listed in allowFrom can chat |
"open" | Public DMs; config validation demands allowFrom to contain "*". Non-wildcard entries still restrict access |
Approve a pairing request:
openclaw pairing list feishu
openclaw pairing approve feishu <CODE>
Group chats
Group policy (channels.feishu.groupPolicy, default: allowlist):
| Value | Behavior |
|---|---|
"open" | Reply to every message in groups |
"allowlist" | Reply only to groups in groupAllowFrom or explicitly set under groups.<chat_id> |
"disabled" | Turn off all group messages; explicit groups.<chat_id> entries cannot override this |
Mention requirement (channels.feishu.requireMention):
- By default, an @mention is needed, except when the effective group policy is
"open"; there it defaults tofalseso messages lacking mentions (like images) still reach the agent. - Override by setting
trueorfalseexplicitly; per-group override:channels.feishu.groups.<chat_id>.requireMention. - Broadcast-only
@alland@_alldo not count as bot mentions. A message mentioning both@alland the bot directly still qualifies as a bot mention.
Group configuration examples
Allow all groups, no @mention required
{
channels: {
feishu: {
groupPolicy: "open", // requireMention defaults to false under "open"
},
},
}
Allow all groups, still require @mention
{
channels: {
feishu: {
groupPolicy: "open",
requireMention: true,
},
},
}
Allow specific groups only
{
channels: {
feishu: {
groupPolicy: "allowlist",
// Group IDs look like: oc_xxx
groupAllowFrom: ["oc_xxx", "oc_yyy"],
},
},
}
In allowlist mode, adding an explicit groups.<chat_id> entry also admits a group. Explicit entries never override groupPolicy: "disabled". Wildcard defaults under groups.* configure matching groups, but they do not admit groups on their own.
{
channels: {
feishu: {
groupPolicy: "allowlist",
groups: {
oc_xxx: {
requireMention: false,
},
},
},
},
}
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"],
},
},
},
},
}
channels.feishu.groupSenderAllowFrom applies the same sender allowlist across every group; a group-specific allowFrom overrides it.
Bot-authored messages
By default, Feishu ignores messages from other bots. To enable bot-to-bot group chats, request the im:message.group_at_msg.include_bot:readonly and im:message:readonly scopes for the app, then configure allowBots:
{
channels: {
feishu: {
allowBots: true,
},
},
}
Feishu only sends bot-authored group events when another bot mentions this bot. Existing group policy, sender allowlists, and mention requirements remain in effect. OpenClaw discards self-authored messages, mentions the peer bot in every text or card reply, and enforces the shared channels.defaults.botLoopProtection guard.
Get group/user IDs
Group IDs (chat_id, format: oc_xxx)
In Feishu/Lark, open the group, tap the menu icon at the top-right, then choose Settings. The group ID (chat_id) appears on that settings page.

User IDs (open_id, format: ou_xxx)
Launch the gateway, send a DM to the bot, and inspect the logs:
openclaw logs --follow
Search the log output for open_id. Pending pairing requests can also be reviewed:
openclaw pairing list feishu
Common commands
| Command | Description |
|---|---|
/status | Display bot status |
/reset | Clear the active session |
/model | Show or change the AI model |
Note
Feishu/Lark lacks native slash-command menus, so type these as plain text.
Troubleshooting
Bot does not respond in group chats
- Confirm the bot has been added to the group
- Confirm you @mention the bot (required unless changed)
- Verify
groupPolicyis not set to"disabled" - Review logs:
openclaw logs --follow
Bot does not receive messages
- Confirm the bot is published and approved in Feishu Open Platform / Lark Developer
- Confirm event subscription covers
im.message.receive_v1 - For auto-join of meeting invites, also subscribe to
vc.bot.meeting_invited_v1 - Confirm persistent connection (WebSocket) is selected
- Confirm all required permission scopes have been granted
- Confirm the gateway is running:
openclaw gateway status - Review logs:
openclaw logs --follow
Subscribing to vc.bot.meeting_invited_v1 only triggers the event delivery. Automatic joins are
disabled by default. To turn them on globally:
{
channels: {
feishu: {
vcAutoJoin: true,
},
},
}
To enable for a single account, skip the top-level switch and set the account override:
{
channels: {
feishu: {
accounts: {
meetings: { vcAutoJoin: true },
},
},
},
}
Inviters still pass through the standard Feishu DM policy, allowlist/pairing, session, and reply
routing before the agent gets a join turn. Joining also requires a Feishu VC join
tool configured for app identity with the
vc:meeting.bot.join:write scope. As an example, the official
lark-cli VC agent skill
offers vc +meeting-join.
Warning
The official
lark-cliVC agent skill currently flags meeting-bot actions as a limited beta. If the tool returnsErrNotInGrayor error code20017, the app or tenant has not been enabled for that beta; follow the early-access instructions in the linked skill before checking ordinary scope grants.
QR setup does not react in the Feishu mobile app
- Run setup again:
openclaw channels login --channel feishu - Pick 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
- Reset the App Secret in Feishu Open Platform / Lark Developer
- Update the value in your config
- Restart the gateway:
openclaw gateway restart
Advanced configuration
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 determines which account is used when outbound APIs lack an accountId. Account entries inherit top-level settings; most top-level keys can be overridden per account.
accounts.<id>.tts follows the same structure as 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
textChunkLimit: outbound text chunk size, defaulting to4000charactersstreaming.chunkMode:"length"is the default and cuts at the limit;"newline"prefers breaking at newlinesmediaMaxMb: media upload/download cap, defaulting to30MB
Standard Markdown cards and rich-text posts also get divided to comply with Feishu's 30 KB serialized message cap. Headers, notes, mentions, JSON escaping, and UTF-8 text all consume part of that cap, so chunks can end up smaller than textChunkLimit. Long media captions go out as text/card chunks before the attachment is sent.
Streaming
Feishu/Lark can stream replies through interactive cards using the Card Kit streaming API. With this enabled, the bot refreshes the card live as it produces text.
{
channels: {
feishu: {
streaming: {
mode: "partial", // streaming card output (default: "partial")
block: { enabled: true }, // opt into completed-block streaming
},
},
},
}
Set streaming.mode: "off" to deliver the final reply without streaming updates; long replies still break at the message limits mentioned above. renderMode: "raw" (which uses plain text rather than cards) also turns off streaming cards. streaming.block.enabled defaults to off; switch it on only when you need completed assistant blocks flushed ahead of the final reply. The legacy boolean streaming and the flat blockStreaming / blockStreamingCoalesce / chunkMode keys migrate into this nested structure via openclaw doctor --fix.
Quota optimization
Cut down on 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,
},
},
}
Group session scope and topic threads
channels.feishu.groupSessionScope (top-level, per account, or per group) determines how group messages map to agent sessions:
| Value | Session |
|---|---|
"group" (default) | One session per group chat |
"group_sender" | One session per (group + sender) |
"group_topic" | One session per topic thread; falls back to the group session |
"group_topic_sender" | One session per (topic + sender); falls back to (group + sender) |
For topic scopes, native Feishu/Lark topic groups rely on the event thread_id (omt_*) as the canonical topic session key. When a native topic starter event omits thread_id, OpenClaw fills it in from Feishu before routing the turn. Regular group replies that OpenClaw converts into threads keep using the reply root message ID (om_*) so the initial turn and subsequent turns stay in the same session.
Set replyInThread: "enabled" (top-level or per group) so bot replies create or continue a Feishu topic thread instead of replying inline. topicSessionMode is the deprecated predecessor of groupSessionScope; go with groupSessionScope.
Feishu workspace tools
The plugin includes agent tools for Feishu documents, chats, knowledge base, cloud storage, permissions, and Bitable, along with matching skills (feishu-doc, feishu-drive, feishu-perm, feishu-wiki). Tool families are controlled by channels.feishu.tools:
| Key | Tools | Default |
|---|---|---|
tools.doc | feishu_doc document operations | true |
tools.chat | feishu_chat chat info + member queries | true |
tools.wiki | feishu_wiki knowledge base (requires doc) | true |
tools.drive | feishu_drive cloud storage | true |
tools.perm | feishu_perm permission management | false (sensitive) |
tools.scopes | feishu_app_scopes app scope diagnostics | true |
tools.bitable | feishu_bitable_* Bitable/Base operations | true |
Per-account gates are located under accounts.<id>.tools.
Only title-bearing documents are produced by feishu_doc. To include Markdown content, take the returned document_id and feed it as doc_token into a subsequent write call. Any create request carrying content will fail, and no empty document gets created.
For direct feishu_drive info lookups outside the root directory, grant drive:drive.metadata:readonly, unless the app already holds the complete drive:drive scope. When neither scope is present, info preserves the legacy root-directory lookup path via drive:drive:readonly.
ACP sessions
ACP is supported for DMs and group thread messages on Feishu/Lark. Since there are no native slash-command menus, Feishu/Lark ACP relies on text commands, so send /acp ... messages straight into the conversation.
Persistent ACP binding
{
agents: {
entries: {
codex: {
default: true,
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
Inside a Feishu/Lark DM or thread:
/acp spawn codex --thread here
DMs and Feishu/Lark thread messages both work with --thread here. Any follow-up messages within the bound conversation are sent directly to that ACP session.
Multi-agent routing
To direct Feishu/Lark DMs or groups toward different agents, use bindings.
{
agents: {
entries: {
main: { default: true },
"agent-a": { workspace: "/home/user/agent-a" },
"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" },
},
},
],
}
Fields for routing:
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)
For lookup guidance, check Get group/user IDs.
Per-user agent isolation (Dynamic Agent Creation)
Turning on dynamicAgentCreation creates isolated agent instances automatically for every DM user. Each user is given their own:
- Workspace directory that is independent
- Separate
USER.md/SOUL.md/MEMORY.md - Conversation history kept private
- Skills and state that are isolated
For public bots where each user should get a private AI assistant experience, this becomes essential.
Note
The normalized Feishu
accountIdis part of dynamic bindings, which means both default and named accounts direct each sender to the appropriate dynamic agent.On older releases, a named account may have created an unscoped dynamic agent. Such legacy agents still consume
maxAgents. Before removing one, verify it is not in use by the default account, or raisemaxAgentstemporarily. OpenClaw cannot reliably determine which account owns ambiguous legacy state.
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
When a user sends their first DM:
- A unique
agentIdis generated by the channel:feishu-{user_open_id}for the default account, or a bounded account-prefixed identity digest for a named account - A new workspace is created at the
workspaceTemplatepath - The agent is registered and a binding for that user is established
- On first access, the workspace helper ensures bootstrap files (
AGENTS.md,SOUL.md,USER.md, etc.) are present - All subsequent messages from this user are routed to their dedicated agent
Configuration options
| Setting | Description | Default |
|---|---|---|
channels.feishu.dynamicAgentCreation.enabled | Turn on automatic per-user agent creation | false |
channels.feishu.dynamicAgentCreation.workspaceTemplate | Template for dynamic agent workspace paths | ~/.openclaw/workspace-{agentId} |
channels.feishu.dynamicAgentCreation.agentDirTemplate | Template for agent directory names | ~/.openclaw/agents/{agentId}/agent |
channels.feishu.dynamicAgentCreation.maxAgents | Cap on the number of dynamic agents | unlimited |
Template variables:
{agentId}- the generated agent ID (for instance,feishu-ou_xxxxxxorfeishu-support-<identity_digest>){userId}- the sender's Feishu open_id (for instance,ou_xxxxxx)
Session scope
Mapping of direct messages to agent sessions is governed by session.dmScope. This setting applies globally, affecting every channel.
| Value | Behavior | Best for |
|---|---|---|
"main" | A user's DM maps to their agent's main session | Single-user bots where USER.md / SOUL.md should auto-load |
"per-peer" | Each peer receives its own session (channel-independent) | Isolation based solely on sender identity |
"per-channel-peer" | Each (channel + user) pair gets its own session | Public multi-user bots requiring stronger isolation |
"per-account-channel-peer" | Each (account + channel + user) trio gets its own session | Multi-account bots needing account-level session isolation |
Tradeoff: With "main", bootstrap files (USER.md, SOUL.md, MEMORY.md) load automatically, but every DM across all channels shares the same session key pattern. For public multi-user bots where isolation outweighs bootstrap auto-loading, "per-channel-peer" is a better fit, with manual bootstrap file management.
Note
When named Feishu accounts must maintain separate sessions for the same sender, use
"per-account-channel-peer". Account scope is preserved by dynamic bindings.
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
To verify dynamic creation is functioning, inspect the gateway logs:
feishu: creating dynamic agent "feishu-ou_xxxxxx" for user ou_xxxxxx
workspace: /home/user/.openclaw/workspace-feishu-ou_xxxxxx
agentDir: /home/user/.openclaw/agents/feishu-ou_xxxxxx/agent
To list every workspace that has been created:
ls -la ~/.openclaw/workspace-*
Notes
- Workspace isolation: A dedicated workspace directory and agent instance exist for each user. Within the normal messaging flow, users cannot access each other's conversation history or files.
- Security boundary: This isolates messaging context, not hostile co-tenants. The agent process and host environment are shared.
- Config writes must stay enabled: Agents and bindings are written into the config during dynamic creation; this step is skipped when
channels.feishu.configWritesisfalse(default: enabled). bindingsshould be empty: Bindings are auto-registered by dynamic agents- Upgrade path: Manual bindings and dynamic agents can coexist
session.dmScopeis global: All channels are affected, not just Feishu
Configuration reference
Full configuration: Gateway configuration
| Setting | Description | Default |
|---|---|---|
channels.feishu.enabled | Turns the channel on or off | true |
channels.feishu.domain | API endpoint (feishu, lark, or a custom https:// base URL) | feishu |
channels.feishu.connectionMode | How events are delivered (websocket or webhook) | websocket |
channels.feishu.defaultAccount | Default account used for outgoing messages | default |
channels.feishu.verificationToken | Mandatory when operating in webhook mode | - |
channels.feishu.encryptKey | Mandatory when operating in webhook mode | - |
channels.feishu.webhookPath | Standard HTTP request path (needs to begin with /) | /feishu/events |
channels.feishu.webhookHost | Host the webhook listens on | 127.0.0.1 |
channels.feishu.webhookPort | Port the webhook listens on | 3000 |
channels.feishu.accounts.<id>.appId | Application identifier | - |
channels.feishu.accounts.<id>.appSecret | Application secret | - |
channels.feishu.accounts.<id>.domain | Overrides the domain for a specific account | feishu |
channels.feishu.accounts.<id>.replyToMode | Overrides reply-reference behavior for a specific account | inherited |
channels.feishu.accounts.<id>.tts | Overrides text-to-speech for a specific account | tts |
channels.feishu.accounts.<id>.actions.sticker | Overrides sticker handling for a specific account | inherited |
channels.feishu.dmPolicy | Direct message handling (pairing, allowlist, open) | pairing |
channels.feishu.allowFrom | Direct message allowlist (open_id list) | - |
channels.feishu.groupPolicy | Group handling (open, allowlist, disabled) | allowlist |
channels.feishu.groupAllowFrom | Group allowlist | - |
channels.feishu.groupSenderAllowFrom | Sender allowlist that applies to every group | - |
channels.feishu.requireMention | Groups require an @mention | true (false when policy is open) |
channels.feishu.allowBots | Accept mentions from other bots, with protection against bot loops | false |
channels.feishu.groups.<chat_id>.requireMention | Overrides @mention needs per group; explicit IDs also add the group to the allowlist in allowlist mode | inherited |
channels.feishu.groups.<chat_id>.enabled | Enables or disables a particular group | true |
channels.feishu.groups.<chat_id>.allowFrom | Per-group sender allowlist (takes precedence over groupSenderAllowFrom) | - |
channels.feishu.groupSessionScope | Maps group sessions (group, group_sender, group_topic, group_topic_sender) | group |
channels.feishu.replyToMode | Reply-reference mode (off, first, all, batched) | all |
channels.feishu.replyInThread | Bot replies create/continue topic threads (disabled, enabled) | disabled |
channels.feishu.reactionNotifications | Inbound reaction events (off, own, all) | own |
channels.feishu.actions.sticker | Enable received-sticker sending and configured sticker search | false |
channels.feishu.stickerSets | Searchable received-sticker keys and keywords, grouped by bot app ID | none |
channels.feishu.vcAutoJoin | Join invited VC meetings after normal DM authorization | false |
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 | 4000 |
channels.feishu.streaming.chunkMode | Chunk splitting (length or newline) | length |
channels.feishu.mediaMaxMb | Media size limit | 30 |
channels.feishu.renderMode | Reply rendering (auto, raw, card) | auto |
channels.feishu.streaming.mode | Streaming card output (partial or off) | partial |
channels.feishu.streaming.block.enabled | Completed-block reply streaming | false |
channels.feishu.typingIndicator | Send typing reactions | true |
channels.feishu.resolveSenderNames | Resolve sender display names | true |
channels.feishu.configWrites | Allow channel-initiated config writes (needed by dynamic agents) | true |
channels.feishu.tools.doc | Enable document tools | true |
channels.feishu.tools.chat | Enable chat info tools | true |
channels.feishu.tools.wiki | Enable knowledge base tools (requires doc) | true |
channels.feishu.tools.drive | Turn on cloud storage tools | true |
channels.feishu.tools.perm | Turn on permission management tools | false |
channels.feishu.tools.scopes | Turn on app scopes diagnostic tool | true |
channels.feishu.tools.bitable | Turn on Bitable/Base tools | true |
channels.feishu.accounts.<id>.tools.bitable | Per-account Bitable/Base tool gate | inherited |
In webhook mode, channels.feishu.webhookPath and channels.feishu.accounts.<id>.webhookPath have to be canonical HTTP request paths that start with /, for instance /feishu/events. An optional query string is allowed and needs to match exactly. Full URLs, relative paths, URL fragments, dot segments, and unencoded spaces or Unicode get rejected. If a current configuration holds a noncanonical path, execute openclaw doctor --fix to fix it before the gateway starts.
Supported message types
Receive
- ✅ Text
- ✅ Rich text (post)
- ✅ Images
- ✅ Files
- ✅ Audio
- ✅ Video/media
- ✅ Stickers
Received stickers make their reusable file_key available to the agent as <sticker key="..."/>. Downloading sticker resources is not supported by Feishu/Lark, so OpenClaw keeps the key without fetching an attachment.
Inbound Feishu/Lark audio messages get normalized as media placeholders rather than raw file_key JSON. When tools.media.audio is set, OpenClaw pulls the voice-note resource and runs shared audio transcription before the agent turn, giving the agent 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 gets a <media:audio> placeholder plus the saved attachment, not the raw Feishu resource payload.
Send
- ✅ Text
- ✅ Images
- ✅ Files
- ✅ Audio
- ✅ Video/media
- ✅ Interactive cards (including streaming updates)
- ✅ Stickers previously received by the same bot (requires
actions.sticker) - ⚠️ 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 need 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.
Sticker replies
Enable the sticker action to let the agent resend stickers:
{
channels: {
feishu: {
actions: { sticker: true },
},
},
}
For one account only, set channels.feishu.accounts.<id>.actions.sticker: true instead. An account-level actions object replaces, rather than merges with, the channel-level object. Repeat any action gates you want to preserve. For example, keep reactions disabled while enabling stickers for work:
{
channels: {
feishu: {
actions: { reactions: false },
accounts: {
work: {
actions: { reactions: false, sticker: true },
},
},
},
},
}
Send a sticker to that bot first, then ask it to resend the sticker. The shared message tool uses action: "sticker" with the received file_key in fileId or the first entry of stickerId. In multi-account setups, use the same accountId that received the sticker.
Only stickers previously received by that bot can be sent. Uploading new stickers, downloading sticker resources, and searching the sticker store are not supported.
Sticker keyword search
Add a curated sticker set to let the agent find a received sticker by keyword. First send each sticker to the bot and ask it for the received file_key. Then add keys and your own labels to the existing Feishu configuration:
{
channels: {
feishu: {
actions: { sticker: true },
stickerSets: {
cli_work: {
file_received_key: ["thumbs up", "赞", "👍"],
},
},
},
},
}
Replace cli_work with the bot's actual app ID and file_received_key with the key received by that bot. stickerSets belongs directly under channels.feishu, not inside an account. The selected account can search only the set matching its app ID; changing an account to a different bot does not reuse the previous bot's set. Accounts using the same bot share its set. Keep any existing account-level action gates as described above.
Ask the agent to “send a thumbs up sticker.” It can use the shared message tool with action: "sticker-search", query: "thumbs up", and the intended accountId, then send a returned fileId with action: "sticker" on that same account. Search is available only when stickers are enabled and the bot has a nonempty configured set.
Search matches a case-insensitive substring of an explicit keyword, including Chinese labels and emoji, in sticker-key order. It does not infer a sticker's meaning, search Feishu's store, or automatically collect received stickers. Results include the matching keyword and reusable fileId. No matches produce an empty list; truncated: true means matching entries were omitted by the result limit or output budget. Narrow the query to find other matches.
Limits: 32 bot sets, 256 stickers per set, and 1, 8 keywords per sticker. Store keywords without leading or trailing whitespace; each must be nonempty and at most 64 Unicode characters. File keys must be canonical received keys, at most 512 Unicode characters. Each key appears only once in its bot's map. Queries are nonempty and at most 128 Unicode characters. limit defaults to 5 and accepts integers from 1 through 10; search results are also capped at 3 KiB of JSON output. Removing a set removes it from search; no separate sticker database or cache is created.
Threads and replies
- ✅ Inline responses are supported
- ✅ Replies within threads are supported
- ✅ When replying to a thread message, media replies remain thread-aware
For details on topic-group session routing, see Group session scope and topic threads.
Related
- Channels Overview - every channel that is supported
- Pairing - the DM authentication and pairing process
- Groups - behavior in group chats and mention restrictions
- Channel Routing - how messages are routed across sessions
- Security - the access model and hardening measures