Communitygithub.com

Aquarius-mu/skillManager

개인 스킬 저장소: AI Agent 스킬의 수집, 정리 및 버전 관리

skillManager란 무엇인가요?

이 스킬은 Feishu(飞书) 메시지 카드의 schema 2.0 버전을 사용하여 풍부하고 상호작용 가능한 메시지 카드를 구축하는 방법을 상세히 설명합니다. AI Agent가 Feishu 봇을 통해 정교한 카드를 발송, 업데이트 및 상호작용해야 하는 개발자에게 유용합니다. 이 문서는 JSON 2.0의 핵심 규칙(예: 버튼의 `behaviors` 배열 사용, `note` 태그를 `div + lark_md`로 대체)에서부터 `div`, `img`, `column_set`, `collapsible_panel`, `table`, `button`, `input` 등 다양한 UI 구성 요소의 상세 사용법, 나아가 Feishu 특화 `lark_md` 구문, 색상 열거형 값, @멘션, 이모지 키 및 발송/회신/업데이트를 위한 구체적인 bash 명령어에 이르기까지 완벽한 참고 자료를 제공합니다. Claude Code, Cursor, Codex 등 Feishu 봇과 통합된 모든 AI Agent 플랫폼에서 사용할 수 있으며, Agent가 자체적으로 카드 메시지를 생성하고 관리할 수 있도록 합니다.

지원 대상✓Claude Code~Codex CLI~Cursor
npx skills add Aquarius-mu/skillManager

즐겨 사용하는 AI에게 물어보기

이 에이전트 스킬이 미리 로드된 새 채팅을 엽니다.

문서

feishu-card (schema 2.0)

핵심 규칙

  • 모든 카드는 schema 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로 원본 업데이트 (도배 방지)
  • note 태그는 schema 2.0에서 지원 중단됨 (오류 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_modeboolfalse스트리밍 업데이트 상태 (생각 중 자리 표시용)
enable_forwardbooltrue카드 전달 허용
update_multiboolfalseJSON 2.0 공유 카드 모드 (여러 사용자 동기 업데이트 필요 시 true)
width_modestringdefault (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"를 단독으로 사용하면 일부 컴포넌트에서 오류 발생), 계층 접미사가 필요:

색상 계열밝음 (배경 권장)중간색어두움 (텍스트 권장)
블루 blueblue-50 blue-100 blue-200blue-300~blue-500blue-600~blue-900
워터블루 wathetwathet-50 wathet-100 wathet-200wathet-300~wathet-500wathet-600~wathet-900
청록 turquoiseturquoise-50 turquoise-100turquoise-300~turquoise-500turquoise-600~turquoise-900
그린 greengreen-50 green-100 green-200green-300~green-500green-600~green-900
라임 limelime-50 lime-100lime-300~lime-500lime-600~lime-900
옐로우 yellowyellow-50 yellow-100yellow-300~yellow-500yellow-600~yellow-900
오렌지 orangeorange-50 orange-100orange-300~orange-500orange-600~orange-900
레드 redred-50 red-100red-300~red-500red-600~red-900
카민 carminecarmine-50 carmine-100carmine-300~carmine-500carmine-600~carmine-900
퍼플 purplepurple-50 purple-100purple-300~purple-500purple-600~purple-900
바이올렛 violetviolet-50 violet-100violet-300~violet-500violet-600~violet-900
인디고 indigoindigo-50 indigo-100indigo-300~indigo-500indigo-600~indigo-900
그레이 greygrey-00 grey-50 grey-100grey-300~grey-500grey-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레이아웃❌ schema 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을 지원하지 않음, 전폭 효과는 음수 margin 사용


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 (동일 폭 두 열) / trisect (동일 폭 세 열) 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개의 table만 가능, 중첩 불가


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=\\

관련 스킬