| name | lark-wiki-kb |
| description | Build and maintain a persistent Feishu/Lark knowledge base using the LLM Wiki pattern. Use when the user wants to ingest new documents into an interlinked wiki, query accumulated knowledge, or lint the wiki for gaps, contradictions, and stale pages. Best when `lark-cli` is installed and a `wiki-instance.yaml` config has been filled in. |
| compatibility | Works best in Openclaw when installed as /workspace/skills/lark-wiki-kb or /workspace/<channel>/skills/lark-wiki-kb. Requires authenticated `lark-cli`. |
| metadata | {"requires":{"bins":["lark-cli"]}} |
Lark Wiki KB
The LLM maintains three data layers: raw sources in Feishu Drive (read-only), persistent wiki nodes in Feishu Wiki (LLM writes), and a structured index and log in Feishu Base.
Config
Read the instance config before every operation. Resolve in this order:
LARK_WIKI_KB_CONFIG environment variable
.lark-wiki-kb/wiki-instance.yaml in the working project
Required keys:
wiki.space_id
wiki.nodes.sources, wiki.nodes.entities, wiki.nodes.concepts, wiki.nodes.synthesis, wiki.nodes.overview
base.app_token, base.tables.index, base.tables.log
Recommended keys:
drive.raw_folder_token
domain.current, domain.focus, domain.out_of_scope
wiki.nodes.sources_<slug>, wiki.nodes.synthesis_<slug> — one per active domain, added on first ingest
Triggers
Rules
- Read config before any write.
- Treat raw source files as read-only.
- Cross-links use the full Feishu wiki URL:
https://<tenant>.feishu.cn/wiki/<node_token>.
- Entity and concept pages are cumulative — append new sources, never overwrite history.
- Confirm 3–5 key takeaways with the user before committing an ingest.
- Domain slugs: lowercase, spaces and special characters → underscores (
AI & LLM → ai_llm). Use the same slug consistently across config keys and wiki node titles.
- If a
lark-cli command shape is unclear, check --help and lark-cli schema ... before guessing.
First Run
Run this checklist before the first operation in any session:
- Locate config (
LARK_WIKI_KB_CONFIG → .lark-wiki-kb/wiki-instance.yaml). If missing → ask user to run bash core/bootstrap-instance.sh <harness> <project-dir>.
- Read config. If
wiki.space_id or root node tokens are empty → go to Setup.
- Check auth:
lark-cli auth status. If not logged in → ask user to run lark-cli auth login --recommend.
- If Base tokens are empty → complete Setup step 3, then stop and confirm with user.
Setup
Run once per knowledge base instance.
1. Confirm the target wiki space
lark-cli wiki spaces list --format table
Record the chosen space_id in the instance config.
2. Create the five root nodes if they do not already exist
SPACE_ID="<space_id>"
lark-cli wiki nodes create \
--params "{\"space_id\":\"$SPACE_ID\"}" \
--data '{"node_type":"origin","obj_type":"docx","title":"📥 Sources"}'
lark-cli wiki nodes create \
--params "{\"space_id\":\"$SPACE_ID\"}" \
--data '{"node_type":"origin","obj_type":"docx","title":"🏷️ Entities"}'
lark-cli wiki nodes create \
--params "{\"space_id\":\"$SPACE_ID\"}" \
--data '{"node_type":"origin","obj_type":"docx","title":"💡 Concepts"}'
lark-cli wiki nodes create \
--params "{\"space_id\":\"$SPACE_ID\"}" \
--data '{"node_type":"origin","obj_type":"docx","title":"🔬 Synthesis"}'
lark-cli wiki nodes create \
--params "{\"space_id\":\"$SPACE_ID\"}" \
--data '{"node_type":"origin","obj_type":"docx","title":"📋 Overview"}'
Write the returned node_token values into the instance config.
3. Create the shared Base and tables
All ingests share one Base. Create it once and reuse it forever.
lark-cli base +base-create --name "LarkWikiKB" --folder-token "<drive_root_or_folder_token>"
Then create the index table:
lark-cli base +table-create --base-token "<app_token>" --name "index" \
--fields '[
{"field_name": "title", "type": 1},
{"field_name": "category", "type": 3},
{"field_name": "summary", "type": 1},
{"field_name": "wiki_url", "type": 15},
{"field_name": "source_url", "type": 15},
{"field_name": "tags", "type": 4},
{"field_name": "date", "type": 5},
{"field_name": "source_count", "type": 2}
]'
Then create the log table:
lark-cli base +table-create --base-token "<app_token>" --name "log" \
--fields '[
{"field_name": "timestamp", "type": 1},
{"field_name": "operation", "type": 3},
{"field_name": "title", "type": 1},
{"field_name": "detail", "type": 1},
{"field_name": "affected_nodes", "type": 2}
]'
Field type reference: 1 = text, 2 = number, 3 = single-select, 4 = multi-select, 5 = date, 15 = URL.
Record the returned IDs in the instance config:
base.app_token
base.tables.index
base.tables.log
Verify with:
lark-cli base +table-list --base-token "<app_token>"
4. Fill the domain section
Before large ingests, fill the domain section in the instance config:
- current domain
- core focus
- what is out of scope
Without this, summaries drift.
Operation: Ingest
Step 1: Read the source
- Feishu URL →
lark-cli docs +fetch --doc "<url_or_token>"
- Drive file →
lark-cli drive +download --file-token "<token>" --output "/tmp/<name>"
- External URL → use harness web tools if available; otherwise ask user to paste content.
Step 2: Pause — confirm with user before writing anything
Show:
- 3–5 core takeaways
- likely entities and concepts to create or update
- likely links or contradictions with existing wiki nodes
Wait for user confirmation or correction before proceeding.
Step 3: Resolve domain → create source node
- Determine domain from source content and
domain.current in config. Derive slug.
- Look up
wiki.nodes.sources_<slug> in config.
- IF slug key is missing (new domain): create two subfolder nodes and write their tokens to config:
lark-cli wiki nodes create \
--params "{\"space_id\":\"<space_id>\"}" \
--data "{\"node_type\":\"origin\",\"obj_type\":\"docx\",\"parent_node_token\":\"<wiki.nodes.sources>\",\"title\":\"<emoji> <domain name>\"}"
lark-cli wiki nodes create \
--params "{\"space_id\":\"<space_id>\"}" \
--data "{\"node_type\":\"origin\",\"obj_type\":\"docx\",\"parent_node_token\":\"<wiki.nodes.synthesis>\",\"title\":\"<emoji> <domain name>\"}"
- Create the source node under
wiki.nodes.sources_<slug>:
lark-cli wiki nodes create \
--params "{\"space_id\":\"<space_id>\"}" \
--data "{\"node_type\":\"origin\",\"obj_type\":\"docx\",\"parent_node_token\":\"<sources_slug_token>\",\"title\":\"source-<short-title>-<YYYY-MM-DD>\"}"
- Write summary to the new node:
lark-cli docs +update --doc "<new_obj_token>" --mode overwrite --markdown "<summary>"
Summary must include: original URL, date, tags, core points, key quotes, linked entities/concepts, links to related wiki nodes (including contradictions).
Step 4: Update entity and concept nodes
For each entity (entity-<slug>) and concept (concept-<slug>) identified:
- Search
index table for exact title match:
lark-cli base +record-list --base-token "<app_token>" --table-id "<index_table_id>"
- IF found → fetch doc and append new source section:
lark-cli docs +fetch --doc "<obj_token>"
lark-cli docs +update --doc "<obj_token>" --mode append --markdown "<new section>"
- IF missing → create node under
wiki.nodes.entities or wiki.nodes.concepts and write initial content.
Rules: node title must be exactly entity-<slug> or concept-<slug>, never bare names. Each node needs at least two outbound links. If Base filtering syntax is unclear, use --jq or lark-cli base +data-query.
Step 5: Update Base index and log
After every create or update:
- write or update the corresponding
index row
- append a
log row
Preferred command for writes:
lark-cli base +record-upsert --base-token "<app_token>" --table-id "<table_id>" --json '<record-json>'
Because the wrapper format can change, check lark-cli base +record-upsert --help first.
index record example:
{
"fields": {
"title": "source-example-post-2026-04-10",
"category": "source",
"summary": "A one-sentence description of this node.",
"wiki_url": {"link": "https://<tenant>.feishu.cn/wiki/<node_token>", "text": "source-example-post-2026-04-10"},
"source_url": {"link": "https://original-url.com/", "text": "Original Article"},
"tags": ["ai", "llm"],
"date": 1744300800000,
"source_count": 1
}
}
log record example:
{
"fields": {
"timestamp": "2026-04-10 14:30",
"operation": "ingest",
"title": "source-example-post-2026-04-10",
"detail": "Created 1 source, updated 2 entities, 1 concept.",
"affected_nodes": 4
}
}
Date values in the index table are Unix timestamps in milliseconds.
Step 6: Report impact
Always tell the user:
- which nodes were created
- which nodes were updated
- notable support, additions, or contradictions discovered
- what to ingest next
Operation: Query
Step 1: Search likely nodes
Start from the structured index:
lark-cli base +record-list --base-token "<app_token>" --table-id "<index_table_id>"
Then use full-text search for recall:
lark-cli docs +search --query "<keywords>" --format table
Step 2: Read the relevant pages
lark-cli docs +fetch --doc "<obj_token_or_url>"
Step 3: Answer from the wiki
Requirements:
- cite concrete wiki nodes
- surface contradictions explicitly
- separate facts from inference
- call out data gaps
Step 4: Archive durable answers
If the answer is likely to matter later, create a synthesis node:
synthesis-<topic>-<YYYY-MM-DD>
Place it under the correct domain subfolder (wiki.nodes.synthesis_<domain_slug>), not the root Synthesis node. Write the analysis, then upsert index and append log.
Operation: Lint
Step 1: Enumerate nodes
List children under each configured root parent (run for sources, entities, concepts, synthesis; also enumerate domain subfolders):
lark-cli wiki nodes list --params '{"space_id":"<space_id>","parent_node_token":"<node_token>"}' --page-all --format json
Step 2: Compare against Base
lark-cli base +record-list --base-token "<app_token>" --table-id "<index_table_id>"
Step 3: Check for problems
Look for:
- wiki nodes missing from
index
index rows pointing to missing wiki nodes
- entity or concept mentions without links
- concepts mentioned repeatedly but lacking a dedicated node
- stale claims that newer sources contradict
- pages with too few outbound links
- thin or duplicate tags
Step 4: Ask before mass repair
Small obvious fixes are fine.
For larger changes, show a lint report first and ask whether to:
- auto-fix links
- create missing nodes
- mark stale claims
- leave conflicts for manual review
Step 5: Refresh the Overview node
After every lint run, rewrite the Overview node with a current snapshot of the knowledge base:
- total node counts by category
- active domains
- most recently updated entities and concepts
- suggested next topics to ingest based on detected gaps
lark-cli docs +update \
--doc "<overview_obj_token>" \
--mode overwrite \
--markdown "<overview markdown>"
The Overview is also a reasonable place to update after any ingest that adds a new domain or crosses a round-number milestone (e.g. 10th source, 50th node).
Style And Safety
- Prefer precise node titles over conversational titles.
- Keep source pages as snapshots; do not silently rewrite what a past source claimed.
- Keep entity and concept pages cumulative and time-aware.
- When quoting source text, keep quotes short and place interpretation outside the quote.
- If a command fails due to auth, permissions, or syntax drift, stop and diagnose before writing partial state.