# lark > Lark integration for documents, messenger, contacts, and base. Use for reading docs, sending messages, looking up users, and querying Lark Base/Bitable. - Author: Chang, Hao - Repository: popodidi/harvis - Version: 20260130121519 - Stars: 0 - Forks: 0 - Last Updated: 2026-02-06 - Source: https://github.com/popodidi/harvis - Web: https://mule.run/skillshub/@@popodidi/harvis~lark:20260130121519 --- --- name: lark description: Lark integration for documents, messenger, contacts, and base. Use for reading docs, sending messages, looking up users, and querying Lark Base/Bitable. allowed-tools: Read, Bash, AskUserQuestion, mcp__tn-lark__* --- # Skill: Lark Integration ## Purpose Integrate with Lark/Feishu platform: documents, messenger, contacts, and base (Bitable). ## When to Use - Reading Lark documents (wiki, docx) - Extracting tables from documents - Sending messages to chats - Looking up user information - Querying Lark Base/Bitable data ## Configuration All config files are bundled within this skill: | File | Purpose | |------|---------| | `lark-config.yaml` | API config, app_id | | `lark.secrets.yaml` | app_secret (gitignored) | | `scripts/lark-auth.sh` | Token management with caching | | `lark-token.cache` | Cached token (gitignored, auto-generated) | ### Helper Functions The `scripts/lark-auth.sh` script provides: | Function | Purpose | |----------|---------| | `get_lark_token` | Get/refresh tenant access token | | `lark_api METHOD endpoint [data]` | Make authenticated API call | | `get_document_blocks doc_id` | Get single page of blocks | | `get_all_document_blocks doc_id` | Get all blocks with pagination | ### Usage ```bash # Source the auth script (uses relative path internally) SKILL_DIR="$(dirname "${BASH_SOURCE[0]}")" source "$SKILL_DIR/scripts/lark-auth.sh" # Or via repo root REPO_ROOT="$(git rev-parse --show-toplevel)" source "$REPO_ROOT/projects/truenorth/skills/lark/scripts/lark-auth.sh" # Then use functions TOKEN=$(get_lark_token) lark_api GET "/docx/v1/documents/$DOC_ID/raw_content" ``` --- ## Commands ### `/lark read ` Read and parse a Lark document with table extraction. **Usage:** ``` /lark read FVcbwfYBFii6ZmkXVUNlj4yFgPg /lark read https://xxx.larksuite.com/wiki/FVcbwfYBFii6ZmkXVUNlj4yFgPg ``` **What it does:** 1. Fetches all document blocks via Lark Blocks API 2. Parses block types: Page, Text, Heading, Table, TableCell 3. Reconstructs table content from nested blocks 4. Outputs as formatted markdown --- ### `/lark message ` Send a message to a Lark chat. **Usage:** ``` /lark message oc_xxx "Hello team!" ``` **Implementation:** Uses MCP tool `mcp__tn-lark__im_v1_message_create` --- ### `/lark lookup ` Look up user information by email. **Usage:** ``` /lark lookup user@example.com ``` **Implementation:** Uses MCP tool `mcp__tn-lark__contact_v3_user_batchGetId` --- ## MCP Tools Available | Tool | Purpose | |------|---------| | `mcp__tn-lark__docx_v1_document_rawContent` | Get document text | | `mcp__tn-lark__im_v1_message_create` | Send message | | `mcp__tn-lark__im_v1_message_list` | Get chat history | | `mcp__tn-lark__im_v1_chat_list` | List chats | | `mcp__tn-lark__im_v1_chatMembers_get` | Get chat members | | `mcp__tn-lark__contact_v3_user_batchGetId` | Look up users | | `mcp__tn-lark__wiki_v2_space_getNode` | Get wiki node info | | `mcp__tn-lark__wiki_v1_node_search` | Search wiki | | `mcp__tn-lark__bitable_v1_*` | Lark Base operations | --- ## Document Parsing Details ### Block Types | Type | ID | Description | |------|----|-------------| | Page | 1 | Document root | | Text | 2 | Plain text paragraph | | Heading | 3 | Section heading (H1-H9) | | Table | 31 | Table container | | TableCell | 32 | Table cell | ### Table Parsing Tables have nested structure: ``` Table (31) └── cells: ["cell_block_id_1", "cell_block_id_2", ...] └── TableCell (32) └── children: ["text_block_id"] └── Text (2) └── elements[].text_run.content ``` ### Implementation Example ```bash source "$SKILL_DIR/scripts/lark-auth.sh" # Get all blocks (handles pagination) BLOCKS=$(get_all_document_blocks "$DOC_ID") # Parse with jq echo "$BLOCKS" | jq -r ' (map({key: .block_id, value: .}) | from_entries) as $blocks | .[] | if .block_type == 3 then "## " + (.heading.elements[0].text_run.content // "") elif .block_type == 2 then (.text.elements // [] | map(.text_run.content // "") | join("")) elif .block_type == 31 then "| " + ( .table.cells | map($blocks[.] | .block.children // [] | map($blocks[.].text.elements[0].text_run.content // "") | join(" ") ) | join(" | ") ) + " |" else empty end ' ``` --- ## Limitations 1. **Link previews** - Embedded links show as `link_preview` blocks 2. **Images** - Not downloaded; shows placeholder 3. **Complex formatting** - Bold, italic, colors simplified to plain text 4. **Comments** - Not included in block API response --- ## Related - `/pjm` skill - Uses this for reading sprint docs - Team members in `shared/team/members.yaml` have Lark IDs