Problem
Feishu post type messages do not render markdown tables — they display as raw text with | characters, making table-formatted data unreadable.
Solution
Detect markdown tables via regex and route them to the Feishu CardKit table element (JSON 2.0 schema) instead of post.
API Reference
CardKit Table JSON 2.0 structure
{
"schema": "2.0",
"header": { "template": "blue", "title": { "content": "Title", "tag": "plain_text" } },
"body": {
"elements": [{
"tag": "table",
"page_size": 5,
"columns": [
{ "name": "col_0", "display_name": "Column A", "data_type": "text", "horizontal_align": "left" },
{ "name": "col_1", "display_name": "Column B", "data_type": "text", "horizontal_align": "left" }
],
"rows": [
{ "col_0": "value 1", "col_1": "value 2" },
{ "col_0": "value 3", "col_1": "value 4" }
]
}]
}
}
Supported data_type values: text, lark_md, markdown, number, options, persons, date.
Implementation
parse_markdown_table() — parse markdown table string → (columns, rows) for CardKit
_build_ordered_blocks() — split message into text and table blocks, preserving order
send_card_table() — async method to send a CardKit card with a table element
send_text() override — detects tables in formatted content; builds a combined CardKit card (markdown sections + table element in order); falls back to plain text if parsing fails
Examples
1. Pure table (all markdown rows belong to the same table)
Input:
| Name | Score |
|------|-------|
| Alice | 98 |
| Bob | 85 |
Output: CardKit card with blue header and a rendered table.
2. Text + table mixed content
Input:
## Performance Report
Summary: Strong quarter across all metrics.
| Region | Revenue | Growth |
|---------|---------|--------|
| North | 1200 | +15% |
| South | 890 | +8% |
Please review and let me know if you have questions.
Output: A single CardKit card with:
- A markdown element:
## Performance Report
- A markdown element:
Summary: Strong quarter across all metrics.
- A
table element with columns [Region, Revenue, Growth] and 2 data rows
- A markdown element:
Please review and let me know if you have questions.
3. Multiple tables in one message
Input:
## Q1 Metrics
### Sales
| Product | Units |
|---------|-------|
| A | 100 |
| B | 200 |
### Support
| Agent | Tickets |
|-------|---------|
| X | 50 |
| Y | 30 |
Output: One CardKit card with 4 elements: 2 markdown sections + 2 table elements.
Backwards Compatibility
- Non-table messages pass through unchanged
- If table regex matches but parsing fails (malformed table), falls back to plain
text send
send_card_table() can be called directly for programmatic use
Problem
Feishu
posttype messages do not render markdown tables — they display as raw text with|characters, making table-formatted data unreadable.Solution
Detect markdown tables via regex and route them to the Feishu CardKit
tableelement (JSON 2.0 schema) instead ofpost.API Reference
CardKit Table JSON 2.0 structure
{ "schema": "2.0", "header": { "template": "blue", "title": { "content": "Title", "tag": "plain_text" } }, "body": { "elements": [{ "tag": "table", "page_size": 5, "columns": [ { "name": "col_0", "display_name": "Column A", "data_type": "text", "horizontal_align": "left" }, { "name": "col_1", "display_name": "Column B", "data_type": "text", "horizontal_align": "left" } ], "rows": [ { "col_0": "value 1", "col_1": "value 2" }, { "col_0": "value 3", "col_1": "value 4" } ] }] } }Supported
data_typevalues:text,lark_md,markdown,number,options,persons,date.Implementation
parse_markdown_table()— parse markdown table string →(columns, rows)for CardKit_build_ordered_blocks()— split message intotextandtableblocks, preserving ordersend_card_table()— async method to send a CardKit card with atableelementsend_text()override — detects tables in formatted content; builds a combined CardKit card (markdown sections + table element in order); falls back to plaintextif parsing failsExamples
1. Pure table (all markdown rows belong to the same table)
Input:
Output: CardKit card with blue header and a rendered table.
2. Text + table mixed content
Input:
Output: A single CardKit card with:
## Performance ReportSummary: Strong quarter across all metrics.tableelement with columns [Region, Revenue, Growth] and 2 data rowsPlease review and let me know if you have questions.3. Multiple tables in one message
Input:
Output: One CardKit card with 4 elements: 2 markdown sections + 2 table elements.
Backwards Compatibility
textsendsend_card_table()can be called directly for programmatic use