一个提示词写到第 20 次迭代,最初那版还在不在?大多数工具的答案取决于你当年有没有手动备份。Syzygy 1.2.0 把提示词和技能当资产管理,用不同的动作区分编辑中的草稿与正式发布的版本。这一篇拆的是 1.2.0 里提示词与技能工作台的五个设计决定,每个都对应一种具体的腐烂方式。
保存草稿、发布版本,再恢复为工作内容
提示词的存储是一个提示词一个 TOML 文件,单文件上限 1 MiB,身份就是文档里的 name 字段。资源发现接受根目录下任意位置、任意文件名的 *.toml,用户在文件管理器里搬动或改名提示词文件是合法操作。这个决定推出来一条硬约束:资源身份是用户可见的名字,永远不当文件系统路径用。
提示词目录本身有一层 git,.git 就住在 TOML 文件旁边。保存会原子写入工作草稿;显式发布才分配下一个已发布版本,并创建类似 "publish prompt: 名字 (v7)" 的提交。Git 提交失败时,工作文档中的发布变化会回滚。创建草稿或移入回收站都不等于发布。
对老数据的处理也在这层:早期版本的历史是内联在 TOML 里的 revisions 数组,启动时会把每个文件的旧版本按时间顺序改写成真实的 git 提交("legacy v1: 名字"),然后写入当前版。迁移是幂等的,已有 git 历史的文件跳过。
历史视图里每条记录是一个真实的 git 对象:完整哈希、8 位短哈希、提交消息、作者和时间戳,作者记录来自相应的提交。diff 视图是逐行的统一差异格式,由存储层生成,同一个文件相邻两次提交之间改了什么一目了然。
实现选了 gitoxide(gix 0.87)而不是 libgit2(git2-rs),理由是一笔打包账:Syzygy 要出五个端,macOS(公证加自动更新)、Windows、Linux(AppImage 签名)、iOS(App Store 审核中)和 Android。git2 意味着把一个 C 库带进全部五条构建和签名流水线;gix 是纯 Rust,跟着工作区的工具链一起编过就行,workspace 里声明 default-features = false 加一组精选 feature(blob-diff、revision、status),不编译网络和工作树检出这些用不上的部分。提示词版本管理需要的全部能力是写 blob、写树、提交和逐行 diff,gix 的这些入口够用。
历史接口提供三个命令:prompt_git_history_v1 按文件或全库列提交,prompt_git_diff_v1 出统一 diff,prompt_git_restore_v1 把某个提交的文件内容原子写回。恢复只把选定版本写回工作内容,不自动创建新提交。用户可以检查、继续编辑,再决定是否显式发布成新版本。
已发布版本与工作草稿分工明确。修改正文、变量或附件后保存,不会分配已发布版本号;显式发布推进 publication sequence,并将版本记录到 Git。删除某个已发布版本不会复用它的序号,也不会丢弃工作草稿。Git 历史记录发布节点,不记录每次草稿保存。

编辑过程中可以随时保存草稿,需要保留一个版本节点时再显式发布。
附件按内容寻址,引用跟着文档走
提示词要带图片和文件。常见做法是按提示词建附件目录,Syzygy 明确不这么做:按提示词分目录,就得给目录起名字,而名字要么取自提示词名(提示词名可以是 ../.. 这类字符串,同名清洗还会撞车),要么取自派生值(重命名即失联)。取消这一层,问题整个消失。
附件字节按内容哈希存进一个扁平共享目录 <data_dir>/prompt-assets/<hash>.<ext>,哪个提示词用哪些附件只记在提示词自己的文档里,正文用 {{@附件名}} 引用。这带来三个性质。
一是跨提示词去重:同一张截图被十个提示词引用,磁盘上只有一份字节,手工复制一份提示词文件来"另存",两份自然共享同一批资产。二是重命名免疫:重命名提示词不移动任何附件,重命名附件会强制同步改写正文里的引用,链接在文档内部而不在路径上,用户在文件管理器里怎么折腾提示词文件,附件都跟着走。三是引用回收:永久删除只回收不再被任何提示词引用的字节,提示词目录常驻内存,删除前做一次内存内的引用扫描。这一步必须真的做,跳过它就会删掉别的提示词还在用的字节。
取舍同样明确:哈希目录在文件管理器里没法按提示词浏览(附件条目保留"在文件管理器中显示",导出时再物化成可读文件名);清单不进版本历史,回看旧版本时如果引用的附件已删了,界面显示"引用已失效",不擅自补造资产。单附件上限 64 MiB,上传时同名自动去重命名(image.png 变成 image-2.png),因为粘贴截图会不断产生同名文件。跨设备分享走受校验的 ZIP 导入导出:逐文件校验 CRC 和 BLAKE3,拒绝符号链接、加密条目和路径穿越,边界参数包括最多 128 个附件、解压后累计 256 MiB,create-only 导入,不覆盖已有提示词。
如果你是会把常用提示词打包发给同事的人,ZIP 往返保证对方拿到的是完整文档加全部附件,且对方导入时会生成副本,不会覆盖他自己同名的东西。
变量有五级,值的来源跟着值走
提示词正文里的 {{name}} 从哪取值?Syzygy 的解析器按五级优先级合并:资产默认值最低,然后是工作区默认值、所选环境的值、本机覆盖,调用时显式传入的值最高。五级之上还有一层只读的系统上下文,成员来自实际上下文:语音转写的 transcript、日期、时间、语言、区域设置,任何一层试图覆盖系统上下文都会直接报错,这个口子是焊死的。
每解析出一个值,都带着它的来源标记。调试一个"为什么发出去的提示词里有错的团队名"时,你能看到这个值来自工作区默认还是环境覆盖,不用五层翻配置。声明为必填的变量在所有层级都没取到值时,解析直接失败,错误信息指名缺哪个变量,渲染不会拿着空字符串继续跑。
值的类型也是强制的:secret 是独立的值类型,类型系统保证它不会被当普通字符串拼进渲染上下文。预览和请求走的是同一条渲染路径,先按当前绑定渲染,再对渲染结果做隐私检查。源文里没有隐私,变量解析出来是邮箱,预览就该按有隐私处理。详情页的 Source 视图永远显示原文,包括花括号,不插值;Preview 和 Source 是两种视图,切换 Source 也不是解锁操作。
变量名本身有语法:1 到 64 个字节的 ASCII 标识符,字母或下划线开头。解析只做一次替换,变量值里的 {{other}} 不会递归展开,不存在的变量和未闭合引用原样保留在文本里。环境层的值来自你在应用里配置的环境,解析器无权读取任意操作系统环境变量,更不执行任何代码取值。
如果你是在团队里维护一套共享提示词库的人,五级结构让"库里的默认值"和"我个人环境里的覆盖"各归各位,改默认值不会踩掉任何人的本地覆盖。
斜杠菜单把后果编码进前缀
AI 输入框里的 / 打开一个菜单,里面有两类东西:内置命令(/clear、/search、/thinking、/tools、/help,选中即执行)和三个限定符前缀:/prompt:、/skill:、/file:。
设计点在前缀本身。输入 /prompt: 之后,模糊匹配只在提示词池里进行,选中一条会把提示词正文替换进输入框;/skill: 的池子是技能,选中插入的是技能引用标记,激活哪个技能是在消息文本之外单独确定的;/file: 选中插入文件。也就是说,前缀把"选中之后会发生什么"编码进了入口:用户在按回车之前就知道这次插入的是全文、一个引用还是一个文件路径。菜单不用描述文案来解释行为,前缀就是行为。
内置命令排在菜单最前面,这个顺序是故意的:一次按键就能到达 /clear,限定符跟在后面。语法刻意收紧:整个输入必须仍是单个 token,出现空格或换行菜单就退出,因为空格意味着用户已经开始写自然语言;限定符后的过滤文本是自由模糊文本,标题命中恒排在描述命中之前;全角冒号 : 和半角冒号等价,限定符支持中文别名(/提示词:、/技能:、/文件:),大小写不敏感。加一种新的资产类型是注册表里加一个条目,不是给菜单写新语法。

如果你是键党,这套语法的实际效果是:/clear 一次按键直达,/pro 三个字符就能在提示词池里模糊定位到目标。
技能注册表:去重止于展示,文件永远属于磁盘
技能是一份 SKILL.md 为入口的包。注册表由一份来源列表驱动:用户添加若干目录来源(路径模板支持 home、环境变量、应用数据目录),可以开关、移除、排序,文件系统监视器盯着这些目录,外部改动会反映进目录快照。
扫描是节制的:常规扫描只读 SKILL.md,文件树和附件按需懒加载,预算写死在代码里,SKILL.md 上限 256 KiB,可编辑文件上限 1 MiB,扫描深度 8,每个来源最多一万个目录、两千个包。扫描不是"接管",被索引的外部目录不会变成应用可回收空间,移除来源不删除任何文件。
来源不止是路径列表,它同时组织呈现。在 /skill: 菜单里不做过滤时,技能池按来源分成小节展示,每个小节标着来源标签和条数;扫描到的技能默认可编辑,写入以系统权限和包内路径安全检查为准,来源 symlink 的解析和包内路径逃逸是两条不同的边界,后者始终拒绝。
去重只发生在展示层:两个来源各有一份 SKILL.md 字节完全相同的技能时,列表按原始字节的 SHA-256 去重,保留首个有效实例并记录重复来源;同名但内容不同的包全部保留,身份、内容版本、包版本、展示名是四个分开的概念。这条边界的含义是:应用不假装知道两个同名包"其实是一个",内容不同就是不同资产。
激活侧绑的是内容本身。目录里每个有效条目带一个 instructionDigest,即技能指令内容的摘要;一次 AI 激活携带这个摘要,把请求和当时扫描到的字节绑定。目录快照过期时,条目仍可查看,但任何条目都不能变成 AI 激活,刷新拿到新快照后才恢复;这条规则保证 AI 拿到的技能指令不会是内存里的旧版本。新建技能从一份完整标准的 SKILL.md 模板开始,frontmatter 用强类型解析、按标准键序回写,正文原样保留,注释掉 frontmatter 的"简化视图"不存在。

如果你是 GitHub 上收集了一堆 Claude/Agent 技能包的用户,把目录挂成来源就能用,移除来源原目录毫发无损,重名包不会被静默合并。
这套东西的边界
照实说三点。第一,prompt git 是单机历史,不跨设备同步,提示词及其附件与剪贴板条目一样留在本机,同步边界以后单独谈。第二,技能目前是"指令包":注册表解决发现、去重与内容绑定,技能的执行授权和 MCP 生命周期是另外的边界,文件 API 不执行技能脚本。第三,原生跨平台的文件行为实测仍在进行,已完成的验证是 Rust 侧 1066 个测试、fmt/check/clippy 门禁和 Windows GNU/Linux 目标编译,这些数字属于 2026-09-23 那轮实现记录,不自动覆盖后续平台。补充一句结构上的事实:提示词、技能和记忆的文件级变更事件由同一个事件运行时统一转发,三个领域各自保留自己的业务规则,共享的只是事件管道,不是所有权。
入口分三处:提示词页管理模板、变量与历史;技能页管理来源与包;AI 输入框的斜杠菜单负责把资产送进对话。提示词可以打标签、可以带附件、可以导出成受校验的 ZIP,这几件事的组合让"攒了一套自己的提示词库"从口头习惯变成可迁移的资产。
提示词与技能工作台不是独立产品,它是同一个 AI 工作台的资产层:本地大模型篇讲的是算力从哪来,这一篇讲的是喂给算力的资产怎么管。两边的决策记录(ADR 0003、0010、0059、0061)都在仓库里,随版本发布。
常见问题
Syzygy 的提示词版本历史是怎么做的?
每个提示词是一个 TOML 文件,提示词目录本身就是一个 git 仓库。保存更新工作草稿;显式发布才分配版本并通过纯 Rust 的 gitoxide(gix)写入 Git 提交。历史与差异命令用于查看已有提交,恢复则把所选版本写回工作内容,检查后可再决定是否发布。
提示词附件存在哪里,会不会重复占空间?
附件字节按内容哈希存在共享目录 prompt-assets/ 下,不按提示词分目录。同一张图被多个提示词引用只占一份字节;永久删除时只回收不再被任何提示词引用的附件。
技能来源被移除后,技能文件会被删除吗?
不会。移除来源只是把它从注册表摘除,不删除磁盘上的任何文件,外部目录也不会因为被索引而变成应用可回收的空间。同名不同内容的技能包会保留多份,去重只作用于展示层。