PrivateGPT Workbench 的 AI 编码代理约定(ui/AGENTS.md):如何约束 Codex 等代理安全修改单文件演示 UI
本文以 ui/AGENTS.md 为核心,逐条解读 PrivateGPT 仓库中用于规范 Codex 及其他 OpenAI 风格编码代理在 ./ui 目录下工作流的约定文件,并结合 ui/README.md、ui/docs/SOURCE_OF_TRUTH.md、ui/docs/PRD.md、ui/docs/STYLE_GUIDE.md 与 ui/index.html 等真实文件说明每条规则的落地方式。读完本文,你将掌握一套可直接复用的“AI 代理 + 单文件前端”协作模式:强制阅读顺序、变更范围边界、文档同步纪律,以及一条可复制的 node 内联脚本校验命令。
一、背景:ui/ 是 PrivateGPT 的轻量演示层,AGENTS.md 是它的代理入口
PrivateGPT 是一个面向本地模型的完整 API 层,覆盖 RAG、skills、tools、MCP、text-to-Sql 等能力,可对接任意 OpenAI 兼容的推理服务。在此之上,./ui 目录中的 PrivateGPT Workbench 是一个轻量级静态演示 UI:它把 PrivateGPT 的 API 能力(文档问答、工具调用、代码执行等)变成可直观体验的产品界面,但刻意保持为“轻演示器,而非主产品”。ui/docs/PRD.md 明确写道:
This UI should remain a lightweight demonstrator, not the main product. It now lives inside the PrivateGPT repository under
./uiand must not become a heavy frontend application or a maintenance burden.
正因如此,ui/ 的组织方式极为克制——运行时实现全部收敛在单个文件里,其余全部是文档与参考资料。ui/README.md 给出的目录地图如下:
| 文件 | 职责 |
|---|---|
| ui/index.html | 唯一的运行时实现文件(全文件约 7974 行,内联全部 HTML/CSS/JS) |
| ui/AGENTS.md | Codex / OpenAI 风格代理的工作流约定 |
| ui/CLAUDE.md | Claude Code 的工作流约定 |
| ui/docs/PRD.md | 产品行为与信息架构需求 |
| ui/docs/STYLE_GUIDE.md | 视觉与交互方向 |
| ui/docs/SOURCE_OF_TRUTH.md | 权威路径、API 契约与文档所有权 |
| ui/references/ | 供风格指南使用的视觉参考图 |
ui/AGENTS.md 的标题是 “Codex Instructions”,开篇一句话点明服务对象:
This file is for Codex and other OpenAI-style coding agents working in
./ui.
它的结构只有三部分:Read First(强制阅读顺序)、Scope(变更范围边界)、Codex-Specific Notes(执行纪律)。下面逐节展开,并说明每条规则在仓库中如何被真实文件支撑。
二、Read First:代理动手前的强制阅读清单
ui/AGENTS.md 要求代理在“改变行为、UI 或 API 接线之前”,按固定顺序先读以下五个文件:
README.mddocs/SOURCE_OF_TRUTH.mddocs/PRD.mddocs/STYLE_GUIDE.mdindex.html
转换为仓库根相对路径即 ui/README.md、ui/docs/SOURCE_OF_TRUTH.md、ui/docs/PRD.md、ui/docs/STYLE_GUIDE.md、ui/index.html。这个顺序并非随意排列,它体现了一条“从地图到实现”的信息漏斗:
- README.md 提供目录地图。如上表所示,它先让代理知道每个文件管什么,避免把产品规则误写入运行时文件、或把参考图混进实现目录。
- SOURCE_OF_TRUTH.md 定义文档所有权。ui/docs/SOURCE_OF_TRUTH.md 用一节 “Working Rules” 明确划分:产品需求归
docs/PRD.md,视觉规则归docs/STYLE_GUIDE.md,代理专属规则归AGENTS.md和CLAUDE.md,参考图归references/,运行时代码归index.html。它同时指出 API 契约的权威来源是 Fern 生成的 fern/openapi/openapi.json,并特别强调“Do not maintain a duplicated UI-local OpenAPI snapshot”——即 UI 层不得维护第二份 OpenAPI 快照。 - PRD.md 描述产品行为。ui/docs/PRD.md(约 999 行)列举了 PrivateGPT 的能力清单(Chat/messages API、文件摄取、带引用检索、Text-to-SQL、CSV 沙箱分析、Web 搜索与抓取、MCP、Skills、自定义工具、Embeddings 与底层原语),并列出 Workbench 依赖的关键端点,如
POST /v1/messages、GET /v1/models、POST /v1/artifacts/ingest、POST /v1/primitives/search、POST /v1/tools/database-query等;同时要求实现必须以 Fern 生成的 OpenAPI 中ChatBody、MessageInput、ToolSpecBody、ContextFilter、FileArtifact、SqlDatabaseArtifact、McpServerConfig等 Schema 为准,PRD 中的示例仅作示意。 - STYLE_GUIDE.md 约束视觉语言。ui/docs/STYLE_GUIDE.md(约 599 行)规定深色氛围化工作区风格(深海军蓝/炭色底、细噪点纹理、毛玻璃面板、蓝橙紫渐变点缀),并声明 ui/references/ 下的四张参考图(如
primary-chat-layout.png、search-overlay.png、chat-tools-composer.png、context-knowledge-base.png)分别对应主聊天布局、搜索弹层、输入区与知识库面板的视觉基准;还要求 PrivateGPT Logo 以内联 SVG 方式直接嵌入index.html,使页面运行时不依赖外部 Logo 资源。 - index.html 才是实现本体。代理最后才读它,因为前四份文档已经回答了“要做什么、做成什么样、契约是什么”,最后一步才是对照现有代码。从源码看,ui/index.html 的
<script>块自第 3936 行起,状态持久化键为STORAGE_KEY = "privategpt-workbench-state-v1",API 基地址的默认逻辑是:window.location.origin === "null"(如file://直接打开)时回落到http://127.0.0.1:8080,否则使用当前 origin(见 ui/index.html)。这解释了演示 UI 既可以同源部署在 PrivateGPT 服务后面,也可以作为静态文件直接打开并指向本地 8080 端口。
三、Scope:变更的边界规则
ui/AGENTS.md 的 “Scope” 一节给出四条边界,其本质是把“低维护成本”这一 PRD 级目标翻译成代理可执行的动作:
- Keep the app as a simple static demo —— 保持应用是一个简单的静态演示,不允许代理顺手引入构建工具链、模块化拆分或重型框架。这与 PRD 中 “must not become a heavy frontend application or a maintenance burden” 直接对应。
- Keep
index.htmlas the only runtime implementation file unless the user explicitly asks ——index.html保持为唯一运行时实现文件,除非用户明确要求不同结构。ui/docs/SOURCE_OF_TRUTH.md 在 “Runtime Implementation” 一节同样声明../index.html(即 ui/index.html)是 Workbench 演示的唯一运行时实现文件,两份文档互为印证。 - Treat
docs/SOURCE_OF_TRUTH.mdas the canonical pointer to API contract paths and documentation ownership —— 把 ui/docs/SOURCE_OF_TRUTH.md 视为 API 契约路径与文档所有权的权威指针。也就是说,代理在“某条规则应该写在哪份文档、某个 API 路径以什么为准”这类问题上,不再自行判断,而是以该文件为准:契约指向 fern/openapi/openapi.json,文档归属按 “Working Rules” 划分。 - Update the relevant docs in
docs/whenever behavior, visuals, persistence, security posture, or API request/response handling changes —— 一旦行为、视觉、持久化、安全姿态或 API 请求/响应处理发生变化,必须在同一次变更中更新docs/下相应文档。ui/docs/SOURCE_OF_TRUTH.md 末尾重复了这条规则,且 ui/README.md 的 “Working Rules” 也以 “Keep docs and implementation aligned” 呼应,三处一致说明这是ui/模块最核心的纪律。
值得注意的是,ui/docs/SOURCE_OF_TRUTH.md 还专设 “Key Implementation Notes” 一节,记录那些“光读 index.html 看不出来”的实现事实,例如:Collection 名集中存放在 Settings 的 state.context.documents.defaultCollection 中;Appearance 覆写通过 applyAppearance() 驱动的 CSS 自定义属性生效;代码执行开启时必须把 chat.id 作为 container 字段随 ChatBody 发送以复用同一沙箱会话;文件上传走 POST /v1/files?scope_id={chat.id},下载走 GET /v1/files/{file_id}/content?scope_id={chat.id}。这类“非显而易见的实现注记”正是 Read First 清单中第二份文件的实际价值所在——它把散落在近 8000 行单文件代码中的隐性约定提炼成代理可快速检索的文字。
四、Codex-Specific Notes:执行纪律
ui/AGENTS.md 的 “Codex-Specific Notes” 针对代理执行过程定下三条纪律:
- Follow the validation steps documented in
README.mdanddocs/SOURCE_OF_TRUTH.md—— 遵循 ui/README.md 与 ui/docs/SOURCE_OF_TRUTH.md 中记载的校验步骤,而不是自创校验方式。 - If implementation and docs disagree, fix the disagreement in the same change —— 如果发现实现与文档不一致,必须在同一次变更中修掉这种不一致,不允许“先改代码、文档以后再补”。
- When finishing work, summarize what changed, what validation ran, and any known limitations —— 完成工作时必须总结:改了什么、跑了哪些校验、存在哪些已知限制。
这三条与 “Scope” 第 4 条共同构成了一个闭环:文档是契约 → 契约变化必须随代码同步 → 不一致必须当场修复 → 交付时主动披露校验情况与局限。
校验命令:README 中的一行 node 脚本
AGENTS.md 要求遵循 README 中的校验步骤,该步骤即 ui/README.md 给出的这条命令(在仓库根目录执行):
node -e "const fs=require('fs'); const html=fs.readFileSync('./ui/index.html','utf8'); const m=html.match(/<script>([\s\S]*)<\/script>/); if(!m) throw new Error('script tag not found'); new Function(m[1]); console.log('script ok')"
这条命令的作用是把 ./ui/index.html 中第一个 <script> 块的完整内容用正则提取出来,交给 new Function() 做一次语法解析;若找不到 script 标签则抛错,解析通过则输出 script ok。它不启动浏览器、不访问网络,是一条零依赖的“内联脚本语法门禁”,恰好匹配“单文件运行时”的结构:整个应用的 JS 都在一个 script 标签里,校验它即可拦截最常见的回归——JS 语法错误。这也解释了为什么单文件结构反而是优点:校验目标明确、无构建步骤、代理改动后可立即自检。
五、AGENTS.md 与 CLAUDE.md:同一契约的两个入口
ui/ 目录同时维护了第二份代理约定文件 ui/CLAUDE.md,服务对象是 Claude Code:
See @README.md, @docs/SOURCE_OF_TRUTH.md, @docs/PRD.md, and @docs/STYLE_GUIDE.md before editing
index.html.
两份文件的分工可以从源码结构看得很清楚:核心规则(保持静态单文件、以 SOURCE_OF_TRUTH 为权威指针、行为/视觉/持久化/安全/API 处理变化时同步文档)在两份文件中保持一致;差异只在“入口习惯”——AGENTS.md 用编号列表给出五份必读文件(含最后的 index.html),CLAUDE.md 则用 Claude Code 的 @file 引用语法压缩成一句话,并且多出一条代理专属提示:“Use the shared docs above as the source of truth instead of duplicating product or design rules here”(以共享文档为准,不要把产品/设计规则复制进代理指令文件)。这种“规则集中在共享文档、代理文件只保留入口与专属纪律”的做法,避免了多份代理文件各自演化后互相矛盾。
六、设计启示:这套约定的可复用要点
把 ui/AGENTS.md 放到整个 ui/ 目录的背景下看,它示范了一套适合“AI 代理参与维护的静态前端”的工程约束,可归纳为五点:
- 单一运行时文件 + 单一契约来源。实现只有 ui/index.html 一个文件,API 契约只认 fern/openapi/openapi.json 一份(且明确禁止 UI 本地快照)。代理的决策空间被压缩到最小,幻觉与漂移的余地也最小。
- 固定的阅读顺序代替模糊的“先看文档”。Read First 清单把“理解项目”拆成确定性的五个动作,顺序从目录地图(README)到所有权定义(SOURCE_OF_TRUTH)再到需求(PRD)、视觉(STYLE_GUIDE)、最后才触碰代码(index.html)。
- 文档所有权显式化。“Working Rules” 逐条规定哪类内容住哪个文件,代理改任何一类内容时都能唯一确定落点。
- 同变更同步纪律。“实现与文档不一致时,在同一变更中修复”把一致性从口头要求变成验收项;配合 “Key Implementation Notes” 记录隐性实现事实,文档始终能跟上近 8000 行单文件代码的演化。
- 可执行的轻量校验。一行
node -e命令即可完成内联脚本语法门禁,与交付时“说明改了什么、跑了什么校验、有哪些局限”的总结要求配套,形成最小但完整的验证闭环。
七、小结
ui/AGENTS.md 全文不长,但它与 ui/README.md、ui/docs/SOURCE_OF_TRUTH.md、ui/docs/PRD.md、ui/docs/STYLE_GUIDE.md 一起,构成了 PrivateGPT Workbench 这套“代理工作流”的完整契约:五步强制阅读顺序定义了信息获取路径,四条 Scope 规则定义了变更边界,三条 Codex-Specific Notes 定义了执行与交付纪律,而 ui/README.md 中的一行 node 命令则提供了可立即复制执行的校验手段。对于任何需要在单文件静态应用中引入 AI 编码代理的团队,这套“共享文档承载规则、代理文件只做入口、同变更同步文档、最小语法门禁”的模式都是值得参照的范本;而阅读它的最佳入口,正是按 AGENTS.md 指定的顺序,从 ui/README.md 读起。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0624
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00