SuperAPI AI Directory

feishu-cli-card

Office & productivity

View repository

Updated 10-16 05:47

About this skill

Feishu V2 Card Building Skill

Responsibility: Turn the user's intent → build a visually rich v2 card JSON, write it to /tmp/<name>-card.json, then hand it to feishu-cli msg send --msg-type interactive --content-file to send.

Only do v2: All output must start with "schema": "2.0" , using body to wrap elements. For v1-related migration, see references/v2-vs-v1.md。

1. Decision tree (choose a template in 30 seconds)

用户意图 → 推荐模板 → header.template
├─ 通知 / 公告 / 信息同步      → notification.json      → blue
├─ 操作完成 / 构建成功 / 交付   → success-report.json    → green
├─ 告警 / 故障 / 错误           → alert.json             → red / carmine
├─ 审批请求 / 待办 / 确认       → approval.json          → orange
├─ 数据展示 / 报表 / 指标       → data-dashboard.json    → purple / indigo
├─ 长文摘要 / 文章总结 / 多章节 → article-summary.json   → blue / wathet
└─ AI 流式输出 / 生成中         → llm-streaming.json     → blue + streaming_mode

When unsure, use notification.json as a fallback(blue, generic structure, broadest coverage).

The user didn't specify the exact scenario but the content has structure (multiple fields/links/charts/status metrics)—also prefer a card over plain text.

2. v2 minimal runnable skeleton

{
  "schema": "2.0",
  "config": {
    "update_multi": true,
    "enable_forward": true,
    "width_mode": "fill"
  },
  "header": {
    "template": "blue",
    "title": { "tag": "plain_text", "content": "标题" },
    "subtitle": { "tag": "plain_text", "content": "可选副标题" }
  },
  "body": {
    "direction": "vertical",
    "vertical_spacing": "medium",
    "elements": [
      { "tag": "markdown", "content": "**正文**\n\n支持完整 CommonMark + `<font>`/`<at>`/`<link>` 等 HTML 标签" }
    ]
  }
}

Four essential blocks:

  1. schema: "2.0" — top-level declaration, required in v2
  2. config — global behavior:update_multi v2 only supports true;width_mode use fill/compact/omitted (default 600px)
  3. header — title area:template sets the theme color,title is required,subtitle is optional
  4. body.elements — component array, rendered in order from top to bottom

3. Workflow (6 steps)

  1. Choose template: Determine templates/<name>.jsonaccording to the decision tree, and Read it in as the starting point
  2. Fill in content: Replace all __PLACEHOLDER__ placeholders (title, field values, URL, data, personnel ID)
  3. Choose color scheme:header.template Pick according to the scenario (see references/design.md color matrix), markdown <font> no more than 3 accent colors
  4. Validate:
    • python -m json.tool /tmp/xxx-card.json passes JSON parsing
    • Check for v2-forbidden fields (see Section 6 prohibited areas)
  5. Save to disk: Write to /tmp/<name>-card.json(reuse existing paths to avoid pollution)
  6. Send:
    feishu-cli msg send \
      --receive-id-type email \
      --receive-id user@example.com \
      --msg-type interactive \
      --content-file /tmp/<name>-card.json
    
    Returns on success message_id: om_xxx。

4. Component quick reference matrix

Display type(view only, no interaction):

tag Purpose Typical properties
markdown Rich text body content + text_size + text_align + icon
div Multi-column key-value with fields fields: [{is_short, text}]
hr Divider No other properties
img Single image img_key + alt
img_combination Image combination (grid/carousel) combination_layout + img_list
chart VChart chart chart_spec + aspect_ratio + color_theme
person Single person user_id + show_name + show_avatar
person_list Person list persons: [{user_id}]
table Table rows + columns + row_height

Container type(holds other components):

tag Purpose Key properties
column_set Horizontal columns flex_mode + horizontal_spacing + columns
collapsible_panel Collapsible panel expanded + header.{title,icon,background_color} + elements
form Form container name + elements(collect a batch of inputs then submit all at once)
interactive_container Interactive container Unified styling and click interaction, wraps multiple components

Interactive type(clickable/inputtable):

tag Purpose Key properties
button Button type + text + `behaviors: [{type: "open_url"
input Single-line input name + placeholder + default_value
textarea Multi-line input Same as input, multiple rows
select_static Dropdown single-select options: [{text, value}]
multi_select_static Dropdown multi-select Same as above,selected_values array
date_picker Date initial_date + placeholder
picker_time Time Same as above
picker_datetime Date-time Same as above
overflow Collapsible menu (⋯ button) options: [{text, value, url}]

Complete fields, nested rules, pitfalls → read references/components.md。

5. The three axes of beauty (overview)

5.1 Color

  • header.template Choose one primary color from the 13 options (see design.md color matrix):
    • blue = notification / information | green = success | orange = warning | red = error | grey = archive | purple = brand/data
  • For inline color in markdown, only use <font color='...'> to highlight key numbers,a card should use no more than 3 primary colors
  • Use grey to reduce the visual weight of secondary text

5.2 Layout rhythm

  • body.vertical_spacing Set medium(8px) as the default rhythm
  • Important information → large (12px) for more separation
  • Compact rows (such as status pills) → small (4px)
  • Scenario switch → insert hr as a hard divider

5.3 Element density (Z-shaped visual path)

顶部  │ header(标题 + 副标题 + 最多 3 个 text_tag)
中上  │ markdown 摘要(核心结论,带 1-2 处 <font> 强调)
中部  │ div.fields(2×2 关键指标) 或 column_set(左图右文)
中下  │ chart / table(数据可视化)
底部  │ collapsible_panel(折叠次要信息)
操作区│ column_set 里放 2-3 个 button(primary 放中间)

See details in references/design.md。

6. Forbidden zones (v2 strict validation, unknown attributes will error!)

❌ Forbidden ✅ Replacement Reason
Top-level elements placed directly Put into body.elements v2 must be wrapped in body
"tag": "action" interactive module Place buttons directly in body.elements, use spacing for spacing v2 deprecates the action module
"tag": "note" note component markdown + <font color='grey'> + text_size: "notation" v2 deprecates note
config.wide_screen_mode config.width_mode: "fill" v1 legacy attribute
config.update_multi: false update_multi: true(or omit) v2 only supports true
i18n_elements i18n_content(local multilingual) v2 does not support global multilingual
hex color #FF0000 color enum red or rgba(255,0,0,1) v2 does not recognize hex
[text]($urlVal) differentiated jump <link icon='' url='' pc_url='' ...> tag removed in v2
stretch_without_padding full-width image margin: "0 -12px" negative margin removed in v2
flex_mode: "fixed" flex_mode: "none" or "bisect"/"trisect" enum does not include fixed
column.width: 1/2/3 number width: "weighted" + weight: 1~5 column width syntax changed
collapsible_panel.header.padding: "4px 8px" two values Write as "4px 8px 4px 8px" four values The server strictly validates header padding and only accepts a single value or four values

Fallback check: after writing the JSON, search for note|action|wide_screen_mode, and change any that appear.

7. Complete example (ready to copy)

{
  "schema": "2.0",
  "config": { "update_multi": true, "enable_forward": true, "width_mode": "fill" },
  "header": {
    "template": "blue",
    "title": { "tag": "plain_text", "content": "🚀 本周迭代完成" },
    "subtitle": { "tag": "plain_text", "content": "2026-04-17 发版报告" }
  },
  "body": {
    "direction": "vertical",
    "vertical_spacing": "medium",
    "elements": [
      { "tag": "markdown", "content": "共交付 **12 个功能** / **修复 8 个 Bug**,<font color='green'>全部测试通过</font>。" },
      { "tag": "hr" },
      {
        "tag": "div",
        "fields": [
          { "is_short": true, "text": { "tag": "lark_md", "content": "**📦 版本**\n`v2.3.0`" } },
          { "is_short": true, "text": { "tag": "lark_md", "content": "**⏱ 耗时**\n5 天" } },
          { "is_short": true, "text": { "tag": "lark_md", "content": "**👥 参与**\n7 人" } },
          { "is_short": true, "text": { "tag": "lark_md", "content": "**✅ 状态**\n<font color='green'>已上线</font>" } }
        ]
      },
      {
        "tag": "collapsible_panel",
        "expanded": false,
        "header": {
          "title": { "tag": "markdown", "content": "**📋 详细变更清单(点击展开)**" },
          "background_color": "grey",
          "padding": "4px 8px 4px 8px",
          "icon": { "tag": "standard_icon", "token": "down-small-ccm_outlined", "size": "16px 16px" },
          "icon_position": "right",
          "icon_expanded_angle": -180
        },
        "elements": [
          { "tag": "markdown", "content": "- 新增卡片 V2 构造能力\n- 支持流式更新\n- 修复图表渲染问题" }
        ]
      },
      {
        "tag": "column_set",
        "flex_mode": "none",
        "horizontal_spacing": "8px",
        "columns": [
          {
            "tag": "column", "width": "weighted", "weight": 1, "vertical_align": "center",
            "elements": [{
              "tag": "button",
              "text": { "tag": "plain_text", "content": "📖 发版文档" },
              "type": "primary", "width": "fill",
              "behaviors": [{ "type": "open_url", "default_url": "https://example.com/release" }]
            }]
          },
          {
            "tag": "column", "width": "weighted", "weight": 1, "vertical_align": "center",
            "elements": [{
              "tag": "button",
              "text": { "tag": "plain_text", "content": "📊 监控大盘" },
              "type": "default", "width": "fill",
              "behaviors": [{ "type": "open_url", "default_url": "https://example.com/monitor" }]
            }]
          }
        ]
      },
      { "tag": "markdown", "content": "<font color='grey'>📡 由 feishu-cli-card 技能生成 · v2 schema 2.0</font>" }
    ]
  }
}

8. Send handoff

# 方式 1:直接发给默认接收人(env FEISHU_OWNER_EMAIL 或 user@example.com)
feishu-cli msg send \
  --receive-id-type email \
  --receive-id user@example.com \
  --msg-type interactive \
  --content-file /tmp/my-card.json

# 方式 2:发群
feishu-cli msg send --receive-id-type chat_id --receive-id oc_xxx \
  --msg-type interactive --content-file /tmp/my-card.json

# 方式 3:带本地图片(--upload-images 自动上传 markdown 里的 ./img.png)
feishu-cli msg send --receive-id-type email --receive-id ... \
  --msg-type interactive --content-file /tmp/my-card.json --upload-images

Success indicator: returns 消息 ID: om_xxxxx. If it reports content format error or invalid element, go back to the forbidden zone table in section 6 and check item by item.


Deep resources

Read as needed:

File When to read Scale
references/components.md Need to use a component but can't remember the fields / need to look up nesting rules / need to look up color enums ~400 lines, with TOC
references/design.md Need to determine color scheme / layout rhythm / scenario → template mapping ~250 lines
references/v2-vs-v1.md Have v1 legacy code to migrate / need to explain why the user's v1 example doesn't work ~120 lines
references/vchart-quickref.md Need to draw charts (bar/pie/line/radar/gauge, etc.) ~180 lines
templates/<name>.json 7 out-of-the-box skeletons; always pick one first instead of writing from scratch each 80-150 lines

Boundary with feishu-cli-msg

  • feishu-cli-card (this skill):Construct v2 card JSON. The responsibility is "write it beautifully."
  • feishu-cli-msg:Send messages (various types, including interactive). The responsibility is "get it delivered."

Construction complete → call msg to send. The two are decoupled; do not write them mixed together.