spec 1.0 · 规范性
机器可读接口
五种产物让工具能够读取上下文层。除此之外,上下文层中的内容都是以人为主要读者、同时供智能体读取的散文;只有这五种产物构成工具所依赖的契约。
| 产物 | 默认位置 | Schema |
|---|---|---|
| 清单 | leji.json(仓库根目录,固定) |
context-manifest.schema.json |
| 上下文索引 | <root>/context-index.json |
context-index.schema.json |
| 上下文变更日志 | <root>/context-changelog.json |
context-changelog.schema.json |
| 智能体配置 | <root>/agents/*.md(frontmatter) |
agent-profile.schema.json |
| 决策记录 | <root>/decisions/*.md(frontmatter) |
decision-record.schema.json |
除清单外,所有位置都由清单声明;上表给出的是默认值。
要求#
- 清单。
leji.json必须存在于仓库根目录,并通过其 schema 校验。它是 Leji 中唯一固定的文件名:工具可以稳定寻找的那个文件。 - 索引。声明
indexed及以上一致性级别的上下文层必须携带一份上下文索引,且该索引是生成的,绝非手工维护:工具把类别索引文件(categories.<id>.indexes,见 content-categories.md)解析为它们所列的文档,并为每一份受治理的文档写入一条条目。每条条目携带稳定的id、一个path、一个title和一个category标识符。生成器应当同时输出文档的kind(intent或record);它在 schema 中是可选的,以便在类型概念出现之前写就的索引依然有效,消费者把缺失值视为intent。当文档声明了合法的 frontmatterdate时,记录的条目还额外携带该日期;生成器只从 frontmatter 取日期,绝不从散文或文件名约定中取。过期的索引(不再与索引文件所解析出的内容一致)必须被视为校验失败。声明了federation.mounts的宿主层,还要在同一份索引中携带一个顶层的mounts数组:每个挂载一条路由记录(name、source、pin、声明时的trackingRef、owner、声明时的role,以及路由元数据categories/topics/requiredWhen)。它们只是路由记录;工具不得把某个同级层的条目或散文复制进宿主索引,而一条挂载记录也不携带任何宿主层受众不该看到的内容(见 distribution.md 的“受限挂载”)。 - 变更日志。声明
indexed及以上一致性级别的上下文层必须携带一份机器可读的上下文层变更日志。条目携带稳定的id、一个 UTCdate、一个type、一行summary,以及受影响的paths。权威顺序是推导出来的,而不是由位置决定的:工具必须按(date, id)升序排列条目,数组位置不承载任何含义。由于id在变更日志内唯一(见“标识符”),即便两次变更共享同一个date,(date, id)仍是全序。留存的条目不可变:只要工具能够确定先前状态,就必须把对已发布条目的修改视为校验失败,而重排数组不算修改。确定先前状态需要一个可供比较的独立基线;当参考工具只有当前版本时(例如普通的持续集成工作副本),这种修改对它不可见,此时是变更集的评审把它抓出来(见 conformance.md)。变更日志用于呈现近期变更,而不是保存完整历史:长期存续的上下文层应当对它做压缩,而不是任由它无限增长;并且可以随时压缩,做法是从该顺序最旧的一端移除条目,前提是同一个变更集追加一条compaction类型的条目,其compacted字段记录被移除的数量以及首尾两个被移除的 id。移除最旧条目以外的任何内容、没有 compaction 条目的移除,以及压缩到空文件,都是校验失败。仅可追加的纪律以id为键在集合意义上成立,并对照先前提交的状态检查,因此它在撰写时需要 git;文件本身对消费者而言与 git 无关,完整记录由 git 历史保存。触及受治理文档(类别索引文件解析出的那些)的变更集必须追加一条条目,其paths覆盖它改动过的受治理路径,使每一份被改动的受治理文档都落在某条被追加的条目之下:仅可追加的纪律保证已发布条目不可变,而这条覆盖规则保证记录完整。可以在旁边另有一份人类可读的变更日志;工具读取的是这份 JSON 记录。 - frontmatter 产物。智能体配置与决策记录是 markdown 文档,其 YAML frontmatter 需通过各自的 schema 校验。散文正文保持自由形式;frontmatter 才是机器契约。不得强制要求纯 JSON 的配置或决策:这些文档是给人读的。
- 标识符。所有
id值一经发布必须保持稳定:重命名与移动更新的是path,绝不是id。标识符为小写、以连字符分隔,在其产物类型内唯一。生成的索引条目的id按优先级顺序推导:文档 frontmatter 中声明的id(若有);否则是已存储索引中同一路径已经携带的id,或者对于纯粹保留内容的移动,是同一内容已经携带的id;否则是文件名的 slug,并与其父目录去重。第一个存在的胜出,因此已发布的id能挺过重命名或移动,只有全新的文档才会铸造新的 id。既可能被移动又可能在同一个变更集中被编辑的文档应当声明 frontmatterid:只有 frontmatter 能在路径与内容同时变化时锁住 id(按路径承继与按哈希承继两种兜底都会落空),并且当某个已存储的 id 消失时,工具会告警(id-vanished),使它留下的悬空引用能被发现。 - 时间戳。变更日志的
date值是 UTC 的 ISO 8601:要么是日历日期YYYY-MM-DD(按当天起点T00:00:00Z排序),要么是以Z结尾的整秒时间戳(例如2026-06-13T15:04:05Z)。不带时区的时间、非 UTC 偏移与小数秒不允许:小数秒会破坏“对date做字典序排序即时间顺序排序”这一保证,因为…05.1Z明明更晚,却排在…05Z之前。所有产物中的每个日期字段都受日历范围约束,因此月份为13或日为99都是非法的。其他产物的日期遵循 ISO 8601,且可以只到日期。路径为 POSIX 风格,相对仓库根目录,不带前导./。 - 除清单外,每一个 JSON 产物必须声明它所依据撰写的 schema 版本系列(
schemaVersion),见 versioning.md;清单则以自命名的leji键声明它面向的规范版本系列。 - 派生产物继承访问约束。索引、变更日志、生成的查看器,以及任何由上下文层内容构建的编译或导出视图,都是派生产物,智能体基于这些内容产出的输出同样如此。派生产物承载它所取材的内容中最受限那部分的访问约束。不得在没有明确的、经过评审的脱敏步骤(该步骤产出面向该受众的独立产物)的情况下,把派生产物写入或复制到受众比该内容更广的位置;智能体也不得把受限上下文引用或摘要进受众更广或访问限制更少的内容载体(拉取请求、工单、聊天、提交信息或公开的上下文层)。一个受限上下文层的索引,可能与它的散文一样敏感:标题、路径与摘要都在描述它。这是对操作工具的人与智能体的约束,而不是工具执行的检查:Leji 没有定义任何工具可读、可据以计算“更广受众”的受众模型(访问权属于版本控制系统,见 governance.md 的“访问边界”),因此参考 SDK 不强制执行它,工具至多只能告警(查看器导出会提示要私有部署)。
任务路由#
索引、类别归属与决策记录之所以存在,是为了让智能体加载一项任务所需的那一片上下文,而不是整棵树。本节以规范性的方式定义任务作用域如何选出那一片。它是本规范其余部分所引用的唯一路由算法:引导配置的“加载”一节(boot-profile.md)用任务语言把智能体指向这里,决策记录的作用域(decisions.md)由它来匹配,联邦读取(distribution.md)也复用它来判定任务触及哪些同级层。路由读取的是上下文;它不是任务信封,也不是执行协议,那些都留在 1.0 之外(见 README.md 的“扩展边界”)。
- 输入。一项任务的作用域,是它读取或改动的、相对仓库根目录的 POSIX 路径集合(按要求 6 归一化:POSIX 风格、相对根目录、不带前导
./),加上任务显式点名的类别,以及任务显式点名的主题。主题是显式输入:算法绝不从路径、类别、散文或内容中推导它们。智能体或工具如何从任务推导出作用域不在规范范围内;下面的匹配则在范围内。 - 路径匹配(字面、双向)。一个声明的路径与一个任务路径匹配,当且仅当归一化之后(POSIX 风格、相对根目录、不带前导
./、去掉任何尾随/)两个字符串相等,或者其一是另一个的路径前缀祖先:较短者等于较长者在某个/边界处截断后的结果。匹配是纯字面的:它绝不查询文件系统,也不区分某个路径指向的是文件还是目录,因为归一化之后二者无从分辨。这是双向的包含关系(各参考实现共用的underPath关系),因此作用域宽泛的任务与声明狭窄的选择器,无论哪一边更宽都能互相找到。 - 类别匹配(狭义),以及两个类别集合。一项任务的类别分为展开与示意两类。任务显式点名的类别同时进入两个集合。若某个任务路径本身就是一份受治理的文档(按完全相等匹配到它生成的索引条目,绝不按包含关系),则它把该条目的类别只贡献给示意集合。展开类别会加载它的意图文档与记录候选;示意类别只是决策与联邦挂载的匹配信号,自身不加载任何东西。类别选择器不得为仓库中的任意文件推断类别,而本身不是受治理文档的任务路径,包括受治理文档的任何祖先目录,都不贡献任何类别。路径作用域触及文件;类别展开不随之延伸。
- 主题匹配(精确、仅限挂载)。主题是由 Unicode 标量值构成的非空字符串,按其 UTF-8 编码比较;孤立代理项不是合法主题。两边都受这条规则约束:任务主题或挂载
topics中不是由 Unicode 标量值构成的非空字符串的条目属于输入错误,实现必须拒绝它,而不是当作静默的不匹配返回。任务主题与声明主题匹配,当且仅当两个解码后的字符串完全相等。实现不得对任一边做大小写转换、Unicode 归一化、按区域设置比较、裁剪、分词、子串匹配或模糊匹配,因此规范等价但字节不同的写法不会匹配;这条相等规则与下文结果的按字节排序是两回事。重复的任务主题构成一个信号,因此点名两次与点名一次的匹配结果完全相同。当任何任务主题等于某个挂载所声明的任何主题时,该联邦挂载匹配。主题匹配只选中挂载本身:它不得进入展开或示意类别集合、加载任何文档或记录、路由任何决策、求值requiredWhen,也不得使某个挂载成为必读。 - 状态过滤。只有
status具有约束力的决策记录才作为当前指引被路由。accepted与deprecated具有约束力;deprecated的记录带着过期的姿态生效,智能体必须把它当作正在退场的指引,而不是已成定论的当前实践。superseded的记录不得具有约束力,只能作为历史,并必须携带supersededBy;proposed与rejected的记录不得具有约束力。具有约束力的记录称为live。 - 无作用域的决策。既未声明
affectedPaths也未声明affectedCategories的 live 决策记录是组织级的:无论任务作用域为何,它对每一项任务都被路由。带作用域的 live 决策,只有在任务按路径(第 2 条)或按类别(第 3 条)与之匹配时才被路由。 - 空路径作用域,以及空作用域。当任务的路径集合为空时,路径匹配不贡献任何东西,智能体必须声明未曾求值按路径的路由;显式点名的类别仍然生效并仍会展开,显式点名的主题仍会被匹配。点名的类别与点名的主题都算作非空作用域。只有当任务既未点名路径、也未点名类别与主题时,它的整个作用域才为空;此时智能体只路由无条件的引导配置与智能体配置上下文,加上组织级的无作用域 live 决策。智能体不得把一次未经路由的加载呈现为经过作用域筛选的结果。
- 记录作为候选被路由。展开类别把它的意图文档作为必需上下文路由;该类别的记录则单独返回,各自带上类型与日期,作为读者凭判断加载的候选。记录只有在以下情形才成为必需:任务的路径按第 2 条直接选中它;智能体或引导配置点名它;或者有人要求它。仅仅因为是类别匹配,或者因为日期最新,绝不使一条记录成为必需。当某条记录既是类别候选、又被路径直接选中时,直接选中胜出,它是必需的。路由不得把任何记录认定为“最新的”或“当前的”:1.0 没有定义记录系列的身份或顺序保证,因此新近度的判断属于读者,依据索引呈现的日期来做。决策记录保有自己的路由方式(第 5、6 条),绝不作为普通记录被路由。把某个决策文件作为任务路径点名,并不会路由那个决策;决定它的是它声明的作用域。
- 引用。加载了被路由决策记录的智能体必须说明自己加载了哪些匹配到的记录,使读者能看到智能体应用了哪些指引,并据此推断它没有应用哪些。
被路由的那一片就是智能体为一项任务所加载的内容。它是以下各项的并集:引导配置的无条件加载集合与当前生效智能体配置的 requiredRead(智能体把它们作为与任何作用域无关的基线持有);每个展开类别中的每一份受治理意图文档;任务路径按第 2 条选中的每一条受治理条目;按第 8 条被路径直接选中的每一条记录;以及任务按路径、或按示意或展开类别匹配到的每一条 live 决策,再加上组织级的无作用域 live 决策。
示意类别只贡献匹配,作用于决策与联邦挂载,绝不展开任何语料。
路由结果不是完整信封。计算路由的工具在返回所选内容的同时,还会返回智能体不得在无人提示时加载的材料:记录候选及其候选路由元数据。如果不加区分地加载整个信封,路由也就失去了意义。
结果顺序具有规范性(当工具输出顺序时),以便各独立实现逐字节一致:类别按本规范的权威类别顺序;文档、记录与决策按路径升序;挂载按名称升序。字符串比较是按 UTF-8 字节进行的,不依赖区域设置或码点排序规则。
工具可以提供一个由路径集合计算这一片的辅助函数;各参考实现都提供了一个(route)。这类辅助函数计算的是依赖作用域的那部分,并不要求输出基线,因为调用方本就持有基线;智能体加载该基线的义务不变。只要一个原始读取者照此算法执行,路由即为符合规范。
注记(非规范性)#
参考工具目前会检查变更日志的 schema 与仅可追加纪律(leji validate 两者都跑);对照某个基线版本验证变更日志的覆盖度,即每一条被改动的受治理路径都出现在某条被追加的条目中,是路线图上的一项报告式检查,尚未成为阻断性关卡。在它发布之前,覆盖度靠流程担保的评审与 CI 纪律来保障(见 conformance.md)。
索引是受治理上下文的导航来源:leji viewer 根据索引呈现受治理的主干,并在下方将仓库自身的目录树显示为可浏览的参考区,因此同一个视图既包含受治理的上下文,也保留团队原有的导航。其他文档工具也可以用相同方式投影索引。具体呈现方式不属于规范范围。这个接口有意保持精简:五种形态足以让工具校验上下文层、比较差异、评估时效性,并将智能体路由到正确内容;数量又足够少,团队可以记住整个接口。超出这五种形态的内容属于 1.0 之后的范围,将由实践中的真实需求决定。