
开发工具接口测试桌面应用【免费下载链接】yaakThe most intuitive desktop API client. Organize and execute REST, GraphQL, WebSockets, Server Sent Events, and gRPC 项目地址https://gitcode.com/GitHub_Trending/ya/yaak点击查看免费下载导读.claude/rules.md是 Yaak 桌面 API 客户端仓库Rust 内核 TypeScript 前端 插件生态的混合工程专门面向 AI 辅助开发协作而维护的一份契约式规则文档。它浓缩了该仓库在多语言、多进程、多包npm workspaces Cargo crates协作开发中最容易踩坑的六类硬约束提交纪律、构建与静态检查、插件后端的UpdateSource语义、时间戳所有权、MCP Server 的上下文模型以及 Rust 类型到 TypeScript bindings 的再生成流程。阅读本文后你将掌握这些规则背后的源码级原理对应UpdateSource::Plugin的调用链、upsert_date的时间戳策略、MCP 工具如何获取 workspace 上下文、ts-rs 如何驱动gen_*.ts生成并能在开发或审查 AI 生成的代码时准确执行这些约束。一、规则文档的定位面向 AI 助手的协作契约在 Yaak 仓库中人类开发者与 AI 助手的协作规则被刻意拆成了三层各司其职文件定位核心内容.claude/rules.md面向 AI 辅助开发的强制性执行规则提交确认、lint/bootstrap 时机、插件后端约束、MCP 上下文限制、bindings 再生成AGENTS.md面向 Agent 的仓库级约束tag 安全v*与yaak-api-*的区别、未经明确批准不得 commit/push/tagCONTRIBUTING.md面向社区贡献者的流程约定仅接受 bug fix PR非 bugfix 改动需先获得作者许可三者共同构成规则金字塔CONTRIBUTING.md决定能否贡献AGENTS.md约束 Git 操作安全而.claude/rules.md则聚焦到每次修改后的技术动作。本文后续所有内容均以.claude/rules.md为主线展开并用仓库源码逐一印证。二、通用开发纪律与构建/静态检查流程2.1 提交纪律未经明确确认绝不 commit / push.claude/rules.md的第一条规则是NEVER commit or push without explicit confirmation这与 AGENTS.md 中未经明确批准不得 commit、push 或打 tag的要求互为印证。之所以在 AI 协作语境下被反复强调是因为 Yaak 的发布模型对 tag 极为敏感应用与 CLI 共用v*tagCLI 与应用版本锁定、随每次应用 tag 发布到 npm而yaakapp/api使用独立的yaak-api-*tag。AI 助手如果自主执行 Git 写操作极易在错误的 tag 上引发发布事故。因此该规则要求任何 Git 写操作都必须先获得人类开发者显式批准。2.2 修改 TS/JS 后必须运行npm run lint规则要求修改任何 TypeScript 或 JavaScript 文件后运行npm run lint。查看根目录 package.json 的 scripts 可以发现这条命令并非单一步骤而是一个并行管道lint: run-p lint:*, lint:vp: vp lint, lint:workspaces: npm run --workspaces --if-present lint即npm run lint同时执行两条链lint:vp使用vpVite Plus 的命令行工具对仓库根级配置与代码做静态检查lint:workspaces递归进入 package.jsonworkspaces字段声明的全部 workspace包括packages/*、plugins/*、plugins-external/*、crates-tauri/*、crates/*、apps/*等近 60 个包对各自声明了 lint 脚本的包逐一执行。因此AI 助手在修改任意一个插件如plugins/template-function-json或前端包如apps/yaak-client后都必须通过这条命令确保整仓不引入 lint 错误。2.3 修改插件运行时或 MCP Server 代码后必须运行npm run bootstrap规则要求在修改plugin runtime 或 MCP server 代码后运行npm run bootstrap。bootstrap在 package.json 中定义为一组串行任务bootstrap: run-s bootstrap:*, bootstrap:install-wasm-pack: node scripts/install-wasm-pack.cjs, bootstrap:build: npm run build, bootstrap:vendor: npm run vendor其链路为安装wasm-pack负责编译 Rust 到 WebAssembly→ 构建所有 workspace → 执行 vendoringvendor-plugins将插件打包为发布产物、vendor-protoc处理 gRPC 的 protoc 工具链见 scripts/vendor-plugins.cjs 与 scripts/vendor-protoc.cjs。之所以这两类改动需要全量 bootstrap是因为插件运行时依赖 Rust 编译出的 wasm 产物如 crates/yaak-wasm 与 crates/yaak-templates 的pkg/目录而 MCP Server 插件plugins-external/mcp-server运行时会通过 scripts/vendor-node.cjs 打入 Node 运行时。仅改前端文件时不需要走这条重链路这也是规则把 bootstrap 单独列出的原因。三、插件系统后端约束UpdateSource::Plugin与时间戳所有权这是.claude/rules.md中技术含量最高的部分三条约束共同回答了同一个问题插件进程写入数据库时谁能决定哪些字段。3.1 数据库写操作必须使用UpdateSource::Plugin规则原文Always useUpdateSource::Pluginwhen calling database methods from plugin events。UpdateSource定义在 crates/yaak-models/src/util.rs是一个带标签的枚举pub enum UpdateSource { Background, Import, Plugin, Sync, Window { label: String }, }它标明了每次数据变更的来源渠道。在 crates/yaak/src/plugin_events.rs 中插件事件的UpsertModelRequest与DeleteModelRequest分派逻辑可以完整看到这一约束的落地无论插件写入的是HttpRequest、GrpcRequest、WebsocketRequest、Folder、Environment还是Workspace统一走with_tx(|tx| tx.upsert_xxx(m, UpdateSource::Plugin))删除操作同理例如delete_http_request_by_id(req.id, UpdateSource::Plugin)crates/yaak/src/plugin_events.rs。同文件的单元测试也严格遵循种子数据用UpdateSource::Sync写入而模拟插件写入时全部显式传入UpdateSource::Plugin例如upsert_and_delete_model_are_shared_handled测试crates/yaak/src/plugin_events.rs。为什么要区分来源UpdateSource会直接影响后续的同步sync与冲突处理逻辑——来自Sync的写入需要走双向同步管道来自Plugin的写入则需要被重新广播给同步层。如果 AI 助手在生成插件事件处理代码时漏掉UpdateSource::Plugin或错用UpdateSource::Sync轻则导致本地变更无法正确上链同步重则引发数据环回。3.2 时间戳由 Rust 后端控制TypeScript 永不发送规则原文Never send timestamps (createdAt,updatedAt) from TypeScript - Rust backend controls these。这条规则的直接技术依据在 crates/common/yaak-database/src/traits.rs 的upsert_date函数pub fn upsert_date(update_source: UpdateSource, dt: NaiveDateTime) - SimpleExpr { match update_source { UpdateSource::Sync | UpdateSource::Import { if dt.and_utc().timestamp() 0 { Utc::now().naive_utc().into() } else { dt.into() } } _ Utc::now().naive_utc().into(), } }其语义非常清晰对于Sync/Import来源保留传入的时间戳仅在时间戳为 0、即未设置时回退为当前 UTC 时间以保证跨设备同步时原始创建/修改时间不被覆盖对于包括Plugin在内的其他来源一律由后端覆盖为当前 UTC 时间——插件传入的任何时间戳都会被丢弃。因此从 TypeScript 侧发送createdAt/updatedAt不仅是多余的还会造成误导调用方以为时间戳由自己控制实则后端_ Utc::now().naive_utc().into()分支会直接忽略它们。正确做法是只携带业务字段id、name、url等让 Rust 后端统一生成时间戳。3.3 后端使用NaiveDateTime无时区避免发送 ISO 时间戳字符串规则原文Backend usesNaiveDateTime(no timezone) so avoid sending ISO timestamp strings。在 crates/yaak-models/src/models.rs 中几乎所有模型的时间字段都声明为NaiveDateTime。以Settings为例#[ts(export, export_to gen_models.ts)] pub struct Settings { pub created_at: NaiveDateTime, pub updated_at: NaiveDateTime, ... }NaiveDateTime是 chrono 中不带时区信息的时间表示仅含日期与时刻。这意味着序列化到 TypeScript 侧时时间字段的格式与带时区的 ISO 8601 字符串如2026-09-30T02:27:52Z或带08:00偏移的形式并不一致如果插件或前端代码发送 ISO 字符串后端在反序列化/存储时可能因格式不匹配产生解析偏差或失败仓库内所有时间均由upsert_date统一以Utc::now().naive_utc()形式生成见 3.2天然是无时区的 UTC 时刻前端如需展示本地时间再做转换即可。实践结论TypeScript/插件侧应当把时间字段视为后端私有、只读的字段——既不发送也不假设其带时区语义需要展示时将其当作 UTC 时刻在 UI 层转换。四、MCP Server 的上下文模型没有活动窗口概念规则原文MCP server has no active window context - cannot callwindow.workspaceId()- Get workspace ID fromworkspaceCtx.yaak.workspace.list()instead。4.1 为什么 MCP Server 没有活动窗口上下文MCP Server 插件plugins-external/mcp-server是一个独立运行的后台服务。从其入口 plugins-external/mcp-server/src/index.ts 可以看到插件在init后延迟 5 秒启动服务器监听环境变量YAAK_PLUGIN_MCP_SERVER_PORT默认端口64343const serverPort parseInt(process.env.YAAK_PLUGIN_MCP_SERVER_PORT ?? 64343, 10);它通过 MCPModel Context Protocol标准协议与外部 AI 客户端通信运行时并不依附于某个具体的桌面窗口。而window.workspaceId()这类 API 依赖当前活动窗口的 UI 状态——在无窗口的后台进程中该调用无法可靠返回可能为空或 undefined。这就是规则禁止直接调用它的根本原因。4.2 源码中的正确替代模式显式解析 workspace 上下文规则要求的替代路径在 MCP 工具实现中有完整的源码佐证plugins-external/mcp-server/src/tools/workspace.ts 的list_workspaces工具直接调用ctx.yaak.workspace.list()返回当前打开的全部 workspace 及其 IDplugins-external/mcp-server/src/tools/helpers.ts 中的getWorkspaceContext是核心辅助函数先ctx.yaak.workspace.list()拿到 workspace 列表若用户未指定且存在多个 workspace 则抛出带编号清单的错误提示最后通过ctx.yaak.workspace.withContext(workspace)构造出带 workspace 上下文的引用const workspaces await ctx.yaak.workspace.list(); ... return { yaak: ctx.yaak.workspace.withContext(workspace) };基于该上下文plugins-external/mcp-server/src/tools/window.ts 的get_workspace_id/get_environment_id工具才得以工作——它们在getWorkspaceContext返回的workspaceCtx上调用workspaceCtx.yaak.window.workspaceId()/workspaceCtx.yaak.window.environmentId()。由此可以看到这条规则的精髓MCP 场景下不要依赖隐式的活动窗口而要用 workspace 列表显式确定目标上下文必要时让用户从列表中选择。AI 助手在编写或审查 MCP 工具时应优先复用getWorkspaceContext模式而不是凭空假设存在活动窗口。五、Rust 类型生成cargo test驱动 TypeScript bindings 再生成规则原文Runcargo test --package yaak-plugins(and for other crates) to regenerate TypeScript bindings after modifying Rust event types。5.1 机制ts-rs 的测试期导出Yaak 使用ts-rs库在 Rust 侧生成 TypeScript 类型声明。在 crates/yaak-plugins/src/events.rs 与 crates/yaak-plugins/src/api.rs 中所有需要暴露给前端的 Rust 类型都标注了#[ts(export, export_to gen_events.ts)]、#[ts(export, export_to gen_api.ts)]等属性#[derive(Debug, Clone, Serialize, Deserialize, TS)] #[serde(rename_all camelCase)] #[ts(export, export_to gen_events.ts)] pub struct InternalEvent { ... }ts_rs的export属性会在cargo test 执行期间触发文件写出生成到 crates/yaak-plugins/bindings 目录下gen_events.ts、gen_api.ts、gen_models.ts、gen_search.ts等。随后 crates/yaak-plugins/index.ts 通过export * from ./bindings/gen_events等语句把这些类型重新导出供yaakapp/api与前端消费。5.2 为什么要用cargo test触发这正是.claude/rules.md强调修改 Rust 事件类型后必须运行cargo test --package yaak-plugins的原因只有运行测试bindings 文件才会被重新生成。如果 AI 助手改动了crates/yaak-plugins中的事件结构比如给某个InternalEventPayload变体增加字段却忘记运行对应 crate 的测试那么 crates/yaak-plugins/bindings 下的gen_*.ts仍是旧类型TypeScript 侧会出现类型不匹配或缺失字段的编译错误而且这类错误极难定位错误发生在跨语言边界的另一端。同理规则括号中的and for other crates说明凡是用#[ts(export, ...)]声明了 bindings 的 crate如 crates/yaak-models、crates/yaak-plugins 等可在各 crate 的bindings/目录确认改动其导出类型后都要跑对应 crate 的cargo test来刷新 bindings。作为快速自查手段修改后应检查git status中bindings/gen_*.ts是否出现了预期的 diff。六、实践落地AI 协作修改的检查清单综合.claude/rules.md全部条目一份可直接执行的自检清单如下修改类型必做动作对应规则/源码任意代码修改不 commit、不 push等待显式确认.claude/rules.md、AGENTS.md修改 TS/JS 文件npm run lint含lint:vp 各 workspace lintpackage.json修改插件运行时 / MCP Server 代码npm run bootstrapwasm-pack 安装 → 构建 → vendorpackage.json、scripts/install-wasm-pack.cjs编写插件事件中的数据库写入一律传UpdateSource::Plugin绝不使用其他来源crates/yaak/src/plugin_events.rs编写插件/前端数据写入不发送createdAt/updatedAt不发送 ISO 时间字符串crates/common/yaak-database/src/traits.rs编写 MCP 工具不用window.workspaceId()改用workspace.list()显式解析上下文plugins-external/mcp-server/src/tools/helpers.ts、plugins-external/mcp-server/src/tools/workspace.ts修改 Rust 事件/模型类型运行cargo test --package 对应 crate重新生成 bindingscrates/yaak-plugins/src/events.rs、crates/yaak-plugins/index.ts七、结语.claude/rules.md虽然只有二十余行却精准覆盖了 Yaak 这类Rust 内核 TypeScript 前端 插件生态混合工程中 AI 协作的六大高风险区。它不是空泛的行为准则而是可以从源码中逐条验证的工程约束UpdateSource::Plugin在 crates/yaak/src/plugin_events.rs 中有完整的调用链与测试佐证时间戳策略在 crates/common/yaak-database/src/traits.rs 的upsert_date中有明确的来源分支MCP 上下文约束在 plugins-external/mcp-server/src/tools/helpers.ts 中有标准的替代实现bindings 再生成则由 ts-rs 的测试期导出机制驱动。对于任何参与 Yaak 开发尤其是通过 AI 助手提交代码的工程师把这七条规则内化为肌肉记忆是避免跨语言、跨进程边界的隐性 bug 最有效的途径。赞分享开发工具接口测试桌面应用【免费下载链接】yaakThe most intuitive desktop API client. Organize and execute REST, GraphQL, WebSockets, Server Sent Events, and gRPC 项目地址https://gitcode.com/GitHub_Trending/ya/yaak点击查看免费下载相关推荐深入解析 MoveFlowAptos 的 AI 辅助 Move 智能合约开发插件框架MCP Server、插件生成器与编辑钩子深入解析 MoveFlowAptos 的 AI 辅助 Move 智能合约开发插件框架MCP Server、插件生成器与编辑钩子 导读 MoveFlow区块链Web3深入解析linshenkx/prompt-optimizer项目中的AI辅助开发最佳实践深入解析linshenkx/prompt optimizer项目中的AI辅助开发最佳实践 项目概述 linshenkx/prompt optimizer项目提供人工智能大模型提示工程AI 应用AI 评测pydantic-ai 编码规范深度解读从代码风格到类型系统的源码级最佳实践pydantic ai 编码规范深度解读从代码风格到类型系统的源码级最佳实践 本指南基于 pydantic ai 仓库内部维护的 Coding Guideli人工智能大模型AI Agent工具调用MCP Clients上一篇推荐文章轻松管理预约Open Source Doctor Appointment Booking System —— 您的线上医疗服务助手下一篇深入理解 Elasticsearch 读写原理从协调节点路由到 Lucene 倒排索引创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考