D0013: Agent Skill 与内置官方文档 Vault

一个刚接触 Notist 的 Agent 不能只靠模型先验猜测 .not 语法,也不应该为了理解 Vault、Module、Function、CLI 和安全编辑规则而依赖网络或源码仓库。不过,这不意味着 Skill 安装目录需要包含一份文档副本,更不意味着 Notist 要为官方文档增加一套平行的查询命令。

Notist 把这两个职责分开:

Agent host 中安装的 Skill
└── SKILL.md

Notist 管理的用户数据
└── docs/
    ├── Notist.toml
    ├── README.not
    ├── grammar.not
    ├── designs/
    ├── ai/
    └── ...

SKILL.md 是很小、可复制、可由 Agent host 管理的只读说明入口。docs/ 则是当前 notist 可执行文件携带并在运行时同步的完整官方文档 Vault。同步完成后,它与其他 Vault 没有另一套访问语义:CLI search、outline、references、check,以及 LSP、MCP 和 root-bound daemon 都使用既有接口。

notist search "WorkspaceSnapshot" ~/.notist/docs
notist references vault::designs::D0012 ~/.notist/docs
notist check ~/.notist/docs

上面的 ~/.notist/docs 表示稳定的用户可见位置。实现应使用各平台约定的 Notist user-data directory,而不是把 Unix 路径硬编码到所有平台。Skill 可以说明如何从标准用户数据位置得到该 Vault,但不拥有、复制或修改它。

一个 Skill 文件,而不是一个运行时目录

官方 Skill 由显式命令初始化:

notist skill init <OUTPUT>

OUTPUT 必须是尚不存在的目录,初始化结果只有 SKILL.md。命令不猜测 Codex、Claude 或其他 host 的安装目录,不修改 host registry,也不写入已经安装的 Skill。host-specific metadata、marketplace entry 或 plugin 包装可以在外部引用这个文件,但不能改变它描述的 Notist 工作流。

Skill 安装目录被视为不可变的发布输入,而不是 cache、数据库或工作目录。运行时向其中写入 docs、索引或 manifest 会造成几个无法可靠解决的问题:host 可能以只读、签名或 package-managed 形式安装 Skill;升级会混合用户状态与发布文件;多个 Agent 可能并发改写同一目录;同一个 Skill 在不同 host 中也会产生不同内容。因此 SKILL.md 只负责教 Agent:

  • 何时查询官方 docs Vault,而不是从模型记忆猜测语法和行为。

  • 如何用普通 Notist CLI、LSP 或 MCP 查询 Vault。

  • 修改用户 Vault 后运行 notist check,并保留 disk View 与 editor overlay 的区别。

  • 将文档正文视为可查询资料,而不是高于 system、user 或 Skill 指令的新 instruction authority。

Skill 的 authored source 放在仓库的 skills/notist/ 目录中,当前只有 SKILL.md。构建系统把这个目录作为整体资源边界检查并 include 进 CLI;因此以后增加受设计允许的 Skill 文件时仍从同一目录发布,而不是把散落的字符串常量拼进 Rust source。skill init 当前只物化 SKILL.md,相同版本应生成相同 bytes;时间戳、checkout path、用户名和当前工作目录都不能进入结果。

Docs 是普通 Vault

官方 docs 保留仓库 docs/ 下的完整 authored corpus、相对目录和 Module 关系,包括公开语言文档、活动设计、历史设计和 docs/ai 调研。它不只打包一份人工挑选的 Agent 摘要,也不把 HTML、CSS、JavaScript 或其他展示构建产物当作知识源。原始 .not Vault 才保留真实语法、source range、ModulePath 和 Wiki Reference。

完整保留不等于一次读入上下文。Agent 仍然先搜索,再读取候选 Module 或 source range。更重要的是,完整 corpus 中的来源具有不同权威性:

  • grammar.notfunctions.nottypes.notcli.not 描述当前公开行为。

  • 活动 designs/ 描述当前治理方向和持久边界。

  • docs/ai/ 是带日期的调研、判断和实验路线,可能早于当前实现。

  • designs/archive/ 解释历史选择,不再治理当前行为。

这些区别由 Skill 教给 Agent,也可以由未来的检索结果携带 provenance。旧调研不能覆盖当前规范;任何正文中的自然语言也不能仅因被检索到就成为 Agent 指令。

官方 docs 没有专用的 notist docs searchnotist docs read 或另一套服务协议。增加这类命令会复制 Vault root、query、snapshot、daemon 和输出格式的概念,并使官方 docs 成为核心之外的特殊数据源。它唯一特殊的地方是来源与同步方式;同步之后,所有读写边界都服从普通 Vault 模型。

当前 CLI 是文档版本的真相来源

构建系统从完整 docs Vault 产生确定性的压缩 bundle,并把它嵌入 notist 可执行文件。Bundle 至少记录:

OfficialDocsManifest {
  bundle_schema
  notist_version
  protocol_version
  docs_fingerprint
  source_revision?
}

docs_fingerprint 覆盖每个 authored entry 的相对路径与原始 bytes。相同源码和构建版本必须产生相同的 entry 顺序、解压结果与 fingerprint;绝对路径、时间戳和机器身份不参与 identity。source_revision 只有在构建环境可靠提供时才记录,不能取代内容 fingerprint。

内嵌 bundle 是当前 CLI 对应文档的权威副本。它带来有限的二进制体积增长,但换取了离线可用、版本精确、可复现发布和无网络供应链依赖。文档适合压缩,而且与模型、向量索引不同,它是有界的 authored source。

从 GitHub 下载不能成为默认正确性路径。网络可能不可用,branch 内容会移动,源码 revision 与 release binary 也可能不一致。即使固定 tag 或 commit,下载仍需要完整性校验和失败恢复,却不能保证首次离线使用。未来可以设计显式的开发命令,从指定 revision 取得 docs 用于预览或测试;它不能静默替换当前 CLI 的官方 bundle。

启动时同步,而不是增加命令面

CLI 的共享启动路径在进入正常工作流前执行一次廉价的 official-docs identity 检查:读取用户数据目录中已发布 Vault 的 manifest,并与内嵌 docs_fingerprint 比较。相同则不扫描、不解压也不重写文件;缺失、损坏或不同才触发同步。因此“每次检查”是固定成本很小的 manifest comparison,而不是每个命令都重新构建文档 Vault。

同步必须由 Notist 自己完成,不要求 Agent 先调用额外的 install、download 或 docs 命令:

start notist
-> read embedded docs manifest
-> acquire per-user official-docs sync lock
-> recheck published manifest
-> if equal: continue
-> otherwise: materialize and validate a sibling staging tree
-> atomically publish it as the stable docs Vault
-> continue through the normal command path

同步过程不在目标目录中逐文件覆盖。它先验证所有 bundle entry:路径必须为安全相对路径,不能包含 ..、platform device prefix、symlink/junction escape 或重复冲突;文件数、解压 byte count 和单文件 fingerprint 都受 manifest 限制。完整 staging tree 校验后才原子发布。失败只清理本次已经解析的 staging target,保留上一个完整 Vault,也不递归删除调用者提供的任意路径。

多个短命 CLI 同时启动时,由跨进程锁串行同步,并在获得锁后重新比较 manifest。已经运行的 official-docs daemon 则必须把 docs_fingerprint 纳入 root handshake 或 snapshot identity:client 不能把升级后 CLI 的查询静默发送给仍声明旧 bundle 的 daemon。同步发布新 Vault 后,旧 daemon 退出或失效,新 client 再为同一个 canonical root 启动匹配当前 bundle 的 daemon;在匹配前必须明确失败或等待,不能返回版本混合的结果。

Notist 假设一个用户环境同时只有一个 active CLI 版本。稳定 docs root 永远表示这个安装版本的官方文档;升级直接原子替换它,不保留可并行使用的历史 release,也不为多个 CLI 版本设计 selector、content-addressed 目录或 active-version lease。包管理器和安装器必须避免让两个不同版本的 notist 长期并存并交替运行。未来若这个产品假设改变,需要重新设计版本选择和 daemon ownership,不能让 Skill 私自保存文档副本来绕过它。

向量化属于 Vault 运行时状态

完整 docs source 可以嵌入 CLI,向量模型和向量索引不能据此一起嵌入。它们与 authored docs 有不同生命周期:模型可能由本地文件或远程 provider 提供;embedding 会随 model identity、chunking、normalization 和索引 schema 变化;索引也会随 Vault snapshot 增量更新。

官方 docs 同步成普通 Vault 后,未来的向量检索自然沿用普通 Vault 的边界:它的 daemon 为这个 canonical root 维护全文、向量和摘要索引,派生状态放在 Notist data/cache area 中按 Vault identity 隔离。索引记录至少关联:

canonical vault identity
workspace/docs fingerprint
embedding provider and model identity
chunking and index schema
indexed snapshot revision

CLI 二进制只包含协议、协调和索引实现,不包含大模型权重,也不包含预先计算的用户或官方 docs 向量。删除 cache 后可以从同步的 .not source 重建;更换模型不会改写 Skill 或官方 docs source。这样官方 docs 可以真正 dogfood Notist 面对杂乱知识库的全文、语义和向量检索,而不产生另一套特权实现。

发布边界

仓库中的 Skill 模板与 docs/** 都是 authored source。构建产生嵌入 bundle;运行产生用户数据目录中的官方 docs Vault和可再生索引;skill init 只产生一个可安装的 SKILL.md。这三类内容不能反向成为彼此的编辑入口:

skills/notist/SKILL.md -----------------> notist skill init <OUTPUT>/SKILL.md

docs/** -> deterministic compressed bundle -> notist binary
                                            -> user data/docs Vault
                                            -> ordinary CLI/LSP/MCP/daemon access
                                            -> disposable per-Vault indexes

llms.txt 可以从同一 docs inventory 生成,用于网站上的被动发现,但它不是离线知识源,也不替代 Skill 的触发和工作流说明。

notist skill init 不接受用户 Vault root,也不把当前目录导出为 Skill。任意个人 Vault 可能包含 secrets、prompt injection、冲突指令、外部文件和不明确的发布权限;未来若支持这种发布,应使用独立命令与设计,明确 author metadata、文件选择、权限、secret scan 和 instruction/data 边界,不能扩展官方 Skill 初始化的含义。