
Lark Im
- 7 installs
- 60 repo stars
- Updated April 13, 2026
- liangdabiao/lark-workflow-feishu-cli
Helps with ai & agent building tasks.
About
lark-im is a Claude Code skill for ai & agent building. It helps solo builders move faster with AI-assisted development.
- lark-im
- AI & Agent Building
- AI-coding skill
Lark Im by the numbers
- 7 all-time installs (skills.sh)
- Ranked #12,545 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
- Data as of Aug 4, 2026 (Skillselion catalog sync)
npx skills add https://github.com/liangdabiao/lark-workflow-feishu-cli --skill lark-imAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 7 |
|---|---|
| repo stars | ★ 60 |
| Last updated | April 13, 2026 |
| Repository | liangdabiao/lark-workflow-feishu-cli ↗ |
What it does
Helps with ai & agent building tasks.
Files
im (v1)
CRITICAL — 开始前 MUST 先用 Read 工具读取 [`../lark-shared/SKILL.md`](../lark-shared/SKILL.md),其中包含认证、权限处理
Core Concepts
- Message: A single message in a chat, identified by
message_id(om_xxx). Supports types: text, post, image, file, audio, video, sticker, interactive (card), share_chat, share_user, merge_forward, etc. - Chat: A group chat or P2P conversation, identified by
chat_id(oc_xxx). - Thread: A reply thread under a message, identified by
thread_id(om_xxx or omt_xxx). - Reaction: An emoji reaction on a message.
Resource Relationships
Chat (oc_xxx)
├── Message (om_xxx)
│ ├── Thread (reply thread)
│ ├── Reaction (emoji)
│ └── Resource (image / file / video / audio)
└── Member (user / bot)Important Notes
Identity and Token Mapping
--as usermeans user identity and usesuser_access_token. Calls run as the authorized end user, so permissions depend on both the app scopes and that user's own access to the target chat/message/resource.--as botmeans bot identity and usestenant_access_token. Calls run as the app bot, so behavior depends on the bot's membership, app visibility, availability range, and bot-specific scopes.- If an IM API says it supports both
userandbot, the token type changes who the operator is. The same API can succeed with one identity and fail with the other because owner/admin status, chat membership, tenant boundary, or app availability are checked against the current caller.
Sender Name Resolution with Bot Identity
When using bot identity (--as bot) to fetch messages (e.g. +chat-messages-list, +threads-messages-list, +messages-mget), sender names may not be resolved (shown as open_id instead of display name). This happens when the bot cannot access the user's contact info.
Root cause: The bot's app visibility settings do not include the message sender, so the contact API returns no name.
Solution: Check the app's visibility settings in the Lark Developer Console — ensure the app's visible range covers the users whose names need to be resolved. Alternatively, use --as user to fetch messages with user identity, which typically has broader contact access.
Card Messages (Interactive)
Card messages (interactive type) are not yet supported for compact conversion in event subscriptions. The raw event data will be returned instead, with a hint printed to stderr.
Shortcuts(推荐优先使用)
Shortcut 是对常用操作的高级封装(lark-cli im +<verb> [flags])。有 Shortcut 的操作优先使用。
| Shortcut | 说明 |
|---|---|
| `+chat-create` | Create a group chat with bot identity; bot-only; creates private/public chats, invites users/bots, optionally sets bot manager |
| `+chat-messages-list` | List messages in a chat or P2P conversation; user/bot; accepts --chat-id or --user-id, resolves P2P chat_id, supports time range/sort/pagination |
| `+chat-search` | Search visible group chats by keyword and/or member open_ids (e.g. look up chat_id by group name); user/bot; supports member/type filters, sorting, and pagination |
| `+chat-update` | Update group chat name or description; user/bot; updates a chat's name or description |
| `+messages-mget` | Batch get messages by IDs; user/bot; fetches up to 50 om_ message IDs, formats sender names, expands thread replies |
| `+messages-reply` | Reply to a message (supports thread replies) with bot identity; bot-only; supports text/markdown/post/media replies, reply-in-thread, idempotency key |
| `+messages-resources-download` | Download images/files from a message; user/bot; downloads image/file resources by message-id and file-key to a safe relative output path |
| `+messages-search` | Search messages across chats (supports keyword, sender, time range filters) with user identity; user-only; filters by chat/sender/attachment/time, enriches results via mget and chats batch_query |
| `+messages-send` | Send a message to a chat or direct message with bot identity; bot-only; sends to chat-id or user-id with text/markdown/post/media, supports idempotency key |
| `+threads-messages-list` | List messages in a thread; user/bot; accepts om_/omt_ input, resolves message IDs to thread_id, supports sort/pagination |
API Resources
lark-cli schema im.<resource>.<method> # 调用 API 前必须先查看参数结构
lark-cli im <resource> <method> [flags] # 调用 API重要:使用原生 API 时,必须先运行schema查看--data/--params参数结构,不要猜测字段格式。
chats
create— 创建群。Identity:botonly (tenant_access_token).get— 获取群信息。Identity: supportsuserandbot; the caller must be in the target chat to get full details, and must belong to the same tenant for internal chats.link— 获取群分享链接。Identity: supportsuserandbot; the caller must be in the target chat, must be an owner or admin when chat sharing is restricted to owners/admins, and must belong to the same tenant for internal chats.list— 获取用户或机器人所在的群列表。Identity: supportsuserandbot.update— 更新群信息。Identity: supportsuserandbot.
chat.members
create— 将用户或机器人拉入群聊。Identity: supportsuserandbot; the caller must be in the target chat; forbotcalls, added users must be within the app's availability; for internal chats the operator must belong to the same tenant; if only owners/admins can add members, the caller must be an owner/admin, or a chat-creator bot withim:chat:operate_as_owner.get— 获取群成员列表。Identity: supportsuserandbot; the caller must be in the target chat and must belong to the same tenant for internal chats.
messages
delete— 撤回消息。Identity: supportsuserandbot; forbotcalls, the bot must be in the chat to revoke group messages; to revoke another user's group message, the bot must be the owner, an admin, or the creator; for user P2P recalls, the target user must be within the bot's availability.forward— 转发消息。Identity:botonly (tenant_access_token).merge_forward— 合并转发消息。Identity:botonly (tenant_access_token).read_users— 查询消息已读信息。Identity:botonly (tenant_access_token); the bot must be in the chat, and can only query read status for messages it sent within the last 7 days.
reactions
batch_query— 批量获取消息表情。Identity: supportsuserandbot.Must-readcreate— 添加消息表情回复。Identity: supportsuserandbot; the caller must be in the conversation that contains the message.Must-readdelete— 删除消息表情回复。Identity: supportsuserandbot; the caller must be in the conversation that contains the message, and can only delete reactions added by itself.Must-readlist— 获取消息表情回复。Identity: supportsuserandbot; the caller must be in the conversation that contains the message.Must-read
images
create— 上传图片。Identity:botonly (tenant_access_token).
pins
create— Pin 消息。Identity: supportsuserandbot.delete— 移除 Pin 消息。Identity: supportsuserandbot.list— 获取群内 Pin 消息。Identity: supportsuserandbot.
权限表
| 方法 | 所需 scope |
|---|---|
chats.create | im:chat:create |
chats.get | im:chat:read |
chats.link | im:chat:read |
chats.list | im:chat:read |
chats.update | im:chat:update |
chat.members.create | im:chat.members:write_only |
chat.members.get | im:chat.members:read |
messages.delete | im:message:recall |
messages.forward | im:message |
messages.merge_forward | im:message |
messages.read_users | im:message:readonly |
reactions.batch_query | im:message.reactions:read |
reactions.create | im:message.reactions:write_only |
reactions.delete | im:message.reactions:write_only |
reactions.list | im:message.reactions:read |
images.create | im:resource |
pins.create | im:message.pins:write_only |
pins.delete | im:message.pins:write_only |
pins.list | im:message.pins:read |
im +chat-create
Prerequisite: Read `../lark-shared/SKILL.md` first to understand authentication, global parameters, and safety rules.
Create a group chat using bot identity (TAT). You can specify the group name, description, members (users/bots), owner, and chat type (private/public).
This skill maps to the shortcut: lark-cli im +chat-create (internally calls POST /open-apis/im/v1/chats).
Commands
# Create a private group (default)
lark-cli im +chat-create --name "My Group"
# Create a public group (name is required and must be at least 2 characters)
lark-cli im +chat-create --name "Public Group" --type public
# Specify the group owner
lark-cli im +chat-create --name "My Group" --owner ou_xxx
# Invite user members (comma-separated open_ids, up to 50)
lark-cli im +chat-create --name "My Group" --users "ou_aaa,ou_bbb"
# Invite bot members (comma-separated app IDs, up to 5)
lark-cli im +chat-create --name "My Group" --bots "cli_aaa,cli_bbb"
# Invite both users and bots
lark-cli im +chat-create --name "My Group" --users "ou_aaa" --bots "cli_aaa"
# Make the creating bot a group manager
lark-cli im +chat-create --name "My Group" --set-bot-manager
# JSON output
lark-cli im +chat-create --name "My Group" --format json
# Preview the request without creating anything
lark-cli im +chat-create --name "My Group" --dry-runParameters
| Parameter | Required | Limits | Description |
|---|---|---|---|
--name <name> | Required for public groups | Max 60 characters; at least 2 characters for public groups | Group name ("(no subject)" for private groups if omitted) |
--description <text> | No | Max 100 characters | Group description |
--users <ids> | No | Up to 50, format ou_xxx | Comma-separated user open_ids |
--bots <ids> | No | Up to 5, format cli_xxx | Comma-separated bot app IDs |
--owner <open_id> | No | Format ou_xxx | Owner open_id (defaults to the bot if not specified) |
--type <type> | No | private (default) or public | Group type |
--set-bot-manager | No | - | Set the creating bot as a group manager |
--format json | No | - | Output as JSON |
--dry-run | No | - | Preview the request without executing it |
Note: Only bot identity is supported.
AI Usage Guidance
When the user asks to create a group, always use the two-step flow below. Do NOT pass other users' open_ids in --users during group creation — the bot and target users are often mutually invisible (error 232043).
1. Get the current user's open_id: Run lark-cli contact +get-user to retrieve it. 2. Create the group — by default include the current user:
lark-cli im +chat-create --name "<group name>" \
--users "<current user open_id>"Default behavior: Always add the current user to the group, unless the user explicitly says "do not add me" or "bot-only group" — only then omit --users.
3. Add other members via user identity (requires the current user to be in the group):
lark-cli im chat.members create \
--params '{"chat_id":"<chat_id from step 2>","member_id_type":"open_id","succeed_type":1}' \
--data '{"id_list":["ou_aaa","ou_bbb"]}' \
--as usersucceed_type=1 ensures reachable users are added successfully; unreachable ones are returned in invalid_id_list instead of failing the whole request.
4. Check `invalid_id_list` in the response. If non-empty, report to the user which members could not be added.
Output Fields
| Field | Description |
|---|---|
chat_id | The new group's ID (oc_xxx format) |
name | Group name |
chat_type | Group type (private / public) |
owner_id | Owner ID (may be empty when a bot creates the group and --owner is not specified) |
external | Whether the group is external |
share_link | Group share link (omitted if retrieval fails) |
Usage Scenarios
Scenario 1: Create a group and specify the owner
lark-cli im +chat-create --name "Project Discussion Group" --owner ou_xxxScenario 2: Create a group and invite users and a bot
lark-cli im +chat-create --name "Project Discussion Group" \
--owner ou_xxx \
--users "ou_aaa,ou_bbb" \
--bots "cli_aaa"Scenario 3: Create a group and send a welcome message
CHAT_ID=$(lark-cli im +chat-create --name "New Group" --format json | jq -r '.data.chat_id')
lark-cli im +messages-send --chat-id "$CHAT_ID" --text "Welcome, everyone!"Common Errors and Troubleshooting
| Symptom | Root Cause | Solution |
|---|---|---|
| Permission denied (99991672) | The bot app does not have im:chat:create TAT permission enabled | Enable the required permission for the app in the Open Platform console |
--name is required for public groups and must be at least 2 characters | A public group was created without a name or with a name shorter than 2 characters | Provide a name with at least 2 characters |
--name exceeds the maximum of 60 characters | The group name is too long | Shorten the name to 60 characters or fewer |
--description exceeds the maximum of 100 characters | The group description is too long | Shorten the description to 100 characters or fewer |
--users exceeds the maximum of 50 | Too many user members were provided | Split the operation into batches and add more members later |
--bots exceeds the maximum of 5 | Too many bot members were provided | Invite at most 5 bots at once |
invalid user id: expected open_id (ou_xxx) | Invalid user ID format | Use the ou_xxx format for users |
invalid bot id: expected app ID (cli_xxx) | Invalid bot ID format | Use the cli_xxx format for bots |
invalid --owner: expected open_id (ou_xxx) | Invalid owner ID format | Use the ou_xxx format for the owner |
bot is invisible to user (232043) | The bot and target users are mutually invisible | Follow the two-step flow in AI Usage Guidance above — do not pass other users in --users during creation |
References
- lark-im - all IM commands
- lark-shared - authentication and global parameters
Group Chat Identity Rules
Warning: The most common source of failure in group operations is choosing the wrong identity. Confirm the identity before performing the action.
Group-chat operations support both --as user (UAT user identity) and --as bot (TAT bot identity). Choosing the correct identity is critical for success.
Basic Principles
- If the user explicitly specifies an identity: use exactly what the user requested (
--as useror--as bot) without guessing. - If the user does not specify an identity: infer the correct identity from context instead of relying on the default.
Identity Selection by Operation
| Operation | Recommended Identity | Why |
|---|---|---|
Create group (+chat-create) | Depends on the scenario | Default is bot |
| Add members (member-management flow) | --as user | Bot visibility is limited and often fails when the target user is mutually invisible to the bot (232024) |
Update group (+chat-update) | Owner identity | Permission changes require owner/admin privileges; owner transfer requires owner identity |
Inferring the Owner
When an owner-level action is needed and the owner is unknown, infer in this order:
1. A bot created the group and --owner was not specified -> the owner is the bot (--as bot) 2. A bot created the group and --owner ou_xxx was specified -> the owner is that user (--as user) 3. A user created the group and --owner was not specified -> the owner is the current user (--as user) 4. Still unclear -> ask the user to confirm who owns the group before making owner-level changes
When the Owner Is Neither the Current User Nor the Bot
If the query shows that the owner is a third-party user (owner_id is neither the currently authorized user nor the bot), the current identity does not have owner privileges. In that case:
- Permission/setting changes: if the bot is an admin of the group,
--as botcan still perform admin-level operations such as renaming the group or changing permissions. - Owner-only actions such as owner transfer: require the actual owner to complete UAT authorization via
lark-cli auth login, then perform the action as that owner. - Explain the limitation clearly to the user instead of retrying blindly.
Common Pitfalls
Inviting Members During Group Creation
If a bot creates a group and --users includes users who are mutually invisible to the bot, the entire request fails with 232043. Use two steps instead:
1. Create the group with the bot first, excluding invisible users: lark-cli im +chat-create --name "Group Name" 2. Add users later with a user-identity member-management flow
Insufficient Privileges
- 232016 / 232002 / 232017: the current identity is not the owner or an admin -> switch to the owner identity
- 232011: the current user is not in the group -> use a group-member identity, or join the group first
- 232024: the bot and the target user are mutually invisible -> switch to
--as user
References
- lark-im - all IM commands
- lark-shared - authentication and global parameters
im +chat-messages-list
Prerequisite: Read `../lark-shared/SKILL.md` first to understand authentication, global parameters, and safety rules.
Fetch the message list for a conversation. Supports both group chats and direct messages.
This skill maps to the shortcut: lark-cli im +chat-messages-list (internally calls GET /open-apis/im/v1/messages, and automatically resolves the p2p chat_id when needed).
Commands
# Get group chat messages (json output by default)
lark-cli im +chat-messages-list --chat-id oc_xxx
# Get direct messages with a user (pass open_id and resolve p2p chat_id automatically)
lark-cli im +chat-messages-list --user-id ou_xxx
# Specify a time range (ISO 8601)
lark-cli im +chat-messages-list --chat-id oc_xxx --start "2026-03-10T00:00:00+08:00" --end "2026-03-11T00:00:00+08:00"
# Specify a time range (date only)
lark-cli im +chat-messages-list --chat-id oc_xxx --start 2026-03-10 --end 2026-03-11
# Control sort order and page size (max 50)
lark-cli im +chat-messages-list --chat-id oc_xxx --sort asc --page-size 20
# Pagination
lark-cli im +chat-messages-list --chat-id oc_xxx --page-token "xxx"
# JSON output
lark-cli im +chat-messages-list --chat-id oc_xxx --format jsonParameters
| Parameter | Required | Description |
|---|---|---|
--chat-id <id> | One of two | Specify the conversation by its chat_id directly (e.g., group chat oc_xxx) |
--user-id <id> | One of two | Specify a DM conversation by the other user's open_id (ou_xxx); p2p chat_id is resolved automatically |
--start <time> | No | Start time (ISO 8601 or date only) |
--end <time> | No | End time (ISO 8601 or date only) |
--sort <order> | No | Sort order: asc / desc (default desc) |
--page-size <n> | No | Page size (default 50, max 50) |
--page-token <token> | No | Pagination token |
Rule:--chat-idand--user-idare mutually exclusive. You must provide exactly one of them.
Resource Rendering
Messages are rendered into human-readable text for inspection. Image messages are shown as placeholders such as [Image: img_xxx]; files and videos are rendered with resource keys in the content. Resource binaries are not downloaded automatically by this command.
Use lark-im-messages-resources-download when you need to download an image or file from a specific message.
| Resource Type | Marker in Content | Behavior |
|---|---|---|
| Image | [Image: img_xxx] | Download manually with im +messages-resources-download --type image |
| File | <file key="file_xxx" .../> | Download manually with im +messages-resources-download --type file |
| Audio | <audio key="file_xxx" .../> | Download manually with im +messages-resources-download --type file |
| Video | <video key="file_xxx" .../> | Download manually with im +messages-resources-download --type file |
Thread Expansion (thread_id)
In JSON output, a message may contain a thread_id (omt_xxx) field, which means the message has replies in a thread. Use `im +threads-messages-list` to inspect replies in that thread:
lark-cli im +threads-messages-list --thread omt_xxx| Scenario | Recommendation |
|---|---|
| You need context | Call im +threads-messages-list --sort desc --page-size 10 for the discovered thread_id to inspect recent replies |
| The user asks for the "full discussion" | Use im +threads-messages-list --sort asc --page-size 50, then paginate if needed |
| You only need an overview | Skip thread expansion |
Output Fields
| Field | Description |
|---|---|
messages | Message array |
total | Number of messages in the current page |
has_more | Whether additional pages are available |
page_token | Pagination token for the next page |
Each message contains:
| Field | Description |
|---|---|
message_id | Message ID |
msg_type | Message type: text, image, file, interactive, post, audio, video, system, etc. |
create_time | Creation time |
sender | Sender information (includes name for user senders) |
content | Message content |
deleted | Whether the message has been recalled (always present, true = recalled) |
updated | Whether the message has been edited after sending |
mentions | Array of @mentions in the message; each item contains {id, key, name}. Present only when the message contains @mentions |
thread_id | Thread ID (omt_xxx) if the message has replies in a thread. Present only when replies exist |
Pagination (has_more / page_token)
im +chat-messages-list returns has_more and page_token when more data is available. Use --page-token to continue:
lark-cli im +chat-messages-list --chat-id oc_xxx --page-token <PAGE_TOKEN>You can also fall back to the generic API:
lark-cli api GET /open-apis/im/v1/messages \
--params 'container_id_type=chat&container_id=oc_xxx&page_size=50&page_token=<PAGE_TOKEN>'Common Errors and Troubleshooting
| Symptom | Root Cause | Solution |
|---|---|---|
specify --chat-id <chat_id> or --user-id <open_id> | Neither --chat-id nor --user-id was provided | You must provide exactly one |
--chat-id and --user-id cannot be specified together | Both parameters were provided | Use only one |
P2P chat not found for this user | --user-id was used but no p2p chat exists for the current identity and that user | Confirm the target direct-message relationship exists for the current identity |
--start: invalid time format | Invalid time format | Use ISO 8601 or date-only format such as 2026-03-10 |
| Permission denied | Message read permissions are missing | Ensure the app has im:message:readonly and im:chat:read enabled |
AI Usage Guidance
1. Resolving chat_id from a chat name: When the user refers to a chat by name and you don't have the chat_id, use `+chat-search` first:
# Find chat_id by name, then list messages
lark-cli im +chat-search --query "<chat name keyword>" --format json
lark-cli im +chat-messages-list --chat-id <chat_id>Do not use `im chats search` or `im chats list` — always use the `+chat-search` shortcut. 2. Prefer `--chat-id` when available: if the chat_id is already known, use it directly to avoid extra API calls. 3. For direct messages: use --user-id to resolve the p2p chat automatically instead of looking it up manually. 4. For time ranges: both ISO 8601 and date-only inputs are supported. Date-only is usually simpler. 5. For full content: table output truncates content. Use --format json when you need the complete message body. 6. For sender info: the command already resolves sender names, so you do not need a separate lookup.
References
- lark-im - all IM commands
- lark-shared - authentication and global parameters
im +chat-search
Prerequisite: Read `../lark-shared/SKILL.md` first to understand authentication, global parameters, and safety rules.
Search the list of group chats visible to a user or bot, including chats the user or bot belongs to and public chats visible to them. Supports keyword matching on chat names and member names, including pinyin and prefix fuzzy search.
This skill maps to the shortcut: lark-cli im +chat-search (internally calls POST /open-apis/im/v2/chats/search).
Commands
# Search chats by keyword
lark-cli im +chat-search --query "project"
# Restrict by search types
lark-cli im +chat-search --query "project" --search-types "private,public_joined"
# Filter by member open_ids (with keyword)
lark-cli im +chat-search --query "project" --member-ids "ou_xxx,ou_yyy"
# Search by member open_ids only
lark-cli im +chat-search --member-ids "ou_xxx,ou_yyy"
# Only show chats you created or manage
lark-cli im +chat-search --query "project" --is-manager
# Set page size
lark-cli im +chat-search --query "project" --page-size 10
# Pagination
lark-cli im +chat-search --query "project" --page-token "xxx"
# JSON output
lark-cli im +chat-search --query "project" --format json
# Preview the request without executing it
lark-cli im +chat-search --query "project" --dry-runParameters
| Parameter | Required | Limits | Description |
|---|---|---|---|
--query <keyword> | No (at least one of --query / --member-ids required) | Max 64 characters | Search keyword. Supports matching localized chat names, member names, multilingual search, pinyin, and prefix fuzzy search. If the query contains -, it is automatically wrapped in quotes |
--search-types <types> | No | Comma-separated: private, external, public_joined, public_not_joined | Restrict the visible chat types returned by search |
--member-ids <ids> | No (at least one of --query / --member-ids required) | Up to 50, format ou_xxx | Filter by member open_ids; can be used alone or combined with --query |
--is-manager | No | - | Only show chats you created or manage |
--disable-search-by-user | No | - | Disable member-name-based matching and search by group name only |
--sort-by <field> | No | create_time_desc, update_time_desc, member_count_desc | Sort field in descending order |
--page-size <n> | No | 1-100, default 20 | Number of results per page |
--page-token <token> | No | - | Pagination token from the previous response |
--format json | No | - | Output as JSON |
--dry-run | No | - | Preview the request without executing it |
Note: Supports both--as user(default) and--as bot. When using bot identity, the app must have bot capability enabled.
Output Fields
| Field | Description |
|---|---|
chat_id | Chat ID (oc_xxx format) |
name | Chat name |
description | Chat description |
owner_id | Owner ID |
external | Whether the chat is external |
chat_status | Chat status (normal / dissolved / dissolved_save) |
Usage Scenarios
Scenario 1: Search chats that contain a keyword
lark-cli im +chat-search --query "design review"Scenario 2: Search a chat and list recent messages
CHAT_ID=$(lark-cli im +chat-search --query "project" --format json | jq -r '.data.chats[0].chat_id')
lark-cli im +chat-messages-list --chat-id "$CHAT_ID"Scenario 3: Search a chat and send a message
CHAT_ID=$(lark-cli im +chat-search --query "daily report" --format json | jq -r '.data.chats[0].chat_id')
lark-cli im +messages-send --chat-id "$CHAT_ID" --text "Today's progress update"Common Errors and Troubleshooting
| Symptom | Root Cause | Solution |
|---|---|---|
--query and --member-ids cannot both be empty | Both were omitted | Provide at least --query or --member-ids |
| Empty results | No visible chats matched the keyword or filters | Relax the keyword or filters and try again |
--page-size must be an integer between 1 and 100 | page-size is out of range or not an integer | Use an integer between 1 and 100 |
| Permission denied (99991672) | The bot app does not have im:chat:read TAT permission enabled | Enable the permission for the app in the Open Platform console |
Permission denied (99991679) with --as user | UAT is not authorized for im:chat:read | Run lark-cli auth login --scope "im:chat:read" |
Bot ability is not activated (232025) | The app does not have bot capability enabled | Enable bot capability in the Open Platform console |
AI Usage Guidance
When the user asks to search chats, follow these rules:
1. At least one filter required: --query and --member-ids cannot both be empty. Either alone or combined together are valid. 2. Search scope is limited: only chats visible to the current user or bot can be found (joined chats plus public chats). This is not a global search over all chats. 3. Control result volume: the result set may be large. Use --page-size deliberately. 4. Suggest follow-up actions: after finding a chat, common next steps include listing recent messages (im +chat-messages-list) or sending a message (im +messages-send). 5. NEVER fall back to chats list: If +chat-search returns empty results, do NOT attempt to use im chats list or GET /open-apis/im/v1/chats as a fallback. The list API is not a search API — it returns all chats without keyword filtering and will not help locate the target chat. Instead, ask the user to refine the keyword or check whether the chat is visible to the current identity.
References
- lark-im - all IM commands
- lark-shared - authentication and global parameters
im +chat-update
Prerequisite: Read `../lark-shared/SKILL.md` first to understand authentication, global parameters, and safety rules.
Update a group's name or description. Supports both TAT (bot) and UAT (user) identity.
This skill maps to the shortcut: lark-cli im +chat-update (internally calls PUT /open-apis/im/v1/chats/:chat_id).
Commands
# Update the group name
lark-cli im +chat-update --chat-id oc_xxx --name "New Group Name"
# Update the group description
lark-cli im +chat-update --chat-id oc_xxx --description "Updated group description"
# Update multiple fields at once
lark-cli im +chat-update --chat-id oc_xxx \
--name "Q2 Project Team" \
--description "Owns Q2 goal tracking"
# Preview the request without executing it
lark-cli im +chat-update --chat-id oc_xxx --name "Test" --dry-runParameters
Required
| Parameter | Description |
|---|---|
--chat-id <oc_xxx> | Group ID |
Optional Fields
| Parameter | Limits | Description |
|---|---|---|
--name <name> | Max 60 characters | Group name |
--description <text> | Max 100 characters | Group description |
Global Parameters
| Parameter | Description |
|---|---|
--format json | Output as JSON (default) |
--dry-run | Preview the request without executing it |
Usage Scenarios
Scenario 1: Rename a group and update its description
lark-cli im +chat-update --chat-id oc_xxx \
--name "Q2 Project Team" \
--description "Owns Q2 goal tracking"Common Errors and Troubleshooting
| Symptom | Root Cause | Solution |
|---|---|---|
invalid --chat-id: expected chat ID (oc_xxx) | Invalid chat_id format | Use a valid oc_xxx chat ID |
--name exceeds the maximum of 60 characters | Group name too long | Shorten the name to 60 characters or fewer |
--description exceeds the maximum of 100 characters | Group description too long | Shorten the description to 100 characters or fewer |
at least one field must be specified to update | No update field was provided | Specify at least one field to update |
| Permission denied (99991679) | Missing im:chat:update permission | Run lark-cli auth login --scope "im:chat:update" |
| Non-owner/admin cannot update (232016/232002/232017) | Current identity is not the owner/admin | Try switching identity with --as bot or --as user |
| Not in the group (232011) | The current user is not a member of the group | Use a member identity (--as bot) or join the group first |
AI Usage Guidance
Identity Selection
+chat-update supports both user and bot identity (--as user / --as bot).
Infer the group owner from context whenever possible (for example, if a bot just created the group, the owner is the bot) and use the matching identity directly. If ownership is unclear, query the group first and confirm owner_id.
Identity choice should follow Group Chat Identity Rules: if the user explicitly specifies an identity, use it directly; otherwise infer the owner identity from context.
References
- lark-im - all IM commands
- lark-shared - authentication and global parameters
im +messages-mget
Prerequisite: Read `../lark-shared/SKILL.md` first to understand authentication, global parameters, and safety rules.
Fetch message details in batch. Given a list of message IDs, this returns the full content for multiple messages in one call and automatically resolves sender names.
Supports both `--as user` (default) and `--as bot`.
This skill maps to the shortcut: lark-cli im +messages-mget (internally calls GET /open-apis/im/v1/messages/mget).
Commands
# Fetch a single message
lark-cli im +messages-mget --message-ids om_xxx
# Fetch multiple messages in batch (comma-separated)
lark-cli im +messages-mget --message-ids "om_aaa,om_bbb,om_ccc"
# JSON output
lark-cli im +messages-mget --message-ids "om_aaa,om_bbb" --format json
# Preview the request without executing it
lark-cli im +messages-mget --message-ids "om_aaa" --dry-runParameters
| Parameter | Required | Limits | Description |
|---|---|---|---|
--message-ids <ids> | Yes | At least one, max 50, om_xxx format, comma-separated | Message ID list |
Output Fields
| Field | Description |
|---|---|
messages | Message array |
total | Number of messages returned |
Each message contains:
| Field | Description |
|---|---|
message_id | Message ID |
msg_type | Message type (text, image, file, etc.) |
create_time | Creation time |
sender | Sender information (includes name) |
content | Message content |
Usage Scenarios
Scenario 1: Fetch the full content of a specific message
lark-cli im +messages-mget --message-ids om_xxx --format jsonScenario 2: Fetch multiple messages in one batch
lark-cli im +messages-mget --message-ids "om_aaa,om_bbb,om_ccc"Scenario 3: Use together with the message list command
First get message IDs via +chat-messages-list, then fetch full content via +messages-mget:
# Get the message list
lark-cli im +chat-messages-list --chat-id oc_xxx --format json
# Fetch specific message details
lark-cli im +messages-mget --message-ids "om_aaa,om_bbb"Common Errors and Troubleshooting
| Symptom | Root Cause | Solution |
|---|---|---|
--message-ids requires at least one message ID | No message ID was provided | Provide at least one message ID |
invalid message ID: must start with om_ | Invalid message ID format | Message IDs must start with om_ |
| Permission denied | Message read permission is missing | Ensure the app has im:message:readonly and contact:user.base:readonly enabled |
| Empty result | Message IDs do not exist or are not accessible | Verify the IDs and access permissions |
AI Usage Guidance
1. Use JSON for full content: table output truncates content. Use --format json when the full body matters. 2. Sender names are already enriched: the command resolves sender names automatically, so no extra lookup is required. 3. Images are rendered as placeholders: image messages appear as placeholders such as [Image: img_xxx]. Use +messages-resources-download when you need the binary resource. 4. Batching is more efficient: fetching multiple IDs in one request is better than calling the API repeatedly.
References
- lark-im - all IM commands
- lark-shared - authentication and global parameters
im +messages-reply
Prerequisite: Read `../lark-shared/SKILL.md` first to understand authentication, global parameters, and safety rules.
Reply to a specific message. Only supports bot identity. Also supports thread replies.
This skill maps to the shortcut: lark-cli im +messages-reply (internally calls POST /open-apis/im/v1/messages/:message_id/reply).
Safety Constraints
Replies sent by this tool are visible to other people. Before calling it, you must confirm with the user:
1. Which message to reply to 2. The reply content 3. Which identity to use (bot only)
Do not send a reply without explicit user approval.
When using --as bot, the reply is sent in the app's name, so make sure the app has already been added to the target chat.
Commands
# Reply to a message (plain text, bot identity, --text is recommended)
lark-cli im +messages-reply --message-id om_xxx --text "Received"
# Equivalent manual JSON
lark-cli im +messages-reply --message-id om_xxx --content '{"text":"Received"}'
# Reply as a bot
lark-cli im +messages-reply --message-id om_xxx --text "bot reply" --as bot
# Reply inside the thread (message appears in the target thread)
lark-cli im +messages-reply --message-id om_xxx --text "Let's discuss this" --reply-in-thread
# Bot identity + thread reply
lark-cli im +messages-reply --message-id om_xxx --text "bot reply" --as bot --reply-in-thread
# Reply with a rich-text message
lark-cli im +messages-reply --message-id om_xxx --msg-type post --content '{"zh_cn":{"title":"Reply","content":[[{"tag":"text","text":"Detailed content"}]]}}'
# Reply with a local image (uploaded automatically before sending)
lark-cli im +messages-reply --message-id om_xxx --image ./photo.png
# Reply with a local file (uploaded automatically before sending)
lark-cli im +messages-reply --message-id om_xxx --file ./report.pdf
# Reply with a local video (--video-cover is required as the video cover)
lark-cli im +messages-reply --message-id om_xxx --video ./demo.mp4 --video-cover ./cover.png
# With an idempotency key
lark-cli im +messages-reply --message-id om_xxx --text "Received" --idempotency-key my-unique-id
# Preview the request without executing it
lark-cli im +messages-reply --message-id om_xxx --text "Test" --dry-runParameters
| Parameter | Required | Description |
|---|---|---|
--message-id <id> | Yes | ID of the message being replied to (om_xxx) |
--msg-type <type> | No | Message type (default text): text, post, image, file, audio, media, interactive, share_chat, share_user |
--content <json> | One of content options | Reply content as a JSON string; format depends on msg_type |
--text <string> | One of content options | Plain text message (automatically wrapped as {"text":"..."} JSON) |
--markdown <string> | One of content options | Markdown text (auto-wrapped as post format with style optimization; image URLs auto-resolved) |
| `--image <path\ | key>` | One of content options |
| `--file <path\ | key>` | One of content options |
| `--video <path\ | key>` | One of content options |
| `--video-cover <path\ | key>` | Required with `--video` |
| `--audio <path\ | key>` | One of content options |
--reply-in-thread | No | Reply inside the thread. The reply appears in the target message's thread instead of the main chat stream |
--idempotency-key <key> | No | Idempotency key; the same key sends only one reply within 1 hour |
--as <identity> | No | Identity type: bot only |
--dry-run | No | Print the request only, do not execute it |
Mutual exclusivity rule:--text,--markdown,--content, and--image/--file/--video/--audiocannot be used together. Media flags are also mutually exclusive with each other.
>
Video cover rule:--videomust be accompanied by--video-cover. Omitting--video-coverwhen using--videowill fail validation.--video-covercannot be used without--video.
Return Value
{
"message_id": "om_xxx",
"chat_id": "oc_xxx",
"create_time": "1234567890"
}Usage Scenarios
Scenario 1: Reply in the main chat stream
lark-cli im +messages-reply --message-id om_xxx --text "OK, I will handle it"The reply appears in the main chat stream and references the target message.
Scenario 2: Reply inside a thread
lark-cli im +messages-reply --message-id om_xxx --text "Let me take a look at this" --reply-in-threadThe reply appears in the target message's thread and does not show up in the main chat stream.
@Mention Format (text / post)
- @specific user:
<at user_id="ou_xxx">name</at> - @all:
<at user_id="all"></at>
Notes
--message-idmust be a valid message ID inom_xxxformat--contentmust be a valid JSON string--reply-in-threadis only meaningful in group chats--image/--file/--video/--audio/--video-coversupport local file paths; use relative paths within the current working directory. The shortcut automatically uploads the file first and then sends the reply- If the provided value starts with
img_orfile_, it is treated as an existing key and used directly - When using
--video,--video-coveris required as the video cover. Omitting--video-coverwith--videowill produce a validation error.--video-covercannot be used without--video - Failures return error codes and messages
--as botuses a tenant access token (TAT), and requires theim:message:send_as_botscope
im +messages-resources-download
Prerequisite: Read `../lark-shared/SKILL.md` first to understand authentication, global parameters, and safety rules.
Download image or file resources from a message. Resources are identified by the combination of message_id + file_key, both of which come directly from message content returned by im +chat-messages-list.
Note: read-only message commands render resource keys in message content, but they do not download binaries automatically. Use this command whenever you need to fetch the actual image/file bytes or save them to a specific path.
This skill maps to the shortcut: lark-cli im +messages-resources-download (internally calls GET /open-apis/im/v1/messages/{message_id}/resources/{file_key}).
Commands
# Download an image (save to the current directory)
lark-cli im +messages-resources-download --message-id om_xxx --file-key img_v3_xxx --type image
# Download a file
lark-cli im +messages-resources-download --message-id om_xxx --file-key file_v3_xxx --type file
# Specify the output path
lark-cli im +messages-resources-download --message-id om_xxx --file-key img_v3_xxx --type image --output ./photo.png
# Download as a bot
lark-cli im +messages-resources-download --message-id om_xxx --file-key img_v3_xxx --type image --as bot
# Preview the request without executing it
lark-cli im +messages-resources-download --message-id om_xxx --file-key img_v3_xxx --type image --dry-runParameters
| Parameter | Required | Description |
|---|---|---|
--message-id <id> | Yes | Message ID (om_xxx format) |
--file-key <key> | Yes | Resource key (img_xxx or file_xxx) |
--type <type> | Yes | Resource type: image or file |
--output <path> | No | Output path (relative paths only; .. traversal is not allowed; defaults to file_key as the file name) |
--as <identity> | No | Identity type: user (default) or bot |
--dry-run | No | Print the request only, do not execute it |
file_key Sources
Different resource markers in message content correspond to different file_key and type values:
| Message Type | Marker in Content | file_key Format | --type |
|---|---|---|---|
| Image | img_xxx | img_xxx | image |
| File | file_xxx | file_xxx | file |
| Audio | file_xxx | file_xxx | file |
| Video | file_xxx | file_xxx | file |
Usage Scenario
Scenario: Extract and download an image from a message
# Step 1: Fetch messages and find one containing an image
lark-cli im +chat-messages-list --chat-id oc_xxx
# In the response you see: { "msg_type": "image", "content": "{\"image_key\":\"img_v3_xxx\"}" }
# Step 2: Download the image
lark-cli im +messages-resources-download --message-id om_xxx --file-key img_v3_xxx --type imageCommon Errors and Troubleshooting
| Symptom | Root Cause | Solution |
|---|---|---|
| Download failed | file_key does not match the message_id | Make sure the file_key came from that message's content |
| Hit error code 234002 or 14005 | No permission, not missing API scope | no access to this chat or file was deleted — do not retry, return the error to the user |
| Permission denied | im:message:readonly is not authorized | Run auth login --scope "im:message:readonly" |
| File too large | Over the 100 MB limit | This is a Feishu API limitation and cannot be bypassed with this endpoint |
References
- lark-im - all message-related commands
- lark-shared - authentication and global parameters
im +messages-search
Prerequisite: Read `../lark-shared/SKILL.md` first to understand authentication, global parameters, and safety rules.
Search Feishu messages across conversations. This shortcut automatically performs a multi-step workflow: search for message IDs, batch fetch message details, then enrich the results with chat context.
User identity only (--as user). Bot identity is not supported.This skill maps to the shortcut: lark-cli im +messages-search (internally calls POST /open-apis/im/v1/messages/search + GET /open-apis/im/v1/messages/mget, then batch-fetches chat context).
Commands
# Search by keyword
lark-cli im +messages-search --query "project progress"
# Restrict search to a specific group chat
lark-cli im +messages-search --query "weekly report" --chat-id oc_xxx
# Filter by sender (comma-separated)
lark-cli im +messages-search --query "requirement" --sender ou_xxx,ou_yyy
# Filter by attachment type
lark-cli im +messages-search --query "report" --include-attachment-type file
# Filter by chat type (group / p2p)
lark-cli im +messages-search --query "progress" --chat-type group
# Filter by sender type (user / bot)
lark-cli im +messages-search --query "reminder" --sender-type bot
# Exclude bot senders
lark-cli im +messages-search --query "reminder" --exclude-sender-type bot
# Only messages that @me
lark-cli im +messages-search --query "announcement" --is-at-me
# Combined filters + time range
lark-cli im +messages-search --query "meeting" --sender ou_xxx --chat-type group --start "2026-03-13T00:00:00+08:00" --end "2026-03-20T23:59:59+08:00"
# Specific time range (ISO 8601)
lark-cli im +messages-search --query "release" --start "2026-03-01T00:00:00+08:00" --end "2026-03-10T00:00:00+08:00"
# Output format options
lark-cli im +messages-search --query "test" --format pretty
lark-cli im +messages-search --query "test" --format table
lark-cli im +messages-search --query "test" --format csv
# Pagination
lark-cli im +messages-search --query "test" --page-token <PAGE_TOKEN>
# Preview the request without executing it
lark-cli im +messages-search --query "test" --dry-runParameters
| Parameter | Required | Description |
|---|---|---|
--query <text> | No | Search keyword (may be empty when used with other filters) |
--chat-id <id> | No | Restrict to chat IDs, comma-separated (oc_xxx,oc_yyy) |
--sender <ids> | No | Sender open_ids, comma-separated (ou_xxx) |
--include-attachment-type <type> | No | Attachment filter: file / image / video / link |
--chat-type <type> | No | Chat type: group / p2p |
--sender-type <type> | No | Sender type: user / bot |
--exclude-sender-type <type> | No | Exclude messages from user or bot senders |
--is-at-me | No | Only return messages that mention @me |
--start <time> | No | Start time with local timezone offset required (e.g. 2026-03-24T00:00:00+08:00) |
--end <time> | No | End time with local timezone offset required (e.g. 2026-03-25T23:59:59+08:00) |
--page-size <n> | No | Page size (default 20, range 1-50) |
--page-token <token> | No | Pagination token for the next page |
--format <fmt> | No | Output format: json (default) / pretty / table / ndjson / csv |
--as <identity> | No | Identity type (defaults to and only supports user) |
--dry-run | No | Print the request only, do not execute it |
Core Constraints
1. Provide at least one filter whenever possible
All parameters are optional, but you should usually provide at least one filter (--query, --sender, --chat-id, etc.). Otherwise the search scope may be too broad and return low-signal results.
2. Two-step orchestration is automatic
The shortcut automatically performs:
1. The search API returns matching message_id values 2. The mget API fetches full message content for those message IDs in batch
The user does not need to manage the orchestration manually.
3. Conversation context is enriched automatically
In JSON output, each message automatically includes conversation context:
| Field | Description |
|---|---|
chat_type | Conversation type: p2p / group |
chat_name | Group name (for groups) or the other participant's name (for p2p chats) |
chat_partner | For p2p only: the other participant's open_id and name |
In pretty output, the chat column shows the chat name for groups, or "p2p" for direct messages.
Each message in JSON output contains:
| Field | Description |
|---|---|
message_id | Message ID |
msg_type | Message type: text, image, file, interactive, post, audio, video, system, etc. |
create_time | Creation time |
sender | Sender information (includes name for user senders) |
content | Message content |
chat_id | ID of the conversation the message belongs to |
deleted | Whether the message has been recalled (true = recalled) |
updated | Whether the message has been edited after sending |
mentions | Array of @mentions in the message; each item contains {id, key, name}. Present only when the message contains @mentions |
thread_id | Thread ID (omt_xxx) if the message has replies in a thread. Present only when replies exist |
4. Search results contain follow-up clues
In JSON output, each message includes chat_id and thread_id (when present). Use them with other shortcuts for deeper inspection:
# View the full message stream for the conversation that contains the search result
lark-cli im +chat-messages-list --chat-id <chat_id>
# View replies in the thread that contains the search result
lark-cli im +threads-messages-list --thread <thread_id>Resource Rendering
Search results reuse the same content formatter as other read commands. Image messages are rendered as placeholders such as [Image: img_xxx]; resource binaries are not downloaded automatically.
Use im +messages-resources-download if you need to fetch the underlying image or file bytes from a specific message.
AI Usage Guidance
Resolving chat_id from a chat name
When the user refers to a chat by name and you need its chat_id for the --chat-id filter, use `+chat-search` first:
# Step 1: Find the chat_id by name
lark-cli im +chat-search --query "<chat name keyword>" --format json
# Step 2: Use the chat_id to narrow down message search
lark-cli im +messages-search --query "keyword" --chat-id <chat_id>Do not use `im chats search` or `im chats list` — always use the `+chat-search` shortcut.
Work Summary / Report Generation
When the user asks you to summarize work, generate a weekly report, or compile activity from chat messages, you should paginate through all available results to get a complete picture. A single page is rarely enough for thorough summarization.
Strategy
1. Start with targeted filters — use --chat-id, --sender, --start, --end to narrow the scope as much as possible before paginating. 2. Fetch all pages — after the first call, check the output for has_more and page_token. If has_more is true, immediately issue the next call with --page-token <token>. Repeat until has_more is false or the results are clearly sufficient. 3. Accumulate before summarizing — collect all pages of messages first, then analyze and summarize. Do not summarize after the first page alone — you will miss important context. 4. Use `--format json` — JSON output includes has_more and page_token fields needed for pagination. pretty and table formats omit these fields and are not suitable for pagination. Note: pretty is human-readable (per-message rows); table is a flat key-value dump of the response envelope and is not human-readable for message lists.
Example: Weekly work summary from a project chat
# Page 1
lark-cli im +messages-search --query "" --chat-id oc_xxx --sender ou_me --start "2026-03-18T00:00:00+08:00" --end "2026-03-25T23:59:59+08:00" --page-size 50 --format json
# Page 2 (if has_more is true)
lark-cli im +messages-search --query "" --chat-id oc_xxx --sender ou_me --start "2026-03-18T00:00:00+08:00" --end "2026-03-25T23:59:59+08:00" --page-size 50 --page-token <token_from_page_1> --format json
# Continue until has_more is false, then summarize all collected messages.Key points
- Always paginate exhaustively for summary tasks. A single page of 20-50 messages is usually insufficient for a meaningful work summary.
- If the user does not specify a time range, default to the current week (Monday to today) for weekly reports, or ask for clarification.
- When summarizing, group messages by topic/thread rather than by chronological order for better readability.
Common Errors and Troubleshooting
| Symptom | Root Cause | Solution |
|---|---|---|
| Too few results | The time range is too narrow or the keyword is too specific | Expand the time range and try broader keywords |
| No results | Missing permission or no match | Confirm search:message is authorized and relax the filters |
| Permission denied | Search scope not authorized | Run auth login --scope "search:message" |
References
- lark-im - all message-related commands
- lark-im-threads-messages-list - inspect thread replies
- lark-shared - authentication and global parameters
im +messages-send
Prerequisite: Read `../lark-shared/SKILL.md` first to understand authentication, global parameters, and safety rules.
Send a message to a group chat or a direct message conversation. Only supports bot identity.
This skill maps to the shortcut: lark-cli im +messages-send (internally calls POST /open-apis/im/v1/messages).
Safety Constraints
Messages sent by this tool are visible to other people. Before calling it, you must confirm with the user:
1. The recipient (which person or which group) 2. The message content 3. The sending identity (bot only)
Do not send messages without explicit user approval.
When using --as bot, the message is sent in the app's name, so make sure the app has already been added to the target chat.
Commands
# Send plain text (--text is recommended; it is wrapped into JSON automatically)
lark-cli im +messages-send --chat-id oc_xxx --text "Hello"
# Equivalent manual JSON
lark-cli im +messages-send --chat-id oc_xxx --content '{"text":"Hello"}'
# Send to a direct message (pass open_id)
lark-cli im +messages-send --user-id ou_xxx --text "Hello"
# Send a rich-text message
lark-cli im +messages-send --chat-id oc_xxx --msg-type post --content '{"zh_cn":{"title":"Title","content":[[{"tag":"text","text":"Body"}]]}}'
# Send a local image (uploaded automatically before sending)
lark-cli im +messages-send --chat-id oc_xxx --image ./photo.png
# Or send directly with an existing image_key
lark-cli im +messages-send --chat-id oc_xxx --image img_xxx
# Send a local file (uploaded automatically before sending)
lark-cli im +messages-send --chat-id oc_xxx --file ./report.pdf
# Send a video (--video-cover is required as the cover)
lark-cli im +messages-send --chat-id oc_xxx --video ./demo.mp4 --video-cover ./cover.png
lark-cli im +messages-send --chat-id oc_xxx --video ./demo.mp4 --video-cover img_xxx
# Send audio
lark-cli im +messages-send --chat-id oc_xxx --audio ./voice.opus
# Use an idempotency key (same key sends only once within 1 hour)
lark-cli im +messages-send --chat-id oc_xxx --text "Hello" --idempotency-key my-unique-id
# Preview the request without executing it
lark-cli im +messages-send --chat-id oc_xxx --text "Test" --dry-runParameters
| Parameter | Required | Description |
|---|---|---|
--chat-id <id> | One of two | Group chat ID (oc_xxx) |
--user-id <id> | One of two | User open_id (ou_xxx) for direct messages |
--text <string> | One of seven content options | Plain text message (automatically wrapped as {"text":"..."} JSON) |
--markdown <string> | One of seven content options | Markdown text (auto-wrapped as post format with style optimization; image URLs auto-resolved) |
--content <json> | One of seven content options | Message content JSON string; format depends on msg_type |
| `--image <path\ | key>` | One of seven content options |
| `--file <path\ | key>` | One of seven content options |
| `--video <path\ | key>` | One of seven content options |
| `--video-cover <path\ | key>` | Required with `--video` |
| `--audio <path\ | key>` | One of seven content options |
--msg-type <type> | No | Message type (default text): text, post, image, file, audio, media, interactive, share_chat, share_user. Automatically set when using --text/--image/--file/--video/--audio |
--idempotency-key <key> | No | Idempotency key; the same key sends only one message within 1 hour |
--as <identity> | No | Identity type: bot only |
--dry-run | No | Print the request only, do not execute it |
Mutual exclusivity rule:--text,--markdown,--content, and--image/--file/--video/--audiocannot be used together. Media flags are also mutually exclusive with each other.
>
Video cover rule:--videomust be accompanied by--video-cover. Omitting--video-coverwhen using--videowill fail validation.--video-covercannot be used without--video.
content Format Reference
msg_type | Example content |
|---|---|
text | {"text":"Hello <at user_id=\"ou_xxx\">name</at>"} |
post | {"zh_cn":{"title":"Title","content":[[{"tag":"text","text":"Body"}]]}} |
image | {"image_key":"img_xxx"} |
file | {"file_key":"file_xxx"} |
audio | {"file_key":"file_xxx"} |
media | {"file_key":"file_xxx","image_key":"img_xxx"} (video; image_key is the cover from --video-cover — required) |
share_chat | {"chat_id":"oc_xxx"} |
share_user | {"user_id":"ou_xxx"} |
interactive | Card JSON (see Feishu interactive card documentation) |
Return Value
{
"message_id": "om_xxx",
"chat_id": "oc_xxx",
"create_time": "1234567890"
}@Mention Format (text / post)
- @specific user:
<at user_id="ou_xxx">name</at> - @all:
<at user_id="all"></at>
Notes
--chat-idand--user-idare mutually exclusive; you must provide exactly one--contentmust be a valid JSON string--image/--file/--video/--audiosupport local file paths; use relative paths within the current working directory. The shortcut automatically uploads the file first and then sends the message. You do not need to call a separate upload command manually- If the provided value starts with
img_orfile_, it is treated as an existing key and used directly - When using
--video,--video-coveris required as the video cover (image_key). Omitting--video-coverwith--videowill produce a validation error.--video-covercannot be used without--video - Failures return an error code and message
--as botuses a tenant access token (TAT) and requires theim:message:send_as_botscope- When sending as a bot, the app must already be in the target group or already have a direct-message relationship with the target user
im reactions
Prerequisite: Read `../lark-shared/SKILL.md` first to understand authentication, global parameters, and safety rules.
This reference is the shared annotation target for the IM reaction APIs:
im.reactions.createim.reactions.listim.reactions.deleteim.reactions.batch_query
It focuses on:
- What each reaction method does
- The request/response shape you need when calling the raw API commands
- The complete
emoji_typelist used in reaction payloads and filters
Important: These raw API commands accept structured input through--params '<json>'and--data '<json>'. They do not expose typed flags such as--message-idor--reaction-typedirectly.
Command Overview
| Method | HTTP | Path | Purpose |
|---|---|---|---|
im.reactions.create | POST | /open-apis/im/v1/messages/{message_id}/reactions | Add a reaction to one message |
im.reactions.list | GET | /open-apis/im/v1/messages/{message_id}/reactions | List reaction records on one message |
im.reactions.delete | DELETE | /open-apis/im/v1/messages/{message_id}/reactions/{reaction_id} | Delete one specific reaction record |
im.reactions.batch_query | POST | /open-apis/im/v1/messages/reactions/batch_query | Query reactions for multiple messages in one request |
Common Notes
message_idis always an IM message ID such asom_xxxreaction_idis the unique record ID returned after a reaction is addedreaction_type.emoji_typeis the enum-like emoji identifier used by both write and read APIs- Reaction APIs return reaction records, not only aggregated counts
- When the operator is a human user, the returned ID type may depend on
user_id_type
Inspect Schema
lark-cli schema im.reactions
lark-cli schema im.reactions.create --format pretty
lark-cli schema im.reactions.list --format pretty
lark-cli schema im.reactions.delete --format prettyIf your local build has already exposed the batch API in schema, also check:
lark-cli schema im.reactions.batch_query --format prettycreate
Add a reaction to one message.
lark-cli im reactions create \
--params '{"message_id":"om_xxx"}' \
--data '{"reaction_type":{"emoji_type":"SMILE"}}'Request
--params.message_id: required message ID--data.reaction_type.emoji_type: required emoji type
Response
{
"reaction_id": "ZCaCIjUBVVWSrm5L-3ZTw_xxx",
"operator": {
"operator_id": "ou_xxx",
"operator_type": "user"
},
"action_time": "1663054162546",
"reaction_type": {
"emoji_type": "SMILE"
}
}list
List reaction records on one message.
lark-cli im reactions list --params '{"message_id":"om_xxx"}'
lark-cli im reactions list --params '{"message_id":"om_xxx","reaction_type":"SMILE"}'
lark-cli im reactions list --params '{"message_id":"om_xxx","page_size":50}'
lark-cli im reactions list --params '{"message_id":"om_xxx","page_token":"<PAGE_TOKEN>"}'
lark-cli im reactions list --params '{"message_id":"om_xxx","user_id_type":"open_id"}'Request Parameters (--params)
| Parameter | Required | Description |
|---|---|---|
message_id | Yes | Message ID (om_xxx) |
reaction_type | No | Filter by one emoji type such as SMILE or LAUGH |
page_size | No | Number of records per page. Default is 20 |
page_token | No | Pagination token from the previous page |
user_id_type | No | Returned operator ID type when operator_type=user: open_id, union_id, or user_id |
Response Shape
{
"items": [
{
"reaction_id": "ZCaCIjUBVVWSrm5L-3ZTw_xxx",
"operator": {
"operator_id": "ou_xxx",
"operator_type": "user"
},
"action_time": "1663054162546",
"reaction_type": {
"emoji_type": "SMILE"
}
}
],
"has_more": true,
"page_token": "YhljsPiGfUgnVAg9urvRFd-BvSqRLxxxx"
}Top-Level Fields
| Field | Type | Meaning |
|---|---|---|
items | array<object> | Reaction records for the current page |
has_more | boolean | Whether more pages are available |
page_token | string | Token for the next page when has_more=true |
items[] Fields
| Field | Type | Meaning |
|---|---|---|
reaction_id | string | Unique ID of this reaction record |
operator | object | Identity of the user or app that added the reaction |
action_time | string | Unix timestamp in milliseconds |
reaction_type | object | Reaction payload. The key field is emoji_type |
operator Fields
| Field | Type | Meaning |
|---|---|---|
operator.operator_id | string | Operator ID. If operator_type=user, the returned ID type follows user_id_type; if operator_type=app, this is the app ID |
operator.operator_type | string | user or app |
delete
Delete one specific reaction record from one message.
lark-cli im reactions delete \
--params '{"message_id":"om_xxx","reaction_id":"ZCaCIjUBVVWSrm5L-3ZTw_xxx"}'Request
--params.message_id: required message ID--params.reaction_id: required reaction record ID
Response
The response shape is similar to create, and usually echoes:
reaction_idoperatoraction_timereaction_type.emoji_type
batch_query
Query reactions for multiple messages in one request.
lark-cli im reactions batch_query \
--params '{"user_id_type":"open_id"}' \
--data '{
"queries":[
{"message_id":"om_xxx"},
{"message_id":"om_yyy","page_token":"<PAGE_TOKEN>"}
],
"page_size_per_message":10,
"reaction_type":"LAUGH"
}'Request
--params
| Parameter | Required | Description |
|---|---|---|
user_id_type | No | Returned user ID type in operator info: open_id, union_id, or user_id |
--data
| Field | Required | Description |
|---|---|---|
queries | Yes | Array of target messages |
queries[].message_id | No | Message ID to query |
queries[].page_token | No | Continuation token for that message |
page_size_per_message | No | Max reactions returned per message |
reaction_type | No | Filter by one emoji type |
Response
The meta definition contains three top-level result groups:
| Field | Meaning |
|---|---|
success_msg_reaction_details | Per-message reaction detail records |
success_msg_reaction_counts | Per-message aggregated reaction counts |
fail_msg_reaction_details | Query failures for individual messages |
success_msg_reaction_details
Each message_reaction_items[] element includes:
reaction_idoperatoraction_timeemoji_type
success_msg_reaction_counts
Each aggregated count record includes:
message_idreaction_count[].reaction_typereaction_count[].count
fail_msg_reaction_details
Each failed message record includes:
message_idfail_reason
Supported fail_reason values from meta:
invalidinvalid_page_tokenno_permission
emoji_type Field
Reaction emoji identifiers are used in slightly different field names across the APIs:
im.reactions.create: request and response usereaction_type.emoji_typeim.reactions.list: request filter usesreaction_type, response usesreaction_type.emoji_typeim.reactions.delete: response usesreaction_type.emoji_typeim.reactions.batch_query: request filter uses top-levelreaction_type, detail results usemessage_reaction_items[].emoji_type, aggregated results usereaction_count[].reaction_type
Complete emoji_type List
The following list is synchronized from the official Feishu reaction emoji documentation:
- Source page:
https://open.feishu.cn/document/uAjLw4CM/ukTMukTMukTM/reference/im-v1/message-reaction/emojis-introduce - Markdown source:
https://open.feishu.cn/document/uAjLw4CM/ukTMukTMukTM/reference/im-v1/message-reaction/emojis-introduce.md
Current count in the fetched source: 185.
OK, THUMBSUP, THANKS, MUSCLE, FINGERHEART, APPLAUSE, FISTBUMP, JIAYI
DONE, SMILE, BLUSH, LAUGH, SMIRK, LOL, FACEPALM, LOVE
WINK, PROUD, WITTY, SMART, SCOWL, THINKING, SOB, CRY
ERROR, NOSEPICK, HAUGHTY, SLAP, SPITBLOOD, TOASTED, GLANCE, DULL
INNOCENTSMILE, JOYFUL, WOW, TRICK, YEAH, ENOUGH, TEARS, EMBARRASSED
KISS, SMOOCH, DROOL, OBSESSED, MONEY, TEASE, SHOWOFF, COMFORT
CLAP, PRAISE, STRIVE, XBLUSH, SILENT, WAVE, WHAT, FROWN
SHY, DIZZY, LOOKDOWN, CHUCKLE, WAIL, CRAZY, WHIMPER, HUG
BLUBBER, WRONGED, HUSKY, SHHH, SMUG, ANGRY, HAMMER, SHOCKED
TERROR, PETRIFIED, SKULL, SWEAT, SPEECHLESS, SLEEP, DROWSY, YAWN
SICK, PUKE, BETRAYED, HEADSET, EatingFood, MeMeMe, Sigh, Typing
Lemon, Get, LGTM, OnIt, OneSecond, VRHeadset, YouAreTheBest, SALUTE
SHAKE, HIGHFIVE, UPPERLEFT, ThumbsDown, SLIGHT, TONGUE, EYESCLOSED, RoarForYou
CALF, BEAR, BULL, RAINBOWPUKE, ROSE, HEART, PARTY, LIPS
BEER, CAKE, GIFT, CUCUMBER, Drumstick, Pepper, CANDIEDHAWS, BubbleTea
Coffee, Yes, No, OKR, CheckMark, CrossMark, MinusOne, Hundred
AWESOMEN, Pin, Alarm, Loudspeaker, Trophy, Fire, BOMB, Music
XmasTree, Snowman, XmasHat, FIREWORKS, 2022, REDPACKET, FORTUNE, LUCK
FIRECRACKER, StickyRiceBalls, HEARTBROKEN, POOP, StatusFlashOfInspiration, 18X, CLEAVER, Soccer
Basketball, GeneralDoNotDisturb, Status_PrivateMessage, GeneralInMeetingBusy, StatusReading, StatusInFlight, GeneralBusinessTrip, GeneralWorkFromHome
StatusEnjoyLife, GeneralTravellingCar, StatusBus, GeneralSun, GeneralMoonRest, MoonRabbit, Mooncake, JubilantRabbit
TV, Movie, Pumpkin, BeamingFace, Delighted, ColdSweat, FullMoonFace, Partying
GoGoGo, ThanksFace, SaluteFace, Shrug, ClownFace, HappyDragonReferences
- lark-im - all IM commands
- lark-shared - authentication and global parameters
- Official emoji doc:
https://open.feishu.cn/document/uAjLw4CM/ukTMukTMukTM/reference/im-v1/message-reaction/emojis-introduce
im +threads-messages-list
Prerequisite: Read `../lark-shared/SKILL.md` first to understand authentication, global parameters, and safety rules.
Fetch the reply message list inside a thread. When im +chat-messages-list returns messages that include a thread_id field, use this command to inspect all replies in that thread.
This skill maps to the shortcut: lark-cli im +threads-messages-list (internally calls GET /open-apis/im/v1/messages with container_id_type=thread to fetch thread messages).
Commands
# Get thread replies (ascending by time by default, table output)
lark-cli im +threads-messages-list --thread omt_xxx
# Reverse chronological order (latest first)
lark-cli im +threads-messages-list --thread omt_xxx --sort desc
# Control page size
lark-cli im +threads-messages-list --thread omt_xxx --page-size 20
# Pagination
lark-cli im +threads-messages-list --thread omt_xxx --page-token <PAGE_TOKEN>
# Output format options
lark-cli im +threads-messages-list --thread omt_xxx --format pretty
lark-cli im +threads-messages-list --thread omt_xxx --format table
lark-cli im +threads-messages-list --thread omt_xxx --format csv
# View as a bot
lark-cli im +threads-messages-list --thread omt_xxx --as bot
# Preview the request without executing it
lark-cli im +threads-messages-list --thread omt_xxx --dry-runParameters
| Parameter | Required | Description |
|---|---|---|
--thread <id> | Yes | Thread ID (om_xxx or omt_xxx format) |
--sort <order> | No | Sort order: asc (default) / desc |
--page-size <n> | No | Number of items per page (default 50, range 1-500) |
--page-token <token> | No | Pagination token for the next page |
--format <fmt> | No | Output format: json (default) / pretty / table / ndjson / csv |
--as <identity> | No | Identity type: user (default) / bot |
--dry-run | No | Print the request only, do not execute it |
Core Constraints
1. Source of thread_id
thread_id (omt_xxx or om_xxx) comes from the thread_id field in results returned by im +chat-messages-list or im +messages-search. Do not guess a thread ID. Fetch messages first and use the returned value.
2. No time filtering support
Thread messages do not support start_time / end_time filtering because of Feishu API limitations. Use pagination and sort order to control the scope.
3. Pagination (has_more / page_token)
- When the result includes
has_more=true, usepage_tokento fetch the next page - If you need the complete thread, keep paginating; if you only need an overview, the first page is often enough
4. Recommended expansion strategy
| Scenario | Recommended Parameters |
|---|---|
| Quickly inspect recent replies | --sort desc --page-size 10 |
| Read the full thread in chronological order | --sort asc --page-size 50, then paginate as needed |
| Just confirm whether replies exist | --sort desc --page-size 1 |
Usage Scenarios
Scenario 1: Expand a thread discovered in group messages
# Step 1: Fetch group messages and find one that contains thread_id
lark-cli im +chat-messages-list --chat-id oc_xxx
# Step 2: Extract thread_id from the JSON output and fetch thread replies
lark-cli im +threads-messages-list --thread omt_xxxScenario 2: Paginate through a long thread
# First page
lark-cli im +threads-messages-list --thread omt_xxx
# If has_more=true is returned, continue with page_token
lark-cli im +threads-messages-list --thread omt_xxx --page-token <PAGE_TOKEN>Resource Rendering
Thread replies are rendered into human-readable text. Image messages appear as placeholders such as [Image: img_xxx]; resource binaries are not downloaded automatically.
Other resource types (files, audio, video) still need to be downloaded manually through im +messages-resources-download. See lark-im-messages-resources-download.
Common Errors and Troubleshooting
| Symptom | Root Cause | Solution |
|---|---|---|
| "Invalid thread ID format" | thread_id does not start with om_ or omt_ | Use a valid om_xxx or omt_xxx value |
| Empty thread result | Wrong thread_id or no replies in the thread | Confirm the thread_id came from im +chat-messages-list output |
| Permission denied | The user is not authorized or is not a conversation member | Make sure OAuth authorization is complete and the identity is a chat member |
References
- lark-im - all message-related commands
- lark-im-chat-messages-list - fetch conversation messages (source of
thread_id) - lark-shared - authentication and global parameters