SuperAPI AI Directory

soia-cwork-feishu-doc-git-sync

General & other

View repository

Updated 10-16 04:58

About this skill

soia-cwork-feishu-doc-git-sync

Mirror the contents of a Feishu knowledge base to a local Markdown knowledge base. The default direction is Feishu → local/Git/Obsidian/VitePress; this skill does not write to Feishu by default, and two-way sync must first establish document ownership, conflict policy, and write permissions.

Customer-readable description

What this skill can do

Customer wants Skill will do Customer can see
Sync Feishu knowledge base to local Traverse knowledge space nodes, read readable documents, and generate Markdown Local mirror directory, directory hierarchy, source links, sync manifest
Back up to Git Place generated content into the customer-specified Git repository and check differences commit/push receipt, file changes, and failure list
View with Obsidian Save rules, mirrors, and local supplements in a separate vault A vault that can be opened directly with Obsidian
Display with VitePress Generate the site sidebar and build a static site Local development server or build artifact
Check spreadsheet/bitable export capabilities Parse actual resource types, permissions, and available export formats Read-only probe results; will not generate Excel files by default
Sync standalone or embedded Sheets Read Sheets within the scope explicitly authorized by the private configuration; can automatically cover all standalone Sheet nodes, and embedded Sheets are identified from the document XML before reading Bounded Markdown table snapshots; no longer write authorized Sheet nodes as body placeholders
Preserve Sheet formulas, styles, comments, and chart information Save metadata snapshots of cells, layout, charts, and floating images for the selected range Local fidelity JSON alongside Markdown tables; not disguised as an editable workbook
Initialize complete Sheets and reports After confirmation, export the entire Sheet workbook in batches .xlsx Fidelity copy, preserving formulas, styles, comments, charts, pivot tables, and cell images
Mirror specified bitables Read fields, limited records, and optional views of specified Base tables, and generate Markdown and snapshots Bounded table content, schema/record snapshots; by default does not read any Base data
Initialize bitables and multi-person reports After confirmation, export the complete Base in batches; selected tables can also read dashboard and report block metadata .base Fidelity copy; dashboard snapshots are written to JSON, not disguised as an interactive web page
Localize assets and navigation After confirmation, download document images/attachments, or download attachments of selected bitable records, and change internal document links and subpage lists to local navigation Local assets, relative links, and optional subpage navigation
Initialize knowledge base files After confirmation, download Wiki in batches file Raw binary of the node Local links; ZIP, DMG, EXE, etc. are only saved, never executed, mounted, or extracted
View sync changes After configuration, generate a local change ledger and restricted diff of additions, modifications, moves, and remote deletions Statistics, change list, and diff details for this sync
Plan bidirectional sync Distinguish read-only mirrors, managed documents, and local supplements Conflict/permission risk description, does not automatically overwrite Feishu

How customers use it

  1. Confirm soia-cwork-feishu-cli has completed Feishu app credential login, and the bot can read the target knowledge space.
  2. Fill in the knowledge space ID, output directory, and source URL template in the local private configuration; do not commit the App Secret, token, or enterprise private paths to a public skill repository.
  3. For first use, run dry-run first to verify the space, node count, and target directory.
  4. First use an isolated single-node pilot to verify tables, resources, and style snapshots;--pilot-node-token writes only explicitly selected nodes to a separate pilot directory, and will not fill in placeholder files for other nodes in an empty directory.
  5. Execute mirror sync. By default it only writes local files and sync metadata, does not modify Feishu content, and does not delete local history files.
  6. After sync writes, it automatically validates the manifest, file existence, frontmatter, failure placeholders, sidebar coverage, resource references, unarchived embedded Sheets, unarchived Sheets with embedded Base,all_docx historical documents for which the XML semantic scan has not yet been completed in mode all_nodes , and standalone Sheets for which a real table has not yet been generated in mode failed/stale or semantic gaps are found, it returns a non-zero result; blank placeholders or partial content must not be treated as complete success.
  7. If you need to inspect table export, first do a drive +inspect/help/schema probe; a capability probe does not equal authorized export.
  8. Only after the customer explicitly confirms the export scope, format, file count, and local directory, call drive +export or drive +export-download。
  9. If you need to mirror Sheets, first specify the scope in the private configuration: use sync.sheets.enabled: true and all_nodes: true to automatically discover each grid subtable for all standalone Sheets, or specify item by item in selections the node_token, stable sheet_id , and bounded A1 range; both methods must set row, column, cell, and returned character limits. When the response reaches max_chars , you must continue reading from the next row according to actual_range ; truncation must not be treated as failure of the entire table. Mixed workbooks also require explicitly setting include_bitable_tabs: true and the record limit, then routing Base subtables to Bitable reading. After enabling sync.embedded_sheets.enabled for document-embedded Sheets, you must also choose all_docx: true or node_tokens. Enable sync.sheets.preserve on demand to save metadata such as formulas, styles, comments, layout, and charts. When not enabled, semantic gaps must be displayed and validated; you must not silently delete <sheet> or treat a standalone Sheet placeholder as complete archiving.
  10. If you need to mirror Bitable, specify item by item the sync.bitables.selections of node_token、table_id and max_records, then enable sync.bitables.enabled or pass in --sync-bitables; attachment binaries also require enabling download_attachmentsseparately, and dashboard/report metadata requires include_dashboards。
  11. Only after the user explicitly confirms the source, format, file count, output directory, and Git strategy can the full initialization be executed: Sheet settings sync.sheets.workbook_exports.enabled=true and all_nodes=true, Base settings sync.bitables.base_exports.enabled=true and all_nodes=true, Wiki file settings sync.files.downloads.enabled=true and all_nodes=true. Each item must be configured with batch_size, repeat execution until deferred is zero.
  12. If offline resources, local jumps between documents, subpage navigation, or a change ledger are needed, first enable them item by item in the private configuration download_assets、localize_internal_links、render_sub_page_navigation、change_ledger; they are disabled by default for compatibility with existing mirrors.
  13. Before batch initialization, first pilot with a representative scope to confirm resource counts, failure categories, and local rendering; after synchronization is complete, then run Git diff, site build, and necessary manual spot checks.

Recommended command:

python3 scripts/sync_feishu_wiki.py --config <private-config.yml> --dry-run
# 试点只写所选节点到独立目录;仍会核验它是否属于当前知识库
python3 scripts/sync_feishu_wiki.py --config <private-config.yml> --output-dir <pilot-output-dir> \
  --pilot-node-token <node_token> --incremental
python3 scripts/sync_feishu_wiki.py --config <private-config.yml> --incremental
# 没有事件订阅时,按 wiki +node-get 的远端更新时间判断正文是否变化
python3 scripts/sync_feishu_wiki.py --config <private-config.yml> --incremental --probe-remote-metadata
# 复用已完整正文,优先补独立 Sheet stub、未扫描的内嵌 Sheet 文档,再退避重试失败项
python3 scripts/sync_feishu_wiki.py --config <private-config.yml> --retry-failed
# 事件适配器已经拿到变动 ID 时,只拉对应节点;可重复传入多个 ID
python3 scripts/sync_feishu_wiki.py --config <private-config.yml> --incremental \
  --changed-node-token <node_token> --changed-obj-token <obj_token>
# 只修复指定节点的本地格式,复用 manifest 中的其他文档,不重试历史失败项
python3 scripts/sync_feishu_wiki.py --config <private-config.yml> --incremental \
  --rebuild-tree --rebuild-tree-only --only-node-token <node_token> --skip-assets
# 官方 webhook/长连接适配器写入 JSON/NDJSON 后,按事件目标增量拉取
python3 scripts/sync_feishu_wiki.py --config <private-config.yml> --incremental \
  --event-file <events.ndjson>
# 仅在确认历史生成目录曾经扁平化时执行一次结构迁移
python3 scripts/sync_feishu_wiki.py --config <private-config.yml> --retry-failed --rebuild-tree
# 大型知识库遇到限流时分批补偿;重复执行直到 --validate-only 通过
python3 scripts/sync_feishu_wiki.py --config <private-config.yml> \
  --retry-failed --retry-batch-size 100 --skip-assets
# 如果只需要修复本地目录层级、暂时不请求飞书
python3 scripts/sync_feishu_wiki.py --config <private-config.yml> --rebuild-tree --rebuild-tree-only
# 从飞书刷新最新目录层级和兄弟节点顺序,但复用现有本地正文
python3 scripts/sync_feishu_wiki.py --config <private-config.yml> --incremental \
  --rebuild-tree --refresh-tree-only
# 下载图片到本地镜像并把正文中的远程 URL 改成相对路径
python3 scripts/sync_feishu_wiki.py --config <private-config.yml> --incremental \
  --download-assets
# 将私有配置中明确选择的 Sheet 范围渲染为 Markdown 表格
python3 scripts/sync_feishu_wiki.py --config <private-config.yml> --incremental \
  --sync-sheets
# 将已授权文档中的嵌入式 Sheet 追加为有界 Markdown 表格快照
python3 scripts/sync_feishu_wiki.py --config <private-config.yml> --incremental \
  --sync-embedded-sheets
# 将私有配置中明确选择的多维表格镜像为 Markdown 与 JSON 快照
python3 scripts/sync_feishu_wiki.py --config <private-config.yml> --incremental \
  --sync-bitables
# 完整初始化仍使用同一同步命令;私有配置中 workbook_exports/base_exports/files.downloads
# 的 enabled 与 all_nodes 必须都为 true,并按 batch_size 分批重复执行
python3 scripts/sync_feishu_wiki.py --config <private-config.yml> --incremental \
  --sync-sheets --sync-bitables
# 只校验最近一次同步生成的本地镜像,不访问飞书
python3 scripts/sync_feishu_wiki.py --config <private-config.yml> --validate-only

Three working modes

  • mirror: default mode. The knowledge base is the source, and the locally generated 10_knowledge-base/ should not be edited manually.
  • local: only maintain the local 20_本地补录/, which will not be overwritten by mirror synchronization and will not be automatically uploaded to Feishu.
  • managed: intended in the future for explicitly designated bidirectional hosted documents. Write permissions, conflict rules, and publish actions must be confirmed document by document; the current script only provides a read-only mirror foundation and does not disguise it as completed bidirectional synchronization.

ID incremental synchronization and event push

  • node_token is the synchronization primary key, andobj_token is the object key for body reading and event mapping; title changes, moves, and duplicate names should not change these two IDs.
  • --only-node-token is the single-document repair switch; when used together with --rebuild-tree-only , it only locates nodes from the existing manifest, does not re-traverse the Feishu tree, and will not retry other nodes because of their historical failures.
  • The first synchronization establishes a complete baseline, recording obj_edit_time/remote_updated_at and docs +fetch returned by revision_id。
  • Subsequent --incremental will still first rebuild the tree by parent_node_token , but will only read the document bodies of newly added, failed, event-hit, or remotely edited-time-changed documents; unchanged nodes reuse local Markdown.
  • Sibling node order directly preserves the Feishu order returned by wiki +node-list , without re-sorting by title; therefore the VitePress/Obsidian directory should be consistent with the manual ordering of the Feishu knowledge base.
  • When there is no event target, by default use wiki +node-get for metadata probing; this generates many lightweight metadata requests, but avoids repeatedly downloading document bodies. For large spaces, you can switch to official event subscription and pass --event-file。
  • Events only provide a hint of "which object may have changed" and cannot replace Wiki tree reconciliation; creation, deletion, title changes, and unrecognized events still require re-reconciling the node tree.
  • Official event subscription, permissions, and drive.file.* coverage boundaries are described in references/events.yml. Currently lark-cli event list does not expose cloud document drive.file.* events, so this script does not claim to already be resident listening within the CLI; an external long connection/webhook adapter can pass JSON/NDJSON to --event-file。

Dependencies and installation

Dependency Type Installation / configuration What to do if missing
soia-cwork-feishu-cli Hard dependency Install and configure the official Feishu lark-cli app credentials Stop, first complete bot login and permission checks
lark-cli Hard dependency See soia-cwork-feishu-cli installation instructions Stop and report the installation command
Python 3.10+ Hard dependency Use system Python or project Python Stop
PyYAML Hard dependency python3 -m pip install pyyaml Stop and report missing dependencies
Git Optional enhancement Install Git Local images can still be generated, but cannot be committed/pushed
VitePress Optional enhancement Provided by the target documentation repository Can still sync to Obsidian
Obsidian Optional enhancement Installed on the user's machine Plain Markdown can still be generated

Default location of private configuration:

~/.config/soia-skills/soia-open-skills/cwork/soia-cwork-feishu-doc-git-sync/config.yml

You can also use SOIA_CWORK_FEISHU_DOC_GIT_SYNC_CONFIG_FILE to specify the configuration file. Reference assets/config.example.yml。

Minimal configuration example:

version: 1
provider:
  cli: lark-cli
  profile: <configured-cli-profile>
  brand: feishu
  identity: bot
space:
  id: <wiki-space-id>
  source_url_template: https://<tenant>.feishu.cn/wiki/{node_token}
paths:
  output_dir: <git-repository>/docs/feishu-knowledge
  generated_dir: 10_<knowledge-base-name>
sync:
  mode: mirror
  prune: false

Permission recommendation: For the first round, request only read-only permissions for the knowledge base, documents, and Sheets. Downloading images and attachments is an optional enhancement; when cloud drive/export permissions are involved, request them separately; write-back bidirectional permissions are never used as default permissions.

Sync rules

  • Only use --as bot read with the app identity; by default, no user identity token is required.
  • Traverse the knowledge space via node tokens, and use document tokens to read docx content.
  • paths.generated_dir must use the real name or stable English name of the target knowledge base; for example 10_后端技术支持库, do not nest another generalized feishu-knowledge directory.
  • If the existing output directory contains only one 10_* generated directory and the configuration does not specify paths.generated_dir, the skill will reuse it; if multiple candidate directories are found, it will stop and require explicit configuration first, to avoid automatically creating duplicate directories.
  • Each generated Markdown records the source URL, space ID, node token, object token, parent node, and content hash.
  • Use sync-state.json to preserve the mapping from node tokens to local paths; when titles change, keep paths as stable as possible, and recalculate tree positions from the latest parent_node_token .
  • manifest.json and sync-state.json record obj_edit_time、remote_updated_at、revision_id, used for incremental selection and auditing.
  • A single local path component is at most 48 characters; overly long titles keep the full title in frontmatter/sidebar, and a short node ID suffix is appended to the folder or file name to avoid overly long paths in Obsidian, macOS, and VitePress/Rollup.
  • The synchronizer converts custom figure/source/grid/callout, media tokens, and XML fragments exported from Feishu into a form parseable by Markdown/VitePress; this only changes local rendering and does not write back to Feishu.
  • Feishu document references are resolved into clickable Feishu Wiki links with node_token taking priority andobj_token as fallback; user references are preserved as @显示名. Static Markdown does not replicate Feishu's hover cards and member avatar interactions, but it is no longer incorrectly downgraded to code style.
  • A Feishu node with child nodes must generate a directory with the same name and place the body in an index Markdown with the same name inside the directory:父目录/节点名/节点名.md; only leaf nodes directly generate 节点名.md. Do not generate a sibling "same-name file + same-name folder".
  • If Feishu itself has same-name leaves and expandable nodes, parent-child same names, or duplicate expandable nodes at the same level, a stable short node ID suffix will be appended to the directory/file; this is to avoid same-level conflicts in the local file system, and the manifest still uses node_token to distinguish real nodes.
  • --retry-failed will reuse existing complete bodies and add failed nodes, standalone Sheet stubs, and historical documents that have not completed XML semantic scanning to the compensation queue; suitable for continuing to fill in gaps after encountering Feishu API rate limits or enabling a new Sheet strategy.
  • If an old placeholder such as "the current synchronizer only reads the document body" is retained in the historical mirror, even if the Feishu node later changes from Sheet to Docx and the manifest status is still ok, acceptance will still be judged as failed, and the highest-priority node in the --retry-failed queue will be re-pulled; the old placeholder after a type drift must not be treated as successful body text.
  • --retry-batch-size N is used only with --retry-failed , compensating at most N failed or semantically missing nodes each time; large spaces should run it repeatedly, and end when --validate-only 's failed_records=0、unmirrored_sheet_nodes=0、unscanned_embedded_sheet_documents=0 is the termination condition.
  • --retry-failed uses the previous manifest as the node list, and no longer performs metadata probing over all documents first; when the Sheet full strategy is enabled, it first fills in standalone Sheet stubs and historical Docx files missing the semantic scan marker, then retries ordinary failed items, and continues to be protected by global throttling. For large spaces, run it repeatedly with --retry-batch-size until unmirrored_sheet_nodes and unscanned_embedded_sheet_documents are both 0.
  • Only one sync process is allowed in the same output directory at a time; if the previous round is still exiting or the user starts it repeatedly, subsequent processes will stop and report, and will not concurrently overwrite the manifest.
  • Global request throttling and exponential backoff apply across sync workers;sync.min_request_interval_seconds defaults to 0.5 seconds, to avoid a large knowledge base concurrently triggering 99991400 rate limiting.
  • If body reading fails but old body text already exists locally, the node is marked as stale and the old body text is retained; the next incremental sync will continue to retry, and validation will not treat it as successful.
  • Local acceptance runs after every non-dry-run sync;--validate-only can independently recheck the most recent result. When acceptance fails, the exit code is 2, and a machine-readable summary is retained in the validation node of the manifest.
  • prune: false does not delete local files corresponding to nodes that have disappeared; the nodes are marked as deleted in the manifest, to avoid data loss caused by a single permission or network anomaly.
  • 20_本地补录/ and 90_同步元数据/ will not be overwritten by knowledge base sync.
  • --rebuild-tree only migrates paths.generated_dir old flat files generated by the synchronizer, and does not touch 20_本地补录/。
  • --rebuild-tree-only only reuses the existing manifest and generated files to perform directory migration, and does not initiate Feishu body requests; if asset localization is also enabled, it may still read documents containing assets only to refresh expired media URLs.
  • --refresh-tree-only re-reads the Feishu node tree and sibling order, and rebuilds the local directory and sidebar according to the latest parent_node_token , but reuses the existing local body text; when asset localization is enabled, it additionally refreshes documents that still contain unlocalized assets; it must be used together with --rebuild-tree .
  • manifest.json/sync-state.json 's tree_order: feishu_node_list indicates that the directory order comes from the Feishu node list, not title sorting.
  • Images retain remote URLs by default; after setting sync.download_assets: true or passing --download-assets , the skill downloads remote images in the body and <source token="..."> media blocks to paths.generated_dir/_assets/, and rewrites Markdown/HTML references to relative paths. Downloaded Feishu attachment cards must further be rewritten as standard Markdown local links; if the link is wrapped by a separate <p> , that HTML container must also be removed, ensuring both Obsidian and VitePress can click to open it. Cards that were not downloaded still retain the original remote reference and report failure.
  • When downloading assets, deduplicate preferentially by Feishu media token; the same attachment or image is kept as only one local asset even if it has different short-lived signed URLs. Assets without a token are still addressed by URL content.
  • sync.localize_internal_links: true , already-synced Wiki/document references will be changed to relative local Markdown links;sync.render_sub_page_navigation: true , the Feishu-exported <sub-page-list> will be changed to local Markdown subpage navigation. Both are disabled by default and do not affect existing external link behavior.
  • sync.change_ledger: true , a change ledger of additions, modifications, moves, and remote deletions generated per run will be produced under the sync metadata; modified items retain only the diff limited by change_ledger_max_diff_lines , without copying the full document text, and without changing the generated mirror or the local supplemental directory.
  • sheet By default, only a metadata stub is generated. After the user explicitly authorizes a bounded snapshot of the entire library, set sync.sheets.enabled: true and all_nodes: true, and the synchronizer will use sheets +workbook-info to automatically discover the grid subtables of each standalone Sheet, then according to max_rows、max_columns、max_cells、max_chars call within the upper limits sheets +csv-get; when the response is truncated, continue reading line by line according to actual_range . You can also continue to use selections to precisely declare a single range. Base subtables in a mixed workbook are read in a bounded manner according to include_bitable_tabs: true only when max_bitable_records , otherwise the node fails and cannot be silently skipped; if Base permissions are insufficient, the ordinary Sheets already read are still written to disk, but the node remains failed and an explicit gap marker is written.all_nodes Acceptance will reject any metadata_stub, Sheet nodes missing a real table marker, or unarchived Base subtables. For the complete contract, see references/sheet-mirroring.yml。
  • Feishu Markdown may return only <sheet> references without returning any cells. The synchronizer must not delete that reference and still report complete success: when drill-down is not authorized, keep the visible gap and make acceptance fail; only when sync.embedded_sheets.enabled and all_docx: true or node_tokens is explicitly selected will the document XML be read and an "embedded table" snapshot be generated within the configured upper limits. Enabling it for the first time will backfill old documents; the snapshot will not be disguised as an interactive original table. For the complete scope contract, see references/sheet-mirroring.yml。
  • sync.sheets.preserve.enabled: true will save, within the same selected range, a JSON snapshot of cell values, formulas, styles, comments, and worksheet layout, chart, and floating image metadata; pivot table, filter, conditional formatting, and sparkline metadata can additionally be enabled. It does not disguise charts or images as native Markdown. A complete workbook requires, after explicit user approval, setting both sync.sheets.workbook_exports.enabled: true and all_nodes: true, and the synchronizer will use drive +export to generate in batches .xlsx and link them in the Sheet index.
  • When the asynchronous Sheet export does not complete in the first polling round, the export task ticket will be saved in a private snapshot in the generated directory; subsequent batches only poll the same task, and once ready use drive +export-download to download, without repeatedly creating the same workbook export task.manifest.stats.sheet_workbooks_pending indicates the quantity still being processed on the Feishu side.
  • Image/attachment localization is an explicit opt-in local data download; you cannot download all assets just because the user only asks to "check images". The sync.download_assets: true in the persistent configuration can only be regarded as the user's previous explicit authorization for that resource scope and must not be extended to authorization for Sheet or Bitable exports. If structural initialization of Sheet/Base/file is performed first and --skip-assets is used to avoid output lock conflicts, a separate resource localization batch must be executed after initialization ends;--skip-assets will not mark images or attachments as downloaded.
  • bitable and unauthorized sheet By default, only a metadata stub is generated and no in-table data is read; a standalone Sheet with sync.sheets.all_nodes enabled is not allowed to retain a stub. After setting sync.bitables.enabled: true , you must declare item by item node_token、table_id and max_records; the synchronizer uses base +field-list、base +record-list and the optional base +view-list/base +dashboard-list/base +dashboard-block-list to generate Markdown and JSON snapshots.sync.bitables.download_attachments: true is a separate binary download authorization, using base +record-download-attachment and only processes read-record attachments of selected tables. A full Base export still requires explicitly setting both sync.bitables.base_exports.enabled: true and all_nodes: trueafter the user explicitly approves it; the synchronizer uses drive +export to generate in batches .base。
  • Wiki file nodes generate only metadata stubs by default; after the user explicitly confirms a full initialization, set both sync.files.downloads.enabled: true and all_nodes: true, and only then will the synchronizer call drive +downloadin batches. Files are saved as raw binaries and will not be executed, mounted, extracted, or parsed for ZIP, DMG, EXE, or other formats.
  • Feishu image URLs may expire quickly. When localization is enabled and --refresh-asset-urls is used, the URLs of associated documents are refreshed before downloading, and all body content is not unconditionally re-fetched; after download, they are uniformly written as local HTML alt with escaped <img>, and PNG/JPEG/GIF/WebP/SVG are identified by file binary, correcting incorrect cached suffixes.
  • Event targets,--changed-*-token、--only-node-token or isolated pilot runs process only the resources of documents re-read in the current round, and will not re-add historical resources of the entire library to the download queue; a full resource backfill does not pass a target and runs in batches by asset_batch_size .
  • Image downloads use URL content-addressed filenames, and repeated syncs reuse existing resources; ordinary URLs in Markdown and (<https://…>) angle-bracket URLs both enter the same download queue. You can use asset_workers、asset_timeout_seconds、asset_download_attempts、max_asset_bytes to limit concurrency, timeout, media retries, and single-file size; the default cap per resource is 50 MiB, and it can be lowered or raised in private configuration according to the confirmed download scope. Attachments carrying Feishu media tokens are retried within the cap on transient or unclassified CLI failures; clear insufficient permissions, nonexistent resources, or asset_too_large are not retried blindly. Large existing mirrors can set a positive integer asset_batch_size: only that number of resources not yet written to disk are requested each time, and already downloaded resources are still localized and rewritten;asset_refreshed_batch_size can limit the number of new links downloaded from the same batch of refreshed documents. Run repeatedly and confirm completion with --validate-only . The manifest reports this round's assets_deferred. Failed downloads keep only the original URL and are reported in the assets_failed count in the manifest; auth URLs are not written to logs or manifests.
  • <source token="..."> or URL-less <img token="..."> will call the official docs +media-download; when a remote URL cannot be read directly, you need to add docs:document.media:download or drive:file:downloadaccording to the permission list, and enable local resource download in private configuration. Without download permission, you must not assume local resources are complete.

Security Rules

  • Do not write App Secret, access token, or cookie into public skills, Obsidian vaults, Markdown, Git commits, terminal output, or final replies.
  • Terminal logs, progress receipts, and final replies must not output local absolute paths, specific local filenames, operating system usernames, usernames, passwords, App Secret, access token, or private download URLs; use redacted placeholders uniformly, and report only status, counts, and error categories. See references/output-redaction.yml。
  • Do not call Feishu create, update, or delete APIs by default.
  • drive +export、drive +export-download、docs +media-download and attachment downloads are both data export/download actions; when the user says "see if it can be exported," only do inspect, help, schema, or dry-run, and do not directly create local files.
  • Both Sheet and Base value mirrors are sensitive data written to disk: they can be enabled only after the user explicitly confirms the need to sync the selected range/table to the local workspace and writes a bounded sync.sheets.selections or restricted sync.bitables.selections in the private configuration; this confirmation does not authorize any workbook export, download of unselected attachments, or automatic Git commit.
  • Before an actual export, the source, type, format, estimated number of files, output directory, and Git tracking strategy must be clearly acknowledged; "checking capability" is not the same as "authorizing export".
  • Exported files are by default placed in a temporary directory or a directory explicitly specified by the user; only a complete mirror initialization explicitly confirmed by the user may write to _exports/ or _assets/under the generated directory, and it must not automatically commit to Git, automatically push to a remote, or write back to Feishu.
  • Personal cloud drives or private resources that the bot has no permission to access must be reported as invisible, and it must not switch to user OAuth to read them on the user's behalf.
  • Do not overwrite local supplementary data, delete historical files, or push to remote Git by default; these are write/publish actions that require explicit confirmation.
  • Before execution, check the target repository, current branch, and remote address; if anything differs from expectations, stop and report.

Logs and completion acknowledgment

The terminal and final reply must report at least:

  • started: space, identity, configuration source, and target directory (do not print secrets).
  • processed: number of nodes, documents, skipped items, and failures.
  • created/updated: number of Markdown, manifest, and sidebar files generated or updated.
  • skipped/failed: failed nodes, reasons, and whether they can be retried.
  • verification: results of Git diff, VitePress build, sampled documents, and source link checks.
  • next_step: whether additional permissions are needed, Git push needs confirmation, or bidirectional sync needs to be planned.
  • For file changes, report only the count and category, not local paths or file names; for identity, report only non-sensitive statuses such as bot identity / user identity .

Resources

Validation

python3 scripts/sync_feishu_wiki.py --help
python3 scripts/sync_feishu_wiki.py --config <private-config.yml> --dry-run
python3 scripts/sync_feishu_wiki.py --config <private-config.yml> --validate-only
git diff --check

Forward test

Before a real sync, run a dry-run or a small authorized representative scope and verify the tree, stable node-ID mapping, ordering, incremental selection, asset references, and failure receipt. After every write, require the built-in validation gate to pass; a zero exit code alone is not evidence that the mirror is complete.