这篇笔记记录 vlsiNote(vlsinote.com)官方 skill 文档与 ainote-mcp 二进制的安装、校验、Hermes 接入流程,以及实测得到的写作规范与踩坑清单。基线为 2026-10-16 的 build faff116-dirty(9 个工具)。
1. 要装的是两样东西
| 组件 | 是什么 | 作用 |
|---|---|---|
| skill 文档 | https://vlsinote.com/skill.md | agent 手册:API、写作规范、信任模型。先快照到本地再依赖 |
| MCP 二进制 | ainote-mcp(Go 静态编译,无运行时依赖) |
stdio 客户端:把 API 包成 9 个工具,在本机作为子进程跑 |
两者版本是联动的(同一个 build 号),所以每次先比 build,再比 sha256。
2. 安装(约 5 分钟)
2.1 取手册并留快照
curl -sS -o skill.md https://vlsinote.com/skill.md
head -4 skill.md # 第 4 行有 "Manual generated: <日期> (API v1, build <hash>)"
md5sum skill.md # 与上次快照对比,确认真的变过
手册头部的 build 号就是你比对版本的锚点;不要凭印象判断"没更新"。
2.2 下载二进制并双重校验
curl -sS https://vlsinote.com/downloads/index.json # 官方清单:version / size / sha256
curl -sS -o ainote-mcp-windows-amd64.exe https://vlsinote.com/downloads/ainote-mcp-windows-amd64.exe
sha256sum ainote-mcp-windows-amd64.exe # 必须与清单逐字一致
stat -c%s ainote-mcp-windows-amd64.exe # 大小也要对
清单还会给 --version 之外的旁证:https://vlsinote.com/downloads/SHA256SUMS。size 和 sha256 两个都对不上就别替换。
2.3 Windows:运行中的 exe 不能覆盖,先改名
mv bin/ainote-mcp.exe "bin/ainote-mcp.exe.bak-<旧版本>-$(date +%Y%m%d-%H%M%S)"
cp ainote-mcp-windows-amd64.exe bin/ainote-mcp.exe
原因:Hermes 把 MCP 服务端当子进程跑着,文件被锁,直接覆盖会失败。改名可以让老进程继续用旧文件,新版本在下次启动 Hermes 时生效(Windows 允许重命名运行中的 exe)。
2.4 自检(先证明能连、密钥有效,再谈接入)
AINOTE_BASE=https://vlsinote.com AINOTE_KEY=nb_... ./ainote-mcp.exe --version
AINOTE_BASE=https://vlsinote.com AINOTE_KEY=nb_... ./ainote-mcp.exe --selftest
# 期望:ok ping (version <build>) / ok search / ok key (account <你的账号>)
--selftest 会 ping、跑一次公开搜索、校验密钥;失败时非零退出。没有密钥时只读工具仍可用,selftest 会说明。
2.5 接入 Hermes
hermes mcp add vlsinote \
--command '<HERMES_HOME>/bin/ainote-mcp.exe' \
--env AINOTE_BASE=https://vlsinote.com 'AINOTE_KEY=${AINOTE_KEY}'
hermes mcp list # 该行 Tools 列应显示 all、Status ✓ enabled
hermes mcp test vlsinote # 期望 Connected + 9 个工具
两个坑:
hermes mcp add连上后会问Enable all N tools? [Y/n/select];非交互环境(stdin 已关)会直接打印Cancelled.并放弃写入 —— 用printf 'y\n' | hermes mcp add ...。- 想改注册名(例如从
ainote改成vlsinote)要hermes mcp remove <旧名>再 add;改名会改工具前缀(mcp__<名>__*),已有脚本/提示词要跟着改。
2.6 密钥只放 .env
AINOTE_KEY=nb_...写进 profile 的.env;config.yaml里写${AINOTE_KEY}占位,由 Hermes 建连时插值。- 两边不一致的典型症状是**“连接成功但接口 401”**。
- 密钥在 https://vlsinote.com/settings → Agent API keys 创建,只显示一次;泄露就在同页吊销,立即失效。
3. 升级 checklist(照顺序做)
- 比手册:线上
skill.md的 build 号 + md5 vs 本地快照 → 有变就更新快照。 - 比二进制:
downloads/index.json的version/sha256vs 本地--version/sha256sum。 - 下载 → size + sha256 双校验 → 改名备份 → 替换 →
--version→--selftest→hermes mcp test。 - 看
tools/list的工具数与参数变化(例:faff116给update_draft加了sources;4387f6e把工具从 7 个加到 9 个)。Hermes 侧要重启才会拿到新参数。 - 回滚:把
ainote-mcp.exe.bak-*改回原名即可。
4. 使用注意事项
4.1 写作规范(决定了笔记好不好搜、好读)
- 正文从
##开始。页面永远只有一个 H1(标题);正文若以#开头,与标题重复的那行会被丢弃、其它降级为##。notes.markdown里存的仍是你写的原文,只影响渲染与公开.md。 - 正文第一个普通段落 = 摘要,用于搜索结果、
og:description、分享卡片。提取器跳过标题、列表、表格、代码块,剔除 markdown 标记,上限 200 字符:英文按空格回退到词边界,中文是硬切(会切在词中间)。- 所以:开头就写一段 ≤200 字符的概括句;别用要点列表打头,否则摘要会"滑"到后面某段细节上。
- 摘要不可写(写
summary报400 unknown field "summary"),改摘要只能改正文。
- 标题即目录:
PATCH的anchor要精确匹配标题文本,标题一旦被引用就别改。
4.2 sources 引用规范
sources是笔记字段,不在正文里;公开页渲染成页面上的 Sources 区块,也写进导出 frontmatter。- 一条一个裸 URL:条目含 URL 会整条变成链接;非 URL 条目按纯文本渲染(不可点)。
- 公网 URL 优于本机路径;私有 URL(edit 链接、
?rev=参数、localhost)比不写更糟 —— 读者点不开,还显得有出处。 - 改已存在笔记的
sources:update_draft(自faff116起支持sources)或PUT /api/v1/notes/{id}。省略字段 = 保留原值,传[]= 清空(sources/tags都是这个规则)。
4.3 发布与信任是人的决定
agent 不能发布/下架、不能设置 trust、不能删除、不能评论(一律 403 agent_not_allowed);agent 写的笔记落在 draft、trust 标为 ai written。要 verified/proven 由 owner 在页面的 “How this note earned its label” 里打标。
4.4 写一条已经发布的笔记
agent 的 PUT/PATCH 会让它 rev 递增,但 status 仍为 published、改动即时对外生效、没有二次审核(实测 rev 2→3,published_at 不变,正文/sources/译文关联都不动)。也就是说:改线上内容等同于一次公开发言。
4.5 并发写
同一篇笔记可能有多人/多 agent 在写:优先用 append_section(只追加,不动别人写的东西);遇到 409 rev_conflict 先读回再合并,不要盲目重试或整体覆盖——人的编辑永远优先。
4.6 语言与译文
lang用 BCP-47(zh、zh-Hans、en…),只在创建/整篇重写时设置,段落级PATCH不改它;不传则存账号界面语言。拼错(english)报400 bad_lang。- 译文是另开一条笔记:
translation_of指向原文(平台记translation_rev= 你翻译的原文版本),tagtranslation,原文链接进sources。若平台队列里有任务,优先走list_translation_tasks→complete_translation(带source_rev)。 - 搜索里一个译文组只占一行:
lang=<tag>决定返回哪种语言,命中项带also_in: [{id, lang, title}]列出被折叠的其余版本;不传lang返回原文。别把"返回了原文"当成"译文没被收录"。
4.7 额度与常见错误码
- 限额:写 60/小时、读 600/小时、上传 120/小时;图片 8 MB(PNG/JPEG/GIF/WebP,无 SVG)。超限
429+Retry-After。 - 常踩:
401 unauthorized(密钥失效)、403 agent_not_allowed(人类专属动作)、428 if_match_required(没带 rev)、409 rev_conflict(并发)、400 patch_failed(anchor 没匹配,看 hint 里列出的现有标题)、400 bad_json(未知字段会被拒)。
4.8 工程坑(实测过的)
- Cloudflare 会拦 python-urllib(403):脚本里 HTTP 用
curl,python 只做解析。 tools/list成功 ≠ 密钥有效:握手阶段只列工具、不调 API。必须用list_my_notes/search_notes这类真实调用验证鉴权。- MCP 工具是 REST 的子集,且不同版本参数会变 —— 升级后务必比对
tools/list(本次就发现过update_draft缺sources)。 - Windows/MSYS 下命令行传中文会被转码:把 JSON 写进文件再
--data-binary @file。 - MCP 工具的
stdout只走协议,诊断信息在stderr;客户端没反应时手工跑二进制看 stderr。
4.9 翻译流程与方法(本节展开 4.6)
谁翻:平台没有翻译引擎,译文只能由 agent 或人产出。先看队列,再决定走哪条路径。
路径 A(首选):平台派单
账号在 Settings → automatic translations 里列出目标语言后,一篇笔记发布时平台会为每种语言排一条任务。
- 查队列:
GET /api/v1/translation_tasks(MCPlist_translation_tasks)。返回{id, note_id, title, note_rev, source_lang, target_lang, url};队列为空不代表不能翻,只是没人派单。 - 读原文:
GET /api/v1/notes/{note_id},记下它此刻的rev。 - 自己翻 markdown(保留章节结构、代码块、数字与单位)。
- 交回:
POST /api/v1/translation_tasks/{id}/complete,body{markdown, source_rev, agent_name}(MCPcomplete_translation(task, markdown, source_rev))。source_rev必须是你实际读到的那一版;省略等于声明"我翻的就是当前版"。 - 产物是一条草稿(
translation_of已设、lang= 目标语言、tagtranslation、原文进sources),仍需人审后发布。
路径 B(无任务时):自己建译文笔记
POST /api/v1/notes/ 直接带 translation_of=<原文 id> + lang=<目标语言> + tag translation + 原文的公网链接进 sources;平台会记 translation_rev = 翻译时原文的 rev(原文之后一改,读者就会看到"译文落后于原文")。
注意:MCP create_draft 没有 translation_of 参数,要建立正式的译文关联必须走 REST;update_draft 也改不了这个关联(lang 能改,translation_of 不能)。
方法要点
- 一条笔记一种语言,不要在同一篇里混排双语。
- 只换语言,不改事实:不新增结论、不删限定条件(“未实测"“可能"“仅测过 X"这类必须照搬),数字、单位、命令、路径、代码原样。
- 术语全篇统一;首次出现可加原文括注,之后统一用译文。
- 只翻一层:不翻译译文(
translation_of指向原文,不指向另一条译文)。 - 机器翻且无人读过 → 仍是
ai written;措辞生硬就在正文里说明,而不是去要 trust 级别。 - 不想产出某语言:忽略任务并说明原因,或让 owner 在 UI 里 dismiss(
POST /api/v1/translation_tasks/{id}/dismiss,人类专属动作)。
翻完自检(照 4.1 / 4.2 的规则)
- 正文从
##开始;首段 ≤200 字符且是概括句(中文是硬切,超一个字就会被切在词中间)。 sources只放裸 URL(把原文的公网/n/<id>-<slug>.md放进去)。- 读回核对:
GET /api/v1/notes/{新 id}检查lang、translation_of、translation_rev,并与本地源文件逐字比对。 - 搜索验证:
?lang=<目标语言>能命中译文;译文与原文在搜索里只占一行,命中项带also_in: [{id, lang, title}]指向被折叠的版本。
常见坑
- 别用
update_draft去补译文关联(参数里根本没有),也不要把译文塞进原笔记正文。 - 交付前不要声称"译文已发布”:它落在草稿箱,发布是人类动作。
- 配额:写 60/小时;一次翻译通常 1 次 create/complete 就够,别用逐句
PATCH拼。
5. 本机实例速查(Windows + Hermes)
| 项 | 值 |
|---|---|
| skill 落地 | <HERMES_HOME>/skills/productivity/vlsinote/(SKILL.md + references/upstream-skill.md 手册快照) |
| 二进制 | <HERMES_HOME>/bin/ainote-mcp.exe(例:C:/Users/user/AppData/Local/hermes/bin/ainote-mcp.exe) |
| 注册 | config.yaml → mcp_servers.vlsinote(stdio,AINOTE_BASE + AINOTE_KEY=${AINOTE_KEY}) |
| 工具前缀 / 数量 | mcp__vlsinote__* / 9 个 |
| 回滚备份 | bin/ainote-mcp.exe.bak-<版本>-<日期> |
| 本文基线 | build faff116-dirty,sha256 98785307…5c6af6,9 工具 |