Wails v3 的 AI Agent 协作规范与 Streams 运行时架构深度解析
【免费下载链接】wailsCreate beautiful applications using Go项目地址: https://gitcode.com/gh_mirrors/wa/wails
本篇指南围绕仓库根目录下的 AGENTS.md 展开,系统解读该 Wails v3 项目为 AI Agent(含 GitHub Copilot、Claude 等编码助手)制定的工程协作规范:从 GitHub Issue 驱动的任务流转、
history/临时文档治理、coderabbit质量门禁,到前端运行时双构建产物的机制,再到 Streams 传输层内部文档的源码级解读。读完你将掌握在 Wails 仓库中正确发起协作任务、构建运行时、接入 Streams 以及安全收尾会话的完整流程,并能在v3代码库中精准定位每项规范背后的实现证据。
1. 这份 AGENTS.md 是什么
AGENTS.md是 Wails 仓库专门写给AI 编码代理(而非人类贡献者)的“行为契约”。它解决的核心矛盾是:当 AI 以半自主方式参与 Issue 管理、代码生成、文档整理和 Git 提交时,如何保证工作流可追踪、可审计、不破坏项目既有约定。
从内容结构看,它由四大部分组成:
- GitHub Issue 工作流:确立 GitHub Issues/PR 为唯一权威追踪器;
- AI 生成规划文档的治理:约定临时文档统一放入
history/目录; - 前端运行时双构建产物:澄清
@wailsio/runtime两种输出物及其消费方,避免“只重建一半”的经典错误; - 会话收尾(Landing the Plane):规定结束工作会话时的强制步骤。
以下各节将逐项拆解,并补充仓库中的源码、配置与测试证据。该文档本身不包含可执行代码示例,因此本文会将其规范与v3/目录下的实际实现对应起来,帮助读者把“规则”映射到“代码”。
2. Issue 驱动的协作工作流
2.1 权威追踪器原则
AGENTS.md 首先强调一条硬性约定:
GitHub Issues 与 Pull Requests 是本项目唯一的权威追踪器,禁止在本地平行维护一套 Issue 数据库或 Markdown 任务清单。
这意味着 AI 代理不得在仓库内新建TASKS.md、TODO.md之类的文件来替代 Issue 系统。该约定与仓库中的自动化配置相互印证——.github/workflows/labeler.yml 负责自动打标签、.github/workflows/stale-issues.yml 负责清理陈年 Issue、.github/workflows/redirect-enhancement-issues.yml 负责 issue 重定向,全部围绕 GitHub Issues 生态运转。
2.2 建议的代理工作流
文档给出五步工作流,可直接作为 Agent 的 checklist 使用:
- 先搜索后创建:在新建 Issue/PR 前,先检索现有条目,避免重复(仓库中 .github/workflows/pr-master.yml 等 PR 检查流水线会进一步保证合入质量);
- 工作与 Issue/PR 建立关联:实现代码必须链接到对应 Issue 或 PR;
- 新发现的可行动工作:以 GitHub Issue 形式登记,附上复现细节、影响范围、验收标准三要素;
- 用标签/里程碑/交叉引用表达语义:优先级用 labels,发布范围用 milestones,依赖关系用 cross-references;
- 关闭 Issue 的唯一条件:工作已完成且验证通过;否则必须写明延期或不再适用的原因。
2.3 强制规则
- 不得重复已存在的 Issue;
- 当 Issue 范围或复现步骤变化时,及时更新描述;
- AI 生成的规划文档存放在
history/,而非仓库根目录; - 提交前必须执行
coderabbit --plain,提前暴露问题(详见第 4 节); - 所有提交必须使用
taliesin-ai身份; - 在用户明确手动确认之前,绝不 push。
3. AI 规划文档的存放治理(history/ 目录)
AI 在开发过程中往往会生成 PLAN.md、ARCHITECTURE.md、DESIGN.md、CODEBASE_SUMMARY.md、INTEGRATION_PLAN.md、TESTING_GUIDE.md、TECHNICAL_DESIGN.md 等临时规划文档。AGENTS.md 明确建议:
- 在项目根目录创建
history/目录; - 所有临时的 AI 规划/设计文档统一放入其中;
- 仓库根目录保持整洁,只保留永久性项目文件;
- 仅在被明确要求回顾历史规划时访问
history/。
文档还给出了可选的.gitignore片段:
# AI planning documents (ephemeral) history/其收益包括:根目录整洁、临时与永久文档分离、按需排除出版本控制、保留“考古式”的规划历史、降低浏览项目的噪音。仓库中 history/beta-readiness-audit.html 正是这种治理实践的现存示例——它是一份 beta 就绪审计文档,被收纳在history/而非仓库根目录,印证了该规范的实际落地。
4. 提交前的质量门禁:coderabbit 与提交身份
AGENTS.md 规定了一条不可省略的命令:
coderabbit --plain--plain表示以纯文本(无交互、无花哨输出)方式运行 CodeRabbit 代码审查,在提交前捕获潜在缺陷。CodeRabbit 作为 AI 审查机器人,其价值在于把“过早合入问题代码”的成本前移——这与仓库的 CI 策略互为补充:例如 .github/workflows/semgrep.yml 提供静态安全扫描,.github/workflows/build-and-test-v3.yml 提供构建与测试矩阵,而coderabbit --plain则是开发者/AI 在本地提交前的最后一道人工(机器)审查。
配套的提交身份约定为:
所有提交必须使用
taliesin-ai身份;未经用户显式手动确认,绝不 push。
这保证了仓库历史中 AI 提交可被统一识别与回溯。
5. 前端运行时:必须理解的两个构建产物
AGENTS.md 明确指出,v3/internal/runtime/desktop/@wailsio/runtime下的 TypeScript 运行时会产生两个相互独立的产物。只重建其中一个而忽略另一个是常见且极易混淆的错误:
| 任务 | 产物 | 消费方 |
|---|---|---|
task v3:runtime:build:assets | v3/internal/assetserver/bundledassets/runtime.js(另有.debug.js) | webview,以/wails/runtime.js路径被资源服务器提供 |
task v3:runtime:build:package | npm 包目录下的dist/ | 应用的 frontend,通过node_modules导入 |
这两个任务在源码中有精确定义:v3/internal/runtime/Taskfile.yaml中的build:assets依赖build:debug与build:production(两者均用 esbuild 将src/index.ts打包进../assetserver/bundledassets/),而build:package则调用npm run build:code生成 npm 包用的dist/。产物的去向也清晰可见:v3/internal/assetserver/bundledassets/ 目录下确实存在runtime.js与runtime.debug.js两个文件。
5.1 为什么必须两个都重建
- webview 侧:桌面应用的 HTML/JS 运行时由 Go 侧通过
go:embed内嵌的bundledassets/runtime.js提供,webview 加载/wails/runtime.js获得运行时能力; - frontend 侧:生成的应用通过 npm 导入
@wailsio/runtime包,Vite 等打包器从node_modules解析该包,走的完全是另一条路径。
因此,只要修改了src/下的任何代码(例如stream.ts),两个产物都必须重建并一并提交。
5.2 CI 如何强制“产物与源码一致”
AGENTS.md 提到“CI 会校验提交的 bundle 与build:assets输出完全一致”。仓库中的 .github/workflows/verify-runtime-assets.yml 正是这项强制检查的实现:
- 该 job 运行于每个 PR,且当 PR 未改动
v3/internal/assetserver/bundledassets或v3/internal/runtime相关路径时自动跳过; - 一旦相关路径有改动,它会对 PR 源码做一次干净的重新构建,然后与提交中的
runtime.js/runtime.debug.js逐字节比对; - 由于 minified JS 无法靠肉眼审查,该检查将 bundle 视为“内部构建产物”,并要求 PR 必须提交与源码严格匹配的字节。
这意味着 Agent 修改运行时源码后,不能只提交.ts源码而忘记更新 bundle——CI 会直接拒绝。
5.3 用本地 checkout 的运行时测试应用
一个生成的 Wails v3 应用从 npm 导入@wailsio/runtime,因此看不到本 checkout 中对运行时所做的改动。要在真实应用上测试工作树中的运行时改动,AGENTS.md 给出了命令:
task v3:install-runtime -- ./path/to/your-app/frontend该任务在 v3/Taskfile.yaml 中定义:它首先依赖runtime:build:package重建dist/,然后进入目标 frontend 目录执行npm install "file:..."指向本仓库的运行时包,确保安装的一定是当前源码构建的产物。撤销方式同样简单——在相同目录执行:
npm install @wailsio/runtime@latest6. 子系统内部文档索引:以 Streams 为例
AGENTS.md 建议:部分子系统为 Agent 准备了专门的内部文档页面,修改对应代码前必须先阅读,因为其中若干设计决策看似随意,实则都是为了规避某个已被测量的 bug。
它给出的示例是Streams:
- 涉及文件:
v3/pkg/application/stream*.go(Go 侧)与v3/internal/runtime/desktop/@wailsio/runtime/src/stream.ts(TS 侧); - 内部文档:docs/mpress/content/guides/advanced/streams-internals.mpd,覆盖 held-poll 设计、缓冲区常量及其选择方法、会话与连接生命周期、传输层选择,以及未完成事项;
- 若要把现有 WebSocket 实现迁移到 Streams,遵循 docs/mpress/content/guides/advanced/streams-from-websockets.mpd——一份机械式检查清单,其中标注了“静默失效”的差异点。
这一节的深层含义是:Wails v3 的文档体系已经为 AI 代理做过索引优化——遇到 Streams 相关改动,Agent 应先读内部文档再动手,否则很容易“破坏一个被测量的修复”。
6.1 源码侧的文件分布
AGENTS.md 中列出的 Streams 实现文件均可在仓库中定位:
- v3/pkg/application/stream.go:公开 API、
StreamConn、streamSink、管理器与注册表; - v3/pkg/application/stream_session.go:单窗口单次页面加载的会话——出站队列、帧类型、连接表;
- v3/pkg/application/stream_transport.go:两个 HTTP 端点、二进制分帧、分块重组、运行时 prelude;
- v3/pkg/application/stream_server.go:
-tags server构建下的真实 WebSocket sink; - v3/pkg/application/stream_prelude_desktop.go 与 stream_prelude_server.go:在 bundle 服务时选择客户端传输层;
- v3/internal/runtime/desktop/@wailsio/runtime/src/stream.ts:
WebSocket形态的客户端实现; - v3/tests/stream-performance/:负载测试工具(
-upload、-reloads、场景扫描)。
6.2 Streams 的核心设计:非对称传输
内部文档指出,Go→JS 与 JS→Go 使用不同机制,而这种不对称性正是整个设计的核心:
Go webview ── ─────── Send() ─► per-window queue ─────────► GET /wails/stream/poll (held open) └─ one held request per window, carrying frames for every connection Receive() ◄─ per-conn inbox ◄──────── POST /wails/stream/send (one or more frames)- Go→JS 是“保持打开的轮询”(held poll):请求一直挂起直到有内容可投递。没有轮询间隔,也没有自适应机制——服务器挂住直到帧出现,投递延迟天然接近 0;任何客户端间隔都只会增加延迟。响应在途期间到达的帧会累积到下一次响应,往返本身即批处理窗口。实测:100/s 时每响应 1.0 帧,5000/s 时仍为 1.0,20000/s 时达到 3.4,且 p99 延迟随速率上升反而下降。
- JS→Go 是普通 POST:发送按连接用 promise 链串行化(并发
fetch不保序,而 Go 依赖发送顺序即观察顺序)。Go 在响应之前就把被接受的帧(或批次前缀)追加到连接的 inbox,因此客户端不可能越过 Go 尚未排队的字节。 - 每窗口只有一个在途 poll,复用所有连接:单队列、单 drainer,顺序正确性由构造保证;同时绕开了 Windows 上 HTTP/1.1 每主机 6 连接的瓶颈(这些是
http://wails.localhost上真实的 Chromium 网络请求)。
6.3 为什么做这些特定决策(每个都是一道“疤痕”)
内部文档强调:以下每一条都来自事件传输工作的实测教训,移除任一决策都会重新打开一个已测量的 bug:
- Go→JS 路径不碰主线程:
Send在互斥锁下追加后立即返回。事件系统曾在主线程 emit 与 goroutine emit 并发排队时内联执行 eval,导致三个平台上 4.4% 的事件乱序。单队列单 drainer 从构造上杜绝了这一点。 - 任何规模下都不使用
evaluateJavaScript:把 payload 拼接进 eval 源码会保留宿主内存,且存在平台相关的“拐点”(macOS 11.6 GB、WebKitGTK 6.2 GB,均为 100 × 1 MB/s 场景)。Streams 完全不经过 eval,因此恒定字节速率扫描在每个帧大小下都是平坦的。 - 控制数据走 header,不走路由参数或 query string:WebKitGTK 6.0 可能把自定义 URI scheme 的 POST body 当作 query 参数投递(
transport_http.go为此带了一个 fallback),WebView2 则把 body 投递上限限制在约 2 MB。 - poll 响应是二进制而非 JSON:帧是
[]byte;若用 JSON 信封装 base64,每帧多花 33% 开销,还会在 UI 线程上多一次解析。二进制帧格式为:
magic "WS1\0" | flags u8 | count u32 | count × ( connID u32 | kind u8 | len u32 | payload )kind取值 data / open / close / error。没有序号、没有 ack——WebSocket 本就不回放,断连就丢失在途数据,模拟它比维护一个有界缓冲无法总是满足的游标更简单也更诚实。
- 挂住请求是安全的:每个 webview 请求本来就有自己的 goroutine。
assetserver_webview.go中的dispatchWorkers被固定为 0,且注释明确点名此场景;若开启该池,必须先为请求生命周期设定上界。
6.4 缓冲区常量:编译期常量而非选项
所有常量集中在 v3/pkg/application/stream.go 中。它们是编译期常量,不是配置项——没有Options.Streams,也没有按流设置。修改即改源码:
| 常量 | 值 | 约束对象 |
|---|---|---|
streamOutQueueBytes | 8 MB | 每窗口等待收集的字节 |
streamOutQueueDepth | 256 | 每窗口缓冲的帧数 |
streamOutQueueBytesGlobal/streamOutQueueDepthGlobal | 256 MB / 8192 | 整个应用范围的出站数据缓冲 |
streamInQueueBytesGlobal/streamInQueueDepthGlobal | 256 MB / 8192 | 整个应用范围等待Receive的入站数据 |
streamMaxConnections | 256 | 单会话内的活动连接 + 排队关闭 |
streamMaxConnectionsGlobal | 4096 | 整个应用范围的活动连接 |
streamOutCloseDepthGlobal | 4096 | 整个应用范围未投递的关闭通知 |
streamMaxSessionsPerWindow | 16 | 单窗口可持有的会话数(超限时新代次必须取代旧代次) |
streamMaxSessions | 1024 | 整个应用范围的会话数 |
streamOutControlDepth/streamOutControlDepthGlobal | 256 / 4096 | 排队的非关闭控制帧(每会话 / 全应用) |
streamMaxChunkSets/streamMaxChunkTotal | 256 / 4096 | 每会话未完成上传数 / 单次上传的分块数 |
streamMaxChunkBytesGlobal/streamMaxChunkPartsGlobal | 128 MB / 4096 | 全应用范围的分块 payload / 分块元数据 |
streamMaxChunkIDLen | 64 字节 | 单个客户端提供的 chunk-set 标识符 |
streamMaxResponseBytes | 1 MB | 单个 poll 响应 |
streamHoldTimeout | 20 s | 空 poll 挂起的最长时间 |
streamSessionTTL | 60 s | 无 poll 且无活动连接 ⇒ 会话死亡 |
streamSessionGrace | 10 min | 有活动连接但长时间无 poll ⇒ 会话死亡 |
streamSessionSweep | 20 s | janitor 扫描死亡会话的周期 |
streamMaxFrameBytes | 64 MB | 任意方向单帧上限 |
streamMaxNameLen | 256 字节 | 单个注册或请求的流名称 |
streamInQueueDepth/streamInQueueBytes | 256 / 8 MB | 已接收但未被Receive取走的帧 |
如何选择这些值(内部文档的调参指南)
streamOutQueueDepth故意不是eventQueueCapacity(64):后者是按“一次 eval 排空一个”的队列测出来的,深度只增加尾部延迟;而 poll 按批排空,深度必须覆盖一个往返的生产量——5000 帧/s、5 ms 往返约 25 帧,256 给突发留了余量且不阻塞生产者。streamOutQueueBytes才是真正重要的上界:256 帧 × 1 MB 就是 256 MB。它是前端停止收集时宿主内存的后盾。- 两条交互规则(第二条极易被无意破坏):
- 深度与字节上限约束的是累积量;
- 空队列始终接受一帧,无论多大。无条件执行字节上限会让“大于上限的帧”根本无法发送——等待条件永远无法成立,
Send永久阻塞、TrySend永远报告满。帧大小并非总是调用方能选择的(带[]byte字段的结构体 marshal 成多大就是多大)。
streamMaxResponseBytes的存在是因为 Windows:WebView2 响应写入器会先把整个 body 累积在内存中,到Finish才交接,无界响应即无界分配。调高它不会提升 Windows 吞吐——实测 Windows 瓶颈是按字节而非按响应(帧扫描中响应/s 波动 4 倍,而 MB/s 稳定在约 90)。- 入站上限是前端等待的原因:桌面上
deliver报告满时,端点返回429,客户端用有界退避重试同一帧或未被接受的批次后缀;server 模式下 socket 读泵等待,由 TCP 施加背压。若无此上限,一个迟迟不调Receive的 handler 会让宿主内存无限增长。 - 控制帧绕过数据上限,但有独立生命周期上限:丢一个数据帧只是变慢,丢一个 open ack 会让前端永远停在
CONNECTING,丢一个 close 会让前端认为死连接还活着。因此非关闭控制帧有独立的有界队列;每个被接受的连接还会预留一个 close 槽位。 - 每会话上限都配套全应用级上限,否则每个被准入的会话/连接都能同时占满自己的本地配额。出站、入站数据共享独立的 256 MiB / 8192 帧预算;活动连接 4096 项预算;未投递的关闭通知另有同尺寸预算。两个预算刻意分离:每个预留恰好由唯一所有者释放(连接的槽位由只运行一次的
shutdown释放;关闭帧的槽位由处置该帧的一方释放),避免所有权迁移导致的永久泄漏(早期版本曾因此泄漏)。 - Go 帧转移所有权、JS 帧快照拷贝:Go 的
Send在传输层写入前保留调用方切片,调用成功后不得再修改/复用该存储;JS 的send()返回前复制可变二进制输入,与原生 WebSocket 所有权语义一致。 - JS 发送遵循 WebSocket 缓冲契约:
send()不能阻塞,bufferedAmount包含该 socket 保留的所有字节,是调用方的背压信号;宿主侧队列仍由上述上限独立约束。 - 分块重组共享宿主内存配额:每会话可组装最大 64 MiB 的单帧,但该配额不能乘以每个准入会话。未完成/可重试的 chunk 集共享 128 MiB 准入 payload 预算(完成时短暂同时保留分块与连续组装帧,仍处于 256 MiB 有效内存天花板内);保留的分块另共享 4096 项元数据配额。
- poll 重试只针对可恢复失败:网络错误、
408请求超时、425早期数据、429背压、5xx服务端错误,使用 250 ms 起步、最高 5 s 的指数退避;其余4xx属于协议或所有权失败,立即关闭页面 Streams;410是退役会话的干净终止信号。关闭最后一个连接会中止在途 poll 或退避定时器。 streamSessionTTL必须明显高于streamHoldTimeout,否则会话会在自己的 poll 合法挂起期间被回收。- 调参经验:小消息密集负载先撞深度上限,大 payload 先撞字节上限。典型应用无需调整——macOS 上默认值可支撑 634000 帧/s 与 2100 MB/s(该数据来自内部文档的实测记录)。
6.5 会话与连接生命周期
- 会话(session)= 某窗口的一次页面加载,以客户端生成的 id(类似运行时
clientId)为键,由先到的请求惰性创建。当平台无法识别请求窗口(windowID == 0)时,会话 id 仍全局有界,但代次(generation)故意不比较。 - 三种关闭机制(按感知速度排序):
- 新代次会话 poll 取代旧代次:重载会生成新会话 id 并在窗口的
sessionStorage中递增代次;同一值镜像到window.name(存储被禁用时仍能跨重载存活),并锚定到performance.timeOrigin(旧引擎回退Date.now())。poll 只退役更低的页面代次;窗口被销毁时旧会话的连接立即关闭。 - 窗口销毁:丢弃该窗口的所有会话,类似
eventPayloadStore.dropWindow。 - TTL 回收:兜底一切其他情况(渲染进程崩溃、机器休眠)。
- 新代次会话 poll 取代旧代次:重载会生成新会话 id 并在窗口的
- 只有前两种机制退役页面代次;TTL 清理只移除空闲会话而不推进“已退役代次水位线”,这样仍加载的页面在最后一个连接关闭后还能再开新流。已经被真正取代的代次仍被封锁,因为新页面的 poll 会在旧会话被移除前推进水位线。
- Apple WebView 会报告已取消的请求:macOS/iOS 上 WebKit 的
stopURLSchemeTask回调会取消匹配的请求上下文,使导航离开后的 poll 立即解除阻塞。Linux/Windows 当前桥接层没有等效的提前中止回调,parked 请求会一直挂到 hold 超时(连接仍会按规则 1 及时关闭;取消在 Linux 上表现为EPIPE,在 Windows 上直到Finish才显现)。
6.6 传输层选择机制
Stream(name)会查询window._wails.streamFactory:
- server 构建:安装一个返回真实
WebSocket的工厂; - webview 构建:保持未设置,客户端走 poll 传输层。
关键约束是:工厂必须在任何模块体执行之前安装,因为生成的 bindings 会在模块作用域创建流(例如export const Telemetry = Stream("telemetry"))。custom.js无法胜任——它通过loadOptionalScript注入,先做 HEAD 请求再追加<script>标签,落地太晚。正确做法是把工厂前置到运行时 bundle 上(见 v3/pkg/application/stream_prelude_server.go):ES 模块依赖先于导入者求值,因此 prelude 同步先于任何生成模块运行。若新增第三传输层,同样放入 prelude,不要回到custom.js。
6.7 尚未完成的事项(内部文档的诚实清单)
| 事项 | 状态 |
|---|---|
| 平台层请求取消 | Apple 已完成;Linux/Windows 待办 |
| 缓冲区常量作为选项 | 未做,仅编译期 |
| 类型化流 | 未做(有意为之,帧按决策就是[]byte) |
| 流水线(第二个在途 poll) | 未做,需要 JS 侧有序重组 |
| 每连接公平性 | 未做——同窗口连接共享一个队列,洪泛连接会拖慢邻居 |
| JS→Go 帧合并 | 已完成——在途请求后累积的帧以有界批次发送;轻载连接仍每 POST 一帧 |
| Windows 吞吐 | 约 100 MB/s,受WebResourceRequested编组限制;候选修复是共享缓冲区(PostSharedBufferToScript),bindings 已存在于internal/webview2/pkg/webview2/但未接入pkg/edge |
wails3 dev/ Vite | 可用——已验证生成vanilla-js项目,Vite dev server 在/代理,/wails/stream/*在代理前被资源服务器中间件匹配 |
| 多窗口 | 负载下未测,虽然会话按构造是窗口作用域的 |
6.8 Streams 的测试与验证
内部文档给出可直接运行的测试命令:
go test ./pkg/application/ -run TestStream -race # protocol, ordering, backpressure go test -tags server ./pkg/application/ -run TestServerMode pnpm --dir v3/internal/runtime/desktop/@wailsio/runtime test顺序测试是最关键的一个:八个 goroutine 并发发送,在队列锁下分发计数器,排空顺序必须与被接受顺序完全一致。一旦失败,说明“单 drainer”不变量被破坏。
负载测试工具(v3/tests/stream-performance/):
go run ./tests/stream-performance -duration 20s # full sweep go run ./tests/stream-performance -upload -duration 10s # JS→Go matrix go run ./tests/stream-performance -reloads 6 # connection lifecycle在 Windows 上,负载测试必须在交互式控制台会话中运行(纯 SSH 调用会在 session 0 中以零长度输出失败),且二进制必须放在 SSH 账号与控制台账号都能读取的位置(C:\Users\<user>被 ACL 限制为属主)。
7. 会话收尾(Landing the Plane):结束工作的强制流程
AGENTS.md 规定了结束工作会话时的强制工作流,任何 Agent 都应严格遵守:
- 为剩余工作登记 Issue——所有需要跟进的事项创建为 Issue;
- 运行质量门禁(若改了代码)——测试、lint、构建;
- 更新 Issue 状态——关闭已完成项,更新进行中项;
- 准备远端同步:
git status工作树干净且确认要同步时,执行
git pull --rebase;只有用户明确确认后才git push; - 清理——审查 stash,仅移除过时的;清理远端已合并分支;
- 验证——所有预期变更在请求时均已存在并已提交;
- 交接——为下一会话提供上下文。
三条关键规则贯穿始终:
- 每次提交使用
taliesin-ai身份; - 未经用户显式手动确认不 push;
- 清晰汇报变更状态:未提交 / 本地已提交 / 已推送。
8. 结语:让 AI 代理在 Wails 中“可预期地工作”
从 AGENTS.md 可以提炼出 Wails v3 对 AI 协作的完整治理哲学:
- 一切可追踪:Issue/PR 是唯一事实源,规划文档归档于
history/; - 一切有门禁:提交前
coderabbit --plain,CI 层verify-runtime-assets保证运行时产物与源码逐字节一致; - 一切有依据:Streams 内部文档把每个看似随意的决策都回溯到被测量的 bug,形成“改代码前先读文档”的强约束;
- 一切可回退:
task v3:install-runtime指向工作树、npm install @wailsio/runtime@latest撤销,双构建产物并提交,收尾流程以“不 push 直到用户确认”为底线。
对于任何想要为 Wails v3 贡献代码(尤其是涉及v3/internal/runtime、v3/pkg/application/stream*.go的改动)的开发者或 AI 代理,这套规范既是操作手册,也是理解代码库演进逻辑的入口。遵守它,你的每一次会话都会留下干净、可审计、可交接的痕迹。
【免费下载链接】wailsCreate beautiful applications using Go项目地址: https://gitcode.com/gh_mirrors/wa/wails
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考