In Claude Code of any project, "throw in a Feishu link → it lands in a local directory". This skill does not directly request Feishu; instead it hands the task to the already logged-in larksnap browser extension(which holds the cookies and the export engine).
CC ──fetch.mjs(一次性)──HTTP /command──▶ daemon ──WebSocket──▶ Chrome 扩展
▲ 127.0.0.1:19925 └ 后台开标签页跑导出
└ 流式回传进度/产物 ──▶ 解包到 <输出目录>/<文档名>/
This skill is self-contained:daemon and the protocol code has been packaged with the skill in scripts/bridge/ ,fetch.mjs what gets launched is
the daemon inside the skill,does not depend on the directory structure of the larksnap repository, so it can be called from any project. The only external dependency is
that extension installed in Chrome and already logged in to Feishu (the extension cannot be packed into the skill; it can only be loaded once in the browser, see references/setup.md).
Each document lands in its own subfolder(named after the document title), not tiled together with other files:
<输出目录>/
└── 无监督数据修复/ ← 文档标题命名的文件夹
├── 无监督数据修复.md
└── images/ ← 图片用相对路径内联引用
└── xxx.png
- The extension is a WS client, actively connecting outto the local daemon — no native messaging, no system-level installation.
- The daemon is automatically launched on demand by this skill, persists (exits automatically after 30 minutes idle), binds only
127.0.0.1。 - fetch.mjs is one-shot: exits once done, does not stay resident.
Usage
node ~/.claude/skills/larksnap-fetch/scripts/fetch.mjs <飞书链接> <输出目录> [--format md|pdf|html] [--profile <code>]
<输出目录>isparent directory; the output will land in<输出目录>/<文档名>/subfolder (each document gets its own folder, no mixing).--formatDefaultmd。md/htmlwill download images and inline them via relative paths into that subfolder'simages/;pdfdepends on tenant capabilities.- Progress is printed to stderr, the result path is printed to stdout (
✓ 已导出到followed by the absolute path of that document's subfolder). --profile <code>: when multiple browser profiles are connected to the daemon at the same time, specify which one to use (the code is in the Profile in the extension popup; click Copy to copy it). When there is only one, no need to specify.
Exit codes:0 success | 1 failure | 2 usage error | 3 login required | 4 authorized domain required | 5 bridge not ready.
Web search
When you need to search for materials, find reference links, or continue fetching the body text from search results, read references/search.md.
Search and fetch share this skill's daemon and bridge; the script entry point is scripts/search.mjs。
Edit Feishu documents (write Markdown content)
When you need to create, append, insert, replace, delete, or retrieve Feishu document blocks, read references/edit.md.
Editing and fetch share this skill's daemon and bridge; the script entry point is scripts/edit.mjs。
Ordinary web pages and Xiaohongshu
When the link is not a Feishu document,fetch.mjs automaticallygoes through the ordinary web page pipeline (full page converted to Markdown), the command stays the same,only supports md,
images keep external links. Xiaohongshu has a dedicated adapter, requiring login + a full share link with xsec_token ; images will be localized.
When fetching an ordinary web page fails, or when you want to fetch Xiaohongshu, read references/webpage.md。
arXiv papers
arXiv links or bare IDs do not go through the daemon/extension,Download PDF + HTML + Markdown all at once with a standalone script:
node ~/.claude/skills/larksnap-fetch/scripts/arxiv.mjs <arXiv链接或ID> <输出目录> [--pdf-only|--html-only]
For details (ID format compatibility, no HTML version is normal and no retry is needed), see references/arxiv.md。
Execution flow (CC follows this)
- Run the above command directly (the link given by the user + the local directory specified by the user; if the user did not specify a directory, it defaults to the current working directory). The daemon will be started automatically.
- Non-zero exit → parse the last line of stderr as JSON, and follow
hintto execute; do not guess on your own:retryable: true→ after doing as the hint says (e.g., click the extension icon to wake it up), directly rerun the same command; if the same error occurs 2 times in a row, stop and ask the user.retryable: false→ for hints that require user action (login/authorized domain), relay the hint to the user, wait for the user to confirm completion, then rerun.
- Exit code 0 → tell the user the files written as listed in stdout (paths of the form
<文档名>/<文档名>.md). The artifacts are in the<输出目录>/<文档名>/subfolder (mdcontainsimages/subdirectories are referenced by relative paths), and each document is in its own folder.
Complete workflow example (not logged in → self-heal → success)
第 1 步 node .../fetch.mjs https://xxx.feishu.cn/docx/AbCd... ./notes
→ 退出码 3,JSON: {"subtype":"need_login","hint":"让用户在 Chrome 中打开该文档域名并登录飞书…"}
第 2 步 对用户说:「需要先在 Chrome 里登录 xxx.feishu.cn 的飞书,登录好了告诉我。」
第 3 步 用户确认后,原样重跑第 1 步命令
→ 退出码 0,stdout 列出写入文件 → 告诉用户产物路径,结束。
Error contract (AI branches according to this, do not parse the prose)
On any non-zero exit, the last line of stderr is a single line of JSON, and the preceding lines are prose for humans:
{"ok":false,"error":{"type":"authentication","subtype":"need_login","message":"…","hint":"让用户在 Chrome 中打开该文档域名并登录飞书,登录完成后重跑本命令。","retryable":false}}
hint= what to do next (imperative, execute accordingly),do not guess on your own;retryable: true= directly rerunning this command may succeed;false= first act according tohint(usually requires user action) and then rerun.- Exit codes:
0success |1failure |2usage error |3login required |4authorized domain required |5bridge not ready.
For the complete type/subtype enumeration table and real output examples of various errors, see references/errors.md。
Installation and troubleshooting
For installing the extension for the first time, daemon connection failures, port conflicts, missing images, and web video downloads initiated from the extension sidebar (requires yt-dlp), see references/setup.md。