feishu-card(スキーマ 2.0)
重要なルール
- すべてのカードは スキーマ 2.0 を使用し、要素は
body.elements[]に配置すること(トップレベルのelements[]ではない) - カード送信時は
--as bot、--msg-type interactive、--contentに JSON 文字列を渡すこと - カード内での @メンションは
<at id="ou_xxx">名前</at>を使用すること(<at user_id>ではない) - JSON 2.0 では
actionコンテナは不要。button はbody.elementsに直接配置し、インタラクションにはbehaviors配列を使用する - まず「思考中」カードを送信して
message_idを取得し、Claude が回答したら PATCH でその場で更新し、画面のスクロールを防ぐ - スキーマ 2.0 では
noteタグはサポートされていない(エラー 200861)。注釈はdiv + lark_md(<font color=grey>注釈テキスト</font>)を使用すること - カード JSON の作成は Python heredoc またはファイル書き込みで行うこと。
$(python3 -c "...")は禁止 — 内容にバッククォートや特殊文字が含まれる場合、bash が構文エラーになる
トップレベル構造の完全フィールド
{
"schema": "2.0",
"config": {
"streaming_mode": false,
"enable_forward": true,
"update_multi": true,
"width_mode": "default"
},
"card_link": {
"url": "https://...",
"pc_url": "https://...",
"ios_url": "https://...",
"android_url": "https://..."
},
"header": { "...": "..." },
"body": {
"direction": "vertical",
"padding": "0px",
"elements": []
}
}
config フィールド
| フィールド | タイプ | デフォルト | 説明 |
|---|---|---|---|
streaming_mode | bool | false | ストリーミング更新状態(思考中プレースホルダー用) |
enable_forward | bool | true | カードの転送を許可 |
update_multi | bool | false | JSON 2.0 共有カードモード(複数人で同期更新する場合は true に設定) |
width_mode | string | default(600px) | compact(400px)/ fill(全幅レスポンシブ)/ default |
Header フィールド
{
"header": {
"title": {"tag": "plain_text", "content": "タイトル"},
"subtitle": {"tag": "plain_text", "content": "サブタイトル(オプション)"},
"template": "blue",
"icon": {
"tag": "standard_icon",
"token": "robot-outlined",
"color": "blue"
},
"text_tag_list": [
{"tag": "text_tag", "text": {"tag": "plain_text", "content": "New"}, "color": "blue"}
]
}
}
template 色:blue / wathet / turquoise / green / yellow / orange / red / carmine / violet / purple / indigo / grey
Feishu 色の列挙型クイックリファレンス
色の列挙型をサポートするすべてのフィールド(background_color、text_color、icon color など)は以下の形式を使用します。基本色名だけを使用することはできません(例:あるコンポーネントで "blue" を単独で使用するとエラーになる場合があります)。階層サフィックスを付ける必要があります。
| 色系 | 薄色(背景推奨) | 中間色 | 濃色(テキスト推奨) |
|---|---|---|---|
| 青 blue | blue-50 blue-100 blue-200 | blue-300~blue-500 | blue-600~blue-900 |
| 水色 wathet | wathet-50 wathet-100 wathet-200 | wathet-300~wathet-500 | wathet-600~wathet-900 |
| 青緑 turquoise | turquoise-50 turquoise-100 | turquoise-300~turquoise-500 | turquoise-600~turquoise-900 |
| 緑 green | green-50 green-100 green-200 | green-300~green-500 | green-600~green-900 |
| 黄緑 lime | lime-50 lime-100 | lime-300~lime-500 | lime-600~lime-900 |
| 黄 yellow | yellow-50 yellow-100 | yellow-300~yellow-500 | yellow-600~yellow-900 |
| 橙 orange | orange-50 orange-100 | orange-300~orange-500 | orange-600~orange-900 |
| 赤 red | red-50 red-100 | red-300~red-500 | red-600~red-900 |
| ピンク carmine | carmine-50 carmine-100 | carmine-300~carmine-500 | carmine-600~carmine-900 |
| 紫 purple | purple-50 purple-100 | purple-300~purple-500 | purple-600~purple-900 |
| 青紫 violet | violet-50 violet-100 | violet-300~violet-500 | violet-600~violet-900 |
| 藍 indigo | indigo-50 indigo-100 | indigo-300~indigo-500 | indigo-600~indigo-900 |
| 灰 grey | grey-00 grey-50 grey-100 | grey-300~grey-500 | grey-600~grey-1000 |
| 白 | white bg-white | — | — |
よく使う薄色背景のおすすめ(collapsible_panel、column 背景など):
blue-100 wathet-100 green-100 yellow-100
orange-100 red-100 purple-100 carmine-100
turquoise-100 violet-100 indigo-100 lime-100
コンポーネントクイックリファレンス
| tag | タイプ | 説明 |
|---|---|---|
div | コンテンツ | テキストブロック(plain_text / lark_md)、アイコン接頭辞サポート |
markdown | コンテンツ | プレーン Markdown テキスト(@は非対応。@は div+lark_md を使用) |
img | コンテンツ | 画像 |
table | コンテンツ | データテーブル(カードあたり最大5個、ネスト不可) |
hr | レイアウト | 区切り線 |
note | レイアウト | ❌ スキーマ2.0では廃止。div + lark_md + <font color=grey> を使用 |
column_set | コンテナ | 複数列レイアウト |
collapsible_panel | コンテナ | 折りたたみパネル |
button | インタラクション | ボタン(JSON 2.0では elements に直接配置、action コンテナは不要) |
input | インタラクション | テキスト入力(form 内で使用する必要あり) |
select_static | インタラクション | 静的ドロップダウンセレクター |
div(テキストブロック)
{
"tag": "div",
"text": {
"tag": "lark_md",
"content": "**太字** _斜体_ `コード`",
"text_size": "normal",
"text_color": "default",
"text_align": "left",
"lines": 3
},
"icon": {"tag": "standard_icon", "token": "robot-outlined", "color": "blue"}
}
text.tag:plain_text(プレーンテキスト)または lark_md(Markdown + @)
text_size:heading-0 / heading / normal(デフォルト)/ notation / x-small
text_align:left / center / right
img(画像)
{
"tag": "img",
"img_key": "img_xxx",
"alt": {"tag": "plain_text", "content": "ホバー説明"},
"title": {"tag": "plain_text", "content": "画像タイトル"},
"scale_type": "crop_center",
"size": "medium",
"corner_radius": "4px",
"preview": true
}
scale_type:crop_center / crop_top / fit_horizontal
size:stretch(全幅)/ large / medium / small / tiny / "300px 200px"(カスタム)
JSON 2.0 では
stretch_without_paddingはサポートされていません。全幅効果は負のマージンを使用してください
column_set(複数列レイアウト)
{
"tag": "column_set",
"flex_mode": "bisect",
"horizontal_spacing": "medium",
"background_style": "default",
"columns": [
{
"tag": "column",
"width": "weighted",
"weight": 1,
"vertical_align": "top",
"elements": [{"tag": "div", "text": {"tag": "plain_text", "content": "左列"}}]
},
{
"tag": "column",
"width": "weighted",
"weight": 1,
"elements": [{"tag": "div", "text": {"tag": "plain_text", "content": "右列"}}]
}
]
}
flex_mode:none(比率で圧縮)/ stretch(狭画面で縦並び)/ flow(自動折り返し)/ bisect(等幅2列)/ trisect(等幅3列)
horizontal_spacing:small(4px) / medium(8px) / large(12px) / extra_large(16px)
column.width:auto / weighted(weight 1-5と組み合わせて使用)/ "200px"
最大ネスト5層。列内には form コンテナと table は配置不可
collapsible_panel(折りたたみパネル)
{
"tag": "collapsible_panel",
"expanded": false,
"background_color": "default",
"header": {
"title": {"tag": "plain_text", "content": "クリックして展開"},
"background_color": "grey",
"icon": {"tag": "standard_icon", "token": "arrow-down-outlined"},
"icon_expanded_angle": -180
},
"elements": [
{"tag": "div", "text": {"tag": "plain_text", "content": "折りたたみコンテンツ"}}
]
}
table(データテーブル)
{
"tag": "table",
"page_size": 5,
"row_height": "low",
"freeze_first_column": false,
"header_style": {
"text_align": "left",
"text_size": "normal",
"background_style": "grey",
"bold": true
},
"columns": [
{"name": "name", "display_name": "名前", "data_type": "text", "width": "auto"},
{"name": "status", "display_name": "状態", "data_type": "options", "width": "120px"},
{"name": "count", "display_name": "数量", "data_type": "number",
"format": {"precision": 0, "separator": true}},
{"name": "ts", "display_name": "時間", "data_type": "date",
"format": "YYYY/MM/DD HH:mm"}
],
"rows": [
{"name": "山田太郎", "status": [{"name": "進行中", "color": "blue"}], "count": 42, "ts": 1700000000000}
]
}
data_type:text / lark_md / markdown / options / number / persons / date
row_height:low / middle / high / auto / "48px"(32-124px)
カードあたり最大5つのテーブル。ネスト不可
button(JSON 2.0)
{
"tag": "button",
"text": {"tag": "plain_text", "content": "確認"},
"type": "primary",
"size": "medium",
"width": "default",
"disabled": false,
"behaviors": [
{
"type": "callback",
"value": {"action": "confirm", "data": "payload"}
}
],
"confirm": {
"title": {"tag": "plain_text", "content": "再確認"},
"text": {"tag": "plain_text", "content": "この操作を実行してもよろしいですか?"}
}
}
type:default(灰)/ primary(青)/ danger(赤)/ text / primary_text / danger_text / primary_filled / danger_filled / laser
size:tiny / small / medium / large
behaviors[].type:callback(イベントトリガー)/ open_url(リンク遷移)
JSON 2.0 の変更点:
actionコンテナは不要。button は直接body.elementsまたはcolumn.elementsに配置。インタラクションには従来のvalueの代わりにbehaviorsを使用する
input(テキスト入力)
{
"tag": "input",
"name": "field_name",
"placeholder": {"tag": "plain_text", "content": "入力してください..."},
"default_value": "",
"input_type": "text",
"max_length": 200,
"required": false,
"disabled": false,
"label": {"tag": "plain_text", "content": "ラベル"},
"label_position": "top",
"width": "fill"
}
input_type:text / multiline_text / password
ユーザーが送信すると card.action.trigger イベントがトリガーされ、イベントには input_value が含まれる
@メンション構文
| メッセージタイプ | @人構文 | @全体 |
|---|---|---|
カード interactive lark_md | <at id="ou_xxx">名前</at> | <at id="all">全員</at> |
テキスト text / post | <at user_id="ou_xxx">名前</at> | <at user_id="all"></at> |
カード内 @メンション で検証済みの要素構造(div + lark_md を使用。生の markdown タグは使わない):
{
"tag": "div",
"text": {
"tag": "lark_md",
"content": "<at id=\"ou_xxx\">名前</at> メッセージ内容"
}
}
Markdown 構文クイックリファレンス(lark_md / markdown タグ内)
テキストスタイル
**太字** *斜体* ~~打ち消し線~~ `インラインコード`
色付きテキスト
<font color=red>赤色</font>
<font color=green>緑色</font>
<font color=grey>灰色</font>
<font color=blue>青色</font>
<font color=orange>橙色</font>
<font color=wathet>水色</font>
<font color=purple>紫色</font>
完全な色:red / green / grey / blue / orange / wathet / purple / yellow / turquoise / indigo / violet / lime
タグ / 数字バッジ
<text_tag color='red'>タグ</text_tag>
<number_tag>99</number_tag>
ローカライズ時間
<local_datetime millisecond='1700000000000' format_type='date_num'></local_datetime>
format_type:date_num(2023/11/15)/ date_full(2023年11月15日)/ datetime(時分秒含む)
見出し / リスト / 引用
# H1 ## H2 ### H3 #### H4 ##### H5 ###### H6
- 順序なし 1. 順序あり > 引用
コードブロック
```python
print("hello")
```
画像(Markdown 内)

テーブル(最大5行のデータ)
| 列1 | 列2 |
|-----|-----|
| A | B |
リンク
[テキスト](https://url) [電話](tel://13800138000)
区切り線 / 改行
--- または <hr>
<br/> または 改行2回(段落改行)
Emoji
⚠️ 厳格なルール
- 公式リストのキーのみ使用可能。収録されていないキー(例:
:WAITING:、:PROCESSING:)はプレーンテキストとしてレンダリングされるため、使用禁止。 - キーの大文字小文字は公式と完全に一致させる必要がある(例:
FireはFIREではない、TrophyはTROPHYではない、ShrugはSHRUGではない)。 <text_tag>内では:KEY:はレンダリングされない。Unicode絵文字(例:✅)を使用する必要がある。:KEY:はlark_mdの通常テキスト領域でのみ有効。
リリース通知でよく使う
:DONE: :OK: :THUMBSUP: :APPLAUSE:
:PARTY: :FIREWORKS: :MUSCLE: :THANKS:
:Trophy: :Fire: :Hundred: :CheckMark:
作業 & 状態
:LGTM: :OnIt: :OneSecond: :Get:
:ERROR: :CrossMark: :Pin: :Alarm:
:Loudspeaker: :OKR: :Yes: :No:
:HEADSET: :Typing: :MeMeMe: :Sigh:
:Lemon: :AWESOMEN: :VRHeadset: :YouAreTheBest:
:SALUTE: :HIGHFIVE: :FISTBUMP: :FINGERHEART:
:WAVE: :ThumbsDown:
表情 - ポジティブ
:SMILE: :LAUGH: :LOL: :LOVE:
:WINK: :PROUD: :WITTY: :JOYFUL:
:WOW: :BLUSH: :HUG: :BeamingFace:
:Delighted: :ThanksFace: :SaluteFace: :PRAISE:
:CLAP: :JIAYI: :FACEPALM: :YEAH:
表情 - ネガティブ / ふざけ
:CRY: :SOB: :ANGRY: :SHOCKED:
:Shrug: :THINKING: :DIZZY: :SLEEP:
:YAWN: :SICK: :SWEAT: :EMBARRASSED:
:SKULL: :RAINBOWPUKE: :PUKE: :ClownFace:
:ColdSweat: :SMUG: :SILENT: :TERROR:
:PETRIFIED: :BETRAYED: :WRONGED:
お祝い & 祝日
:PARTY: :FIREWORKS: :REDPACKET: :FORTUNE:
:FIRECRACKER: :XmasTree: :XmasHat: :Snowman:
:Pumpkin: :Mooncake: :MoonRabbit: :Partying:
:StickyRiceBalls: :JubilantRabbit: :LUCK:
:FullMoonFace: :GoGoGo: :HappyDragon:
アイテム & 食べ物
:ROSE: :HEART: :BEER: :CAKE:
:GIFT: :BOMB: :Fire: :Trophy:
:Coffee: :BubbleTea: :Drumstick: :Pepper:
:CUCUMBER: :CANDIEDHAWS: :Soccer: :Basketball:
:Music: :CLEAVER: :EatingFood: :LIPS:
状態表示(頻繁に使わないでください。状態シーンのみ)
:GeneralDoNotDisturb: :GeneralInMeetingBusy:
:StatusReading: :GeneralWorkFromHome:
:GeneralBusinessTrip: :StatusInFlight:
:GeneralSun: :GeneralMoonRest:
:StatusFlashOfInspiration: :Status_PrivateMessage:
:GeneralTravellingCar: :StatusBus:
Unicode Emoji(タイトル、text_tag 内、header subtitle で使用)
🎉 ✅ ❌ ⚠️ 🚀 📦 💬 ⏳ 🔔 📝 🛠️ 🔍 👋 🎯 💡 🌟
👥 📅 🤖 🏆 🔥 💯 📣 🎁 ☕ 🍺
推奨スタイル:タイトルには Unicode emoji を使用して視認性を高め、状態/フィードバックには Feishu の
:DONE::LGTM:などの専用構文を使用する
送信 / 返信 / 更新
グループに送信(新規メッセージ)
CARD=$(python3 -c "
import json
card = {
'schema': '2.0',
'header': {'title': {'tag': 'plain_text', 'content': 'タイトル'}, 'template': 'blue'},
'body': {'elements': [{'tag': 'markdown', 'content': '内容'}]}
}
print(json.dumps(card))
")
lark-cli im +messages-send \
--chat-id oc_xxx \
--msg-type interactive \
--content "$CARD" \
--as bot
指定メッセージに返信(message_id を取得して後続の更新に使用)
MSG_ID=$(lark-cli im +messages-reply \
--message-id om_xxx \
--msg-type interactive \
--content "$CARD" \
--as bot \
--jq '.data.message_id')
thread に返信(メインのチャットフローに表示しない)
lark-cli im +messages-reply \
--message-id om_xxx \
--msg-type interactive \
--content "$CARD" \
--reply-in-thread \
--as bot
重複送信防止(1時間以内に同じ key では1回のみ送信)
lark-cli im +messages-send \
--chat-id oc_xxx \
--msg-type interactive \
--content "$CARD" \
--idempotency-key "deploy-654.0-notify" \
--as bot
その場でカードを更新(PATCH)
PAYLOAD=$(jq -n --argjson card "$CARD" '{"msg_type":"interactive","content":($card|tojson)}')
lark-cli api PATCH "/open-apis/im/v1/messages/${MSG_ID}" \
--data "$PAYLOAD" \
--as bot
カードテンプレート
思考中(ストリーミング状態、先にプレースホルダーを送信)
make_thinking_card() {
local name="$1" question="$2"
jq -n --arg name "$name" --arg q "$question"
…
[翻訳のため省略]