SuperAPI AI Directory

feishu-cli-chat

Office & productivity

View repository

Updated 10-15 16:36

About this skill

Feishu conversation browsing and management

This skill handles "reading chat history / managing groups / message interaction". Sending new messages goes through feishu-cli-msg; building cards goes through feishu-cli-card。

Which path to choose

Scenario Which path
View group messages within a time window (including topic replies, name resolution, card parsing) scripts/fetch_chat_history.py(one command does it all)
View the latest page of group chat messages (v1.27.1+ automatically expands all topics by default) msg history single call
View private chat history msg history --user-email or --user-id
Find group msg search-chats --query
View a single message / merged forward msg get / msg mget
View all replies in a topic msg thread-messages <thread_id>
Search messages by keyword search messages(belongs to feishu-cli-search)
Group member management, change group name chat update / chat member ...
Reaction / Pin / Delete msg reaction / msg pin / msg delete

Authentication

Distinguished by command type:

  • Read type(msg history/list/get/mget/thread-messages/resource-download): after login, automatically loads User Token from ~/.feishu-cli/token.json , falls back to App Token if not logged in (requires the Bot to be in the group).External group Bots are usually not in the group, reading external groups requires login first:
    feishu-cli auth check --scope "im:message:readonly im:message.group_msg:get_as_user"
    feishu-cli auth login --domain chat --recommend
    
  • User Token required(reaction add/remove/list、pin/unpin/pins、search-chats、chat get/update/delete、chat member list/add/remove): errors out directly if not logged in.
  • Write type · default Bot identity(chat create、chat link): defaults to App Token, no login required; when explicitly --user-access-token switches to User (created as the person themselves).
  • msg delete: defaults to App Token, used for the Bot to recall messages it sent within 24 hours; when passing --user-access-token or the environment variable, the admin recall scenario can be used.

End-to-end: pull the complete chat history for a time window

The most common need—"pull out all messages from group X in the last 24 hours"—involves pagination, topic expansion, name resolution, recalled messages, rich text, and card rendering at the same time. Each of these steps has more than one pitfall (see references/output-quirks.md), a single CLI cannot solve it all, so it is wrapped into a script:

# 默认最近 24 小时
python3 skills/feishu-cli-chat/scripts/fetch_chat_history.py oc_xxxxxxxx --since 24h

# 自定义时间窗 / 输出目录 / Bot 显示名
python3 skills/feishu-cli-chat/scripts/fetch_chat_history.py oc_xxxxxxxx \
    --start 2026-05-20T00:00:00 --end 2026-05-22T00:00:00 \
    --output-dir /tmp/my_chat \
    --bot-name "你的 Bot 显示名"

# 不展开线程(更快,但话题群会丢回复)
python3 skills/feishu-cli-chat/scripts/fetch_chat_history.py oc_xxx --since 24h --no-thread

Output 4 files to --output-dir(default /tmp/lark_chat/):

File Content
history.json Main message raw JSON + partial sender_names returned by Feishu
threads.json Each thread_id → complete reply list
names.json Merged open_id / app_id → name mapping
timeline.txt Readable timeline: main messages in ascending order + thread replies indented by 4 spaces (└─ marker)

Default script behavior:

  1. msg history uses ByCreateTimeAsc + start-time + end-time, paginates by page_token until has_more=false;
  2. collects all non-empty thread_id, calls msg thread-messages for each tid to expand (does not pass -o json, because it is JSON by default and has anti-error added);
  3. Three-level fallback for name resolution:mentions[].name → sender_names API field → user info call (external users will get 41050, silently skipped);
  4. Bot app_id(cli_xxx) mapped separately to --bot-name the provided name;
  5. Handle simultaneously during rendering: recalled messages (content is a string, not JSON), dual post structure, system template placeholders, interactive v2 card recursion.

If the script is unusable, see the "manually pull group messages" section below, understand what each step does, then fall back to jq + bash.

Single call: common read commands

# 群聊一页历史(v1.27.1+ 默认自动展开线程:一次拉根 + 所有话题回复)
feishu-cli msg history --container-id oc_xxx --container-id-type chat --page-size 50 -o json

# 关闭自动展开(仅拉根消息,更快)
feishu-cli msg history --container-id oc_xxx --container-id-type chat \
    --page-size 50 --expand-threads=false -o json

# 调整展开规模(默认 per=50, total=500,与 lark-cli 对齐)
feishu-cli msg history --container-id oc_xxx --container-id-type chat \
    --threads-per-page 30 --threads-total-limit 300 -o json

# 私聊:邮箱或 open_id 自动反查 P2P chat_id
feishu-cli msg history --user-email user@example.com --page-size 50 -o json
feishu-cli msg history --user-id ou_xxx --page-size 50 -o json

# 时间窗内全部消息(升序 + 翻页)
feishu-cli msg history --container-id oc_xxx --container-id-type chat \
    --start-time $(date -v-24H +%s) --end-time $(date +%s) \
    --sort-type ByCreateTimeAsc --page-size 50 -o json

# 单条 / 批量消息详情
feishu-cli msg get <message_id> -o json
feishu-cli msg mget --message-ids <id1,id2>

# 话题回复(注意:thread-messages 不接受 -o json,默认就是 JSON 输出)
feishu-cli msg thread-messages <thread_id> --page-size 50 --sort ByCreateTimeAsc

JSON output with automatic thread expansion (v1.27.1+)

msg history -o json Three new top-level fields are added, aligned with the official lark-cli +chat-messages-list :

Field Description
thread_replies {thread_id: [reply, ...]}, ASC order, excluding the root message
thread_has_more {thread_id: true} indicates that this thread has not been fully pulled within the threads-per-page limit
thread_replies_card_texts card_texts extraction for interactive cards within the thread

sender_names The field simultaneously merges mentions names from three sources: the main message + merge_forward + thread_replies, significantly improving the name resolution rate for external users (measured in a topic group: from 8% → 42%).

Senders still unresolved are usually真正跨租户外部用户且本话题内无人 @过他——This is a Feishu OpenAPI limitation; contact basic_batch does not return it, and the official lark-cli cannot get it either.

Search and locate

feishu-cli msg search-chats --query "项目群" -o json   # 搜群
feishu-cli search messages "关键词" --chat-type p2p_chat -o json
feishu-cli search messages "关键词" --chat-ids oc_xxx -o json

Searching messages belongs to feishu-cli-search; this skill calls it incidentally during reading tasks.

Message interaction

feishu-cli msg reaction add <message_id> --emoji-type THUMBSUP
feishu-cli msg reaction remove <message_id> --reaction-id <reaction_id>
feishu-cli msg reaction list <message_id>

feishu-cli msg pin <message_id>
feishu-cli msg unpin <message_id>
feishu-cli msg pins --chat-id <chat_id>

feishu-cli msg delete <message_id>                                  # Bot 自撤回
feishu-cli msg delete <message_id> --user-access-token u-xxx        # 管理员撤回

Group chat management

feishu-cli chat get oc_xxx                          # 外部群可能 232033(看下方"外部群操作")
feishu-cli chat update oc_xxx --name "新群名"
feishu-cli chat member list oc_xxx                  # 默认 auto;外部群推荐 --as bot
feishu-cli chat member add oc_xxx --id-list ou_xxx,ou_yyy
feishu-cli chat member remove oc_xxx --id-list ou_xxx
feishu-cli chat create --name "项目群" --user-ids ou_xxx,ou_yyy
feishu-cli chat delete oc_xxx

chat member list/add/remove supports --as bot|user|auto:

  • auto(default): User Token preferred, fallback to Bot Token
  • bot: force Bot Token,recommended for external groups(precondition: the App has enabled "external sharing capability" + the Bot is in the group)
  • user: force User Token

External group operations (must-read)

Whenever you encounter 232033 errors or want to pull the complete member list of an external group,read first references/external-chat.md。

New in v1.27.2+:

  • msg history supports the --as bot|user|auto flag (default auto = User preferred, fallback to Bot)
  • msg history automatically pulls a chat member list once for a group chat container, with the result attached at the top level in the chat_members field
    • The field value is the [{member_id, member_id_type, name, tenant_key}, ...] complete member list (including group nicknames)
    • There is also a chat_members_note hint field telling the Agent how to use it (to avoid mismatches)
  • msg history For each items[*] output, inject the sender_name field, eliminating the need to look up the sender_names dictionary
  • chat member list/add/remove all support --as bot|user|auto
  • Error code translation:chat get/update/delete/link/member when the command receives 232033/232011/232006, automatically print a Chinese solution

⚠️ Major pitfall: in external groups, chat_members[*].member_id and items[*].sender.id aredifferent namespaces, neveruse member_id to look up the sender's name. See references/external-chat.md the "Major pitfall" section.

Pull the complete member list of an external group (typical usage)

# 切到对外共享 App + Bot Token,从 msg history 顺带拉
FEISHU_APP_ID=cli_xxx FEISHU_APP_SECRET=xxx \
feishu-cli msg history --container-id oc_xxx --container-id-type chat \
  --page-size 1 --as bot --expand-threads=false -o json \
  | jq '.chat_members[] | select(.tenant_key != "<my_tenant>") | .name'
# → 输出所有外部商家名字(即群昵称),可直接喂给名字规范检查脚本

In one sentence: for external groups (external=true), "group info/members/config" APIs are disabled by default and require:

  1. The App has enabled "external sharing capability" (Feishu Open Platform → App → Credentials & Basic Info)
  2. This App's Bot has joined this group

If you have another App with external sharing capability enabled, just switch temporarily:

# 临时切 App(不写盘)
FEISHU_APP_ID=cli_对外共享App \
FEISHU_APP_SECRET=xxx \
feishu-cli chat member list oc_xxx --as bot

The returned name field is the user'sgroup nickname in that group(if not set, falls back to the global name), can be used directly for scenarios such as name specification checks.

Determine whether the chat is an external group:feishu-cli msg search-chats --query "..." -o json look at the returned external field.

For the full path/error codes/troubleshooting, see references/external-chat.md。

Pitfall quick reference (important)

Glance over this before writing code, otherwise you can easily get stuck for 30 minutes. For the detailed version, see references/output-quirks.md。

Pitfall One-sentence workaround
thread-messages adding -o json throws an error Do not pass; it is JSON output by default
thread-messages returns PascalCase Use d.get("items") or d.get("Items") to support both sets of keys
history time in seconds,thread-messages time in milliseconds start_sec vs start_sec * 1000, pass them respectively
Recalled message body.content is a literal string try: json.loads(...) wrap it, and on failure display it directly as a string
post content has two structures Support both {zh_cn:{title,content}} and flat {title,content}
system message template contains {from_user} placeholder Fill with other fields of the same object (join list with commas)
Bot sender cli_xxx ≠ sender_names in ou_xxx map separately to a known bot name
External group chat get/member list/... 232033 Required reading references/external-chat.md; switch to an App with external sharing enabled + --as bot
Cross-enterprise user info 41050 silently skipped, rely on mentions[].name as a fallback
msg history does not expand threads by default Topic groups must additionally call thread-messages to expand, otherwise replies are lost

Name reverse-resolution strategy

In external groups, the Feishu backend does not return names for most senders. Sorted by reliability + cost:

  1. mentions[](carried by the message):{"id":"ou_xxx","id_type":"open_id","name":"张三","key":"@_user_1"}, can also use key to replace the @_user_N placeholder in text messages.Not subject to external tenant isolation restrictions, preferred.
  2. sender_names(top level of history/thread-messages): a subset of Feishu reverse resolution, low coverage, use as a starting point.
  3. user info <ou_xxx>: cross-enterprise users always return 41050 no user authority error, almost all external groups hit this, silently skipped.
  4. Bot cli_xxx: map separately to a bot name you know in advance (the script's --bot-name)。

Output handling

  1. Dump JSON to a temporary file before analyzing, to avoid long messages flooding the screen;
  2. the text content is in body.content , parse the JSON string by msg_type (except recalled messages, see above);
  3. mentions the field contains both the open_id → name mapping + @_user_N key → name mapping, more complete than sender_names , prefer it.

Card messages (interactive)

msg history by default includes --card-content-type user, which yields v2 schema JSON + the extracted card_texts. The script already covers v2 schema recursion (column_set / form / collapsible_panel / action / button / img / note), for manual parsing see references/output-quirks.md §8.

When you need the "original cardDSL" or the "OAPI rendered version", switch:

feishu-cli msg history --container-id oc_xxx --card-content-type raw      -o json   # 平台内部 cardDSL
feishu-cli msg history --container-id oc_xxx --card-content-type rendered -o json   # OAPI 渲染版/降级版

Reference

  • scripts/fetch_chat_history.py — an executable script for end-to-end group message fetching
  • references/output-quirks.md — all API quirks such as JSON keys / time units / error codes / card parsing