Skip to main content

flomo

flomo 浮墨笔记助手 — 读取/搜索/写入/编辑短笔记与灵感。通过本技能目录下的 flomo.py 脚本(私有 API + Webhook)操作,浏览器 UI 仅作兜底。适合碎片化快速记录;长笔记/知识管理用 getnote。

Jump to install

Source facts

Repository
llm011/ethan-agent
Last source activity
September 11, 2026 at 11:24
Detected SKILL.md language
Chinese
Stars
8
Forks
0

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

File Explorer
3 files

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
flomo
trigger
flomo|浮墨|浮墨笔记|flomoapp|记灵感|灵感记录|卡片笔记|碎片笔记|快速记一下|随手记|闪念|闪念笔记
description
flomo 浮墨笔记助手 — 读取/搜索/写入/编辑短笔记与灵感。通过本技能目录下的 flomo.py 脚本(私有 API + Webhook)操作,浏览器 UI 仅作兜底。适合碎片化快速记录;长笔记/知识管理用 getnote。
> **多副本同步提醒**:本文件改完后,必须同步到以下两份,否则线上 agent 读到的仍是旧版: > - host:`~/.ethan/skills/flomo/SKILL.md` > - 容器内 volume(运行中 agent 实际读取):`/root/.ethan/skills/flomo/SKILL.md`,用 `docker cp` 推送 > 三份不一致会导致「改了不生效 / 重建镜像后和 volume 对不上」。 # flomo Skill ## 适用边界 **flomo(本技能)**:短笔记、灵感、闪念、碎片化快速记录。**仅在用户点名 flomo/浮墨,或语境明确是"记个灵感/闪念/卡片"时才用**。 - 用户只说"记一下/存一下/我的笔记"等泛化词 → **默认走内置 `knowledge_*`**(系统知识库),不要默认跳到本技能 - 收藏外部文章/视频/链接 → **走 getnote** - 用户明确提到 flomo / 浮墨,或语境是"记个灵感/闪念/卡片" → **走本技能** 完整路由见系统 `tools.md` 的「记录/笔记入口路由」表。 --- ## ⭐ 主路径:调用 flomo.py 脚本 本技能目录下有 `flomo.py` 脚本,**封装了 flomo 私有 API + Webhook**,用 `shell` 工具调用即可,一次调用拿全量,比浏览器快几十倍。 **脚本路径**(两种环境都要支持): - 容器内:`/root/.ethan/skills/flomo/flomo.py` - 本机:`~/.ethan/skills/flomo/flomo.py` 调用前先用 `file_read` 确认脚本路径存在;不存在则报错让用户同步技能目录。 ### 子命令一览 | 子命令 | 功能 | 所需鉴权 | 说明 | |--------|------|---------|------| | `query` | 搜索/查询笔记 | access_token | 支持 keyword/tag/days/start/end/limit | | `tags` | 列出标签及频率 | access_token | 支持 prefix/days/limit | | `create` | 创建笔记 | access_token | 支持 HTML 富文本 | | `edit` | 编辑已有笔记 | access_token | 需指定 slug 或 URL | | `write` | 写入笔记 | webhook key | 仅纯文本 + #标签 | ### 调用示例 ```bash # 读取最近 10 条笔记 python3 ~/.ethan/skills/flomo/flomo.py query --limit 10 # 按关键词搜索 python3 ~/.ethan/skills/flomo/flomo.py query --keyword "认知" --limit 20 # 按标签过滤,最近 30 天 python3 ~/.ethan/skills/flomo/flomo.py query --tag "闪念/思考" --days 30 # 按日期范围 python3 ~/.ethan/skills/flomo/flomo.py query --start 2026-07-01 --end 2026-07-31 # 列出所有标签(前 50 个,按频率降序) python3 ~/.ethan/skills/flomo/flomo.py tags # 按前缀过滤标签 python3 ~/.ethan/skills/flomo/flomo.py tags --prefix "闪念" # 创建笔记 python3 ~/.ethan/skills/flomo/flomo.py create --content "今天的想法 #闪念/思考" # 编辑笔记(slug 从 query 结果取) python3 ~/.ethan/skills/flomo/flomo.py edit --slug "NTAxMjM0" --content "更新后的内容 #闪念/思考" # Webhook 写入(仅需 webhook key,不需要客户端登录) python3 ~/.ethan/skills/flomo/flomo.py write --content "快速记一笔 #闪念/收集" ``` > **容器环境**:路径换成 `/root/.ethan/skills/flomo/flomo.py`。容器的 Dockerfile 已带 python3 + 标准库,无需额外依赖。 ### 鉴权配置 脚本会自动按以下优先级提取鉴权信息: **access_token**(query/tags/create/edit 用): 1. secrets(`set_secret(name="flomo-access-token", value="<id|token>")`) 2. 本机 flomo 客户端 config.json 3. 本机 flomo 客户端 LevelDB **webhook key**(write 用): 1. secrets(`set_secret(name="flomo_webhook_key", value="<key>")`) 2. (本机客户端无此 key,只能走 secrets) > **容器/无客户端环境**:必须先用 secrets 配置 token,否则只有 `write` 能用。本机装了客户端则全部自动可用。 ### 脚本失败时 1. **token 提取失败** → 报错信息会提示用 `set_secret` 配置,照做后重试 2. **API 返回错误** → 反馈给用户,可能是 token 过期(重新登录客户端 / 更新 secrets) 3. **脚本本身不存在或语法错** → 走下面的浏览器兜底 --- ## 浏览器兜底路径 仅当 `flomo.py` 脚本不可用(文件缺失 / Python 环境异常 / 反复失败)时才走浏览器。 ### 浏览器前置条件 - Chrome 已安装 ethan 扩展,用 **Web UI Token**(`dev-ethan.sh` 启动日志里打印)连上服务(默认 8910)。连上后日志显示 `browser ws: extension connected`。 - 本机浏览器已登录 flomo —— 扩展复用你的登录会话,**所有浏览器操作均无需任何 api_key / token**。 - 若页面跳转到登录页:告知用户在浏览器重新登录 `https://v.flomoapp.com/mine/`,不要用 api_key 兜底。 ### ⚠️ OOM 红线(所有 flomo 浏览器操作必须遵守) flomo 首页 DOM 极重(侧边栏 400+ 标签),`browser_page snapshot` 或框架整页截图会把上下文/响应撑爆被 SIGKILL。**所有操作一律用 `browser_page eval` 跑紧凑 JS、只回传小 JSON,绝不 snapshot / 整页截图**。若单次调用仍 OOM,缩小返回内容后重试。 ### 读取笔记(浏览器兜底) 1. `browser_tab` 打开 `https://v.flomoapp.com/mine/`。 2. 用 `browser_page eval` 跑下面的脚本,取最新 N 条: ```javascript (async () => { const N = 5; const cards = [...document.querySelectorAll('.display.showMemoInsight')]; const data = cards.slice(0, N).map(card => ({ text: (card.innerText || '').trim().slice(0, 2000), images: [...card.querySelectorAll('img[src*="static.flomoapp.com"]')].map(i => i.src) })); return JSON.stringify(data); })() ``` 返回数组,每项含 `text`(正文含时间/标签)与 `images`(OSS 预签名直链,可直接 `curl` 下载,无需鉴权)。 > **首页折叠提醒**:flomo 首页卡片默认折叠长文,DOM 拿到的 `innerText` 常是**片段而非全文**(验证时多次踩到)。若 `text` 明显被截断、或用户要的是某条笔记完整内容,需先点开该卡片展开全文,再取完整 `innerText`,不要自信地当成全文返回。 ### 搜索笔记(浏览器兜底) 1. `browser_tab` 打开/聚焦 `https://v.flomoapp.com/mine/`。 2. 定位搜索框 `INPUT.el-input__inner[placeholder="⌘+K"]`,用 `fill` 写入关键词,等 ~500ms 或 `press Enter`。 3. 搜索结果页 DOM 很轻(通常只有几条),用 `browser_page eval` 抽取: ```javascript (() => { const cards = [...document.querySelectorAll('.display.showMemoInsight')]; const data = cards.map(card => ({ text: (card.innerText || '').trim().slice(0, 2000), images: [...card.querySelectorAll('img[src*="static.flomoapp.com"]')].map(i => i.src), tags: [...card.querySelectorAll('[tag]')].map(e => e.getAttribute('tag')) })); return JSON.stringify({ count: data.length, notes: data }); })() ``` > 比扫首页快很多;绝不 snapshot 整页(见全局 OOM 红线)。 ### 读取标签列表(浏览器兜底) 用户问「我有哪些标签 / 某标签下有哪些子标签」时走这里。 用 `browser_page eval` 跑下面脚本(先读 Vuex store 取速,取不到回退 DOM 扫描): > **实测注意**:`window.__INITIAL_STATE__` 在 flomo 根本不存在(`undefined`)。真实 store 是 `window.__flomoVuexStore`,但全量标签字段默认为空(需先开「标签管理」面板才填充)。**最稳路径是 DOM 扫描**(已验证可拿全量 417 个)。 ```javascript (async () => { const collectDOM = () => { const s = new Set(); document.querySelectorAll('[tag]').forEach(el => { const t = el.getAttribute('tag'); if (t) s.add(t); }); return s; }; try { const st = window.__flomoVuexStore && window.__flomoVuexStore.state; const tm = st && st.tagManager && st.tagManager.tags; if (Array.isArray(tm) && tm.length) { const paths = tm.map(x => typeof x === 'string' ? x : (x.name || x.tag || x.path || '')).filter(Boolean); if (paths.length) return JSON.stringify({ route: 'store', tags: paths }); } } catch (e) {} const sleep = ms => new Promise(r => setTimeout(r, ms)); const sb = document.querySelector('.sidebar') || document.querySelector('#sidebar'); const seen = collectDOM(); let last = -1, stable = 0; for (let i = 0; i < 80; i++) { const closed = Array.from(document.querySelectorAll('.tag-expand-button:not(.expanded), button[aria-expanded="false"]')); if (closed.length) closed.forEach(b => b.click()); await sleep(120); collectDOM().forEach(t => seen.add(t)); const atBottom = sb ? (sb.scrollTop + sb.clientHeight >= sb.scrollHeight - 5) : true; if (seen.size === last && closed.length === 0 && atBottom) { if (++stable >= 4) break; } else stable = 0; last = seen.size; if (sb) sb.scrollTop += 800; else window.scrollBy(0, 800); await sleep(120); } collectDOM().forEach(t => seen.add(t)); return JSON.stringify({ route: 'dom', tags: Array.from(seen) }); })() ``` 返回 `{"route":"store"|"dom","tags":[...]}` —— `tags` 是完整路径字符串数组(如 `["领域/财富","work","mac",...]`)。 汇报:总数 + 顶层标签(不含 `/`)+ 用户问到的子树(按前缀 + `/` 层级匹配)。 ### 写入笔记(浏览器兜底) 1. `browser_tab` 打开 `https://v.flomoapp.com/mine/`。 2. `browser_page fill` 把整段内容(含末尾 `#标签`)一次性写入 `div.tiptap.ProseMirror`(占位提示「现在的想法是...」)。 3. `browser_page click` 点提交按钮 `svg.saveBtn`(输入为空时是 `svg.disableSave`,不可点)。 4. 等 1~2 秒,确认内容已出现在首页列表顶部。 写入前务必遵守下方「标签规范」,**优先复用存量标签**。 ### 删除笔记(浏览器兜底) #### 关键策略:先搜后删 首页 DOM 极重,直接在首页操作极易耗尽步数。**先在搜索框搜目标笔记唯一关键词,跳到搜索结果页再删**,结果页 DOM 很轻。 #### 步骤 1. 搜索定位目标笔记(参见「搜索笔记」)。 2. 用 `browser_page eval` 跑下面脚本(把 `__目标文本__` 换成唯一片段): ```javascript (async () => { const sleep = ms => new Promise(r => setTimeout(r, ms)); const vis = el => el && el.offsetParent !== null; const KEY = '__目标文本__'; const cards = [...document.querySelectorAll('.display.showMemoInsight')]; const target = cards.find(c => (c.innerText || '').includes(KEY)); if (!target) return JSON.stringify({ok:false, step:'locate', msg:'未找到目标笔记'}); const trigger = [...target.querySelectorAll('*')].find(b => { if (!vis(b)) return false; return /dropdown|more|operation|menu|ellipsis/i.test('' + b.className); }); if (!trigger) return JSON.stringify({ok:false, step:'menu', msg:'没找到「...」菜单按钮'}); trigger.click(); await sleep(400); const items = [...document.querySelectorAll('li,div,[role=menuitem],.el-dropdown-menu__item')].filter(vis); const del = items.find(b => /删除/.test(b.innerText || '')); if (del) del.click(); await sleep(500); const cfrms = [...document.querySelectorAll('button,.el-button')].filter(vis).filter(b => /确定|删除/.test(b.innerText || '')); const ok = cfrms.find(b => /确定/.test(b.innerText || '')) || cfrms[0]; if (ok) ok.click(); await sleep(800); const after = [...document.querySelectorAll('.display.showMemoInsight')]; const gone = !after.some(c => (c.innerText || '').includes(KEY)); return JSON.stringify({ok:true, deleted: gone}); })() ``` > **安全护栏**: > 1. KEY 必须足够唯一(优先用完整标签如 `领域/思维模型`),绝不用宽泛词。 > 2. **删除前先只读 eval 找出笔记,把原文念给用户确认,用户明确确认后再点删除**。误删不可逆。 --- ## 标签规范(重要) > 用户 flomo 现有 417 个标签,加笔记时**优先复用存量标签**。 ### 五大主框架类目 | 类目 | 含义 | 常见子标签 | |------|------|-----------| | `#领域` | 知识 / 认知领域 | 领域/财富、领域/成长、领域/思维模型、领域/心理学、领域/写作 | | `#项目` | 进行中的项目 | 项目/AI、项目/写作、项目/时间管理、项目/如何阅读 | | `#输入` | 外部输入源 / 素材 | 输入/书、输入/电影、输入/得到、输入/帆书、输入/网络 | | `#闪念` | 突发灵感、临时收集 | 闪念/思考、闪念/收集、闪念/生活、闪念/微信文章 | | `#永久` | 长期沉淀的精华笔记 | 永久/思考、永久/素材、永久/名词、永久/沟通 | ### 上下文 / 来源 / 状态标签(可与框架类目叠加) - 来源/设备:`work`、`mac`、`code` - 状态/动作:`todo`、`fix`、`checklist`、`daily`、`archived` - 生活场景:`旅游`、`日记`、`权益`、`小创新`、`资源`、`临时`、`试试`
View on GitHub
This SKILL.md is very large, so SkillsMP previews the first section here. View on GitHub