mcpField
F
forge-idiomatic-engineer

forge-idiomatic-engineer

github.com/isala404开发85927 次安装9 周前更新
代码仓库

关于 forge-idiomatic-engineer

面向使用 Forge 全栈 Rust 框架的工程师,指导 Agent 熟悉项目、实现处理器并进行验证。内容涵盖编译流程、数据库迁移和弹性设计。

主要功能

  1. 01Forge 项目导览与环境检查
  2. 02处理器类型及注册指导
  3. 03使用 forge 命令生成与验证
  4. 04Rust、SQLx、迁移和前端参考
  5. 05弹性设计与故障处理原则

适用场景

  1. 01开始处理现有 Forge 项目
  2. 02添加并验证后端处理器
  3. 03排查 Forge 构建或迁移问题

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/isala404/forge --skill forge-idiomatic-engineer

安装后在 Claude Code 中输入/forge-idiomatic-engineer确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

references/
api.md
frontend.md
patterns.md
pitfalls.md
recipes.md
resilience.md
testing.md
references/frontend/
dioxus.md
svelte.md
scripts/
orient.sh

详细介绍

Forge 惯用工程师

全栈 Rust 框架。单个二进制文件,以 PostgreSQL 为后端。基于 Axum + Tokio + SQLx。宏会生成运行时连接代码和前端绑定;每个处理程序都必须在 src/main.rs 中注册(仅靠宏不会完成接入)。

编译循环硬性规则

如果忽略这些规则,调试可能会白白耗上数小时。编写代码前请牢记。

  • 手动运行任何 cargo check / cargo build 时,都必须设置 SQLX_OFFLINE=true。 CI 会全局设置此变量。否则,sqlx 会尝试根据你当前的 DATABASE_URL 验证每个 sqlx::query!(),包括你无法编辑的已发布 forge-runtime crate 文件中的查询,最终会在第三方代码中看到一大堆“column does not exist”错误。最简单的解决办法是在 shell rc 文件中运行 eval "$(forge env)";否则就手动运行 export SQLX_OFFLINE=true。
  • forge check 会自动准备离线缓存。 它会检测 src/ 是否比 .sqlx/ 更新,并在流水线其余步骤运行前执行 cargo sqlx prepare --workspace,因此你无需考虑 prepare 的执行顺序。(对于原始的 cargo check,每次编辑任何 sqlx::query!() 后,仍需运行 forge migrate prepare。)在 CI 中,如果缓存应已正确准备好,请传入 --no-prepare。
  • 如果缺少 cargo-sqlx,forge migrate prepare 会直接失败。 请运行 cargo install sqlx-cli --no-default-features --features postgres 安装,然后重试。
  • 所有 forge 命令都会向上查找 forge.toml。 可在任意子目录中运行;启动时会打印解析出的根目录。无需先运行 cd。
  • 如果编译循环中的任何环节感觉不对,先运行 forge doctor。 它会一次性检查 rustc、cargo-sqlx、SQLX_OFFLINE、DATABASE_URL 是否可访问、Docker、前端工具、forge.toml 语法、.sqlx/ 是否为最新状态,以及最新迁移文件是否为空。
  • cargo sqlx prepare 成功就意味着编译通过。 不要只为“确认”刚才 prepare 已证明的结果而运行 forge check——prepare 内部会调用完整的 cargo check。只有在上次 prepare 后有新改动,或要运行其余验证套件(注册、schema、clippy)时,才运行 forge check。

会话开始:只读一次,相信记忆

先运行 bash docs/skills/forge-idiomatic-engineer/scripts/orient.sh。该脚本会向上查找 forge.toml,然后打印结构化信息:项目名称 + 认证模式 + 前端、环境就绪状态(SQLX_OFFLINE、DATABASE_URL、cargo-sqlx、Docker)、.sqlx/ 缓存是否为最新状态、src/main.rs / src/functions/mod.rs / src/schema/mod.rs 的内容、按类型分组的所有已注册处理程序、最新迁移、启用了响应式功能的表,以及具体的 NEXT 操作提示。运行一次即可取代五次单独读取。

每个会话都要阅读一次 references/pitfalls.md 和 references/resilience.md——脚本不会打印它们。

如果脚本不可用(检出版本较旧,或环境受沙箱限制),请改为阅读 forge.toml、Cargo.toml、src/main.rs、src/functions/mod.rs,以及 migrations/ 下最新的文件。

只有在你写入这些文件时,它们才会改变——在会话中途重新读取几乎总是在浪费上下文。

自动压缩后,相信摘要中的文件清单。不要为了确认摘要已记录的信息而重新读取 main.rs / mod.rs——只有在准备写入这些文件、需要确认其当前准确内容时才重新读取。如果压缩内容附带了 <attachment> 文件,就将其视为已在上下文中;不要再发起新的 Read。

确实需要读取文件时,一次调用就完整读取。不要读取有重叠的范围(先从 offset 200 读,再从 offset 1 读)——应从 offset 1 开始,用足够大的 limit 一次读取。Forge 处理程序文件很少超过 600 行。

处理器类型

概念宏结构体后缀注册方式
只读查询#[forge::query]Query.register_query::<FnNameQuery>()
数据变更#[forge::mutation]Mutation.register_mutation::<FnNameMutation>()
后台任务#[forge::job]Job.register_job::<FnNameJob>()
定时任务#[forge::cron]Cron.register_cron::<FnNameCron>()
持久化工作流#[forge::workflow]Workflow.register_workflow::<FnNameWorkflow>()
长时间运行的进程#[forge::daemon]Daemon.register_daemon::<FnNameDaemon>()
外部 HTTP 事件#[forge::webhook]Webhook.register_webhook::<FnNameWebhook>()
AI Agent 工具#[forge::mcp_tool]McpTool.register_mcp_tool::<FnNameMcpTool>()

也可以使用 .auto_register(),通过 inventory 自动注册所有处理器。

命名规则
  • 仅支持 pub async fn 处理器——私有函数会导致代码生成失败。
  • snake_case 函数名 → 宏会生成 PascalCase + 类型后缀。函数名中不要包含类型名(用 heartbeat,而不是 heartbeat_daemon,否则会得到 HeartbeatDaemonDaemon)。
  • #[forge::model] 必须是结构体上的第一个属性。
Context API 速览

请记住这些内容,以免在实现过程中查阅 forge-core 源码:

  • ctx.db() → ForgeDb(一个 sqlx::Executor)。直接传给查询宏:sqlx::query_as!(...).fetch_one(ctx.db()).await?。
  • ctx.conn().await? → ForgeConn<'_>(事务型,仅用于变更)。将 &mut conn 传给查询宏。
  • ctx.user_id() → QueryContext 和 MutationContext 上的 Result<Uuid>。如果没有主体,则返回 ForgeError::Unauthorized。MutationContext 上没有 ctx.auth() 方法。
  • ctx.db_conn() → DbConn<'_>,用于必须同时适用于查询和变更的共享辅助函数。DbConn 的调用约定相反(在 DbConn 上调用 .fetch_*,并传入查询)——请参阅 references/patterns.md。
  • 让类型推断确定绑定的类型(let mut conn = ctx.conn().await?)。除非辅助函数签名有要求,否则不要导入 ForgeConn / ForgeDb / DbConn 并显式声明类型。

工作流

  1. 了解项目——阅读上面的会话启动文件列表,以及 references/pitfalls.md 和 references/resilience.md。通过 frontend/package.json(Svelte)或 frontend/Cargo.toml(Dioxus)判断前端类型。
  2. 规划改动范围——在编写代码前,确定此 PR 要包含哪些处理器、迁移和前端改动。改动应精简、纵向贯穿,聚焦于单个功能。
  3. 逐个处理器执行检查点循环:
    1. 使用 forge new <kind> <name>,不要手动编写文件。它会搭建包含正确宏默认值的框架,将 pub mod <name>; 追加到 src/functions/mod.rs,并在 src/main.rs 缺少 mod functions; 时插入该声明。类型:query、mutation、job、cron、workflow、daemon、webhook、mcp_tool、model、enum。
    2. 编辑搭建好的文件:用实际实现替换占位 SQL / 业务逻辑。
    3. 运行 forge check。如果源文件比 .sqlx/ 缓存新,它会自动准备缓存,因此通常不需要单独运行 forge migrate prepare。
    4. 如果失败,修复根本原因并仅重新运行失败的步骤。还有错误时,不要编写下一个处理器。
    5. 继续处理下一个处理器。
  4. forge generate——后端改动稳定后运行。绝不要编辑生成的文件。
  5. 前端——使用生成的绑定接入 UI。运行 forge test 执行 Playwright E2E 测试。
  6. 最终检查——确保 forge check 无错误、forge test 全部通过,并撰写简短的改动摘要。

如果用户在你诊断问题后说“修复它” / “你能修复它吗”,就直接修复——不要请求再次确认。只有在执行破坏性操作(删除数据、删除架构、强制推送)时才暂停并确认。

架构默认项(提前选择)
  • 身份验证:社交 OAuth、密码 + HS256 或 RS256——编码前选定(参见 patterns.md)。社交登录必须通过 user_identities 表关联。
  • 环境变量:使用 ctx.env_require() / ctx.env_or(),绝不使用 std::env::var()。
  • HTTP:RPC 使用 ctx.http();需要 bytes_stream() 或自定义重定向策略时使用 ctx.raw_http()。
  • SQL:只使用 sqlx::query!() / query_as!() 这类带感叹号的宏。架构或查询变更后运行 forge migrate prepare——参见“编译循环硬性规则”。
  • 作业/工作流:仅在变更操作中分派(默认启用事务)。切勿在会分派任务的变更操作上设置 transactional = false。
  • 共享逻辑:一旦有两个处理器需要,就提取到 src/utils/。

参考资料选择指南

任务参考资料
任何新处理器(必读)references/resilience.md
宏、上下文、错误、配置、CLIreferences/api.md
后端模式:作业、工作流、身份验证、Webhook、编译循环references/patterns.md
可复制粘贴的示例(用户获取、套餐限制、电子邮件、S3、支付、AI)references/recipes.md
前端原则(响应性、订阅、错误、上传)references/frontend.md
SvelteKit 细节(runes、stores、身份验证辅助工具)references/frontend/svelte.md
Dioxus 细节(钩子、信号、身份验证键控)references/frontend/dioxus.md
编写测试(后端构建器 + Playwright 场景)references/testing.md
调试构建或运行时错误references/pitfalls.md

工程原则

  • 为故障而设计:身份验证可能中断、实体可能消失、网络可能故障。参见 resilience.md。
  • 零死代码:彻底删除未使用的代码和已替换的模式。工作区 lint 会禁止 dead_code、unwrap_used、panic、indexing_slicing、unsafe_code。
  • 精简差异:每个 PR 只包含一个精简的纵向切片。
  • 边界验证:在处理器入口处验证,并返回 ForgeError 变体(绝不使用 unwrap/expect/panic!)。
  • 范围强制执行**(由宏在编译时强制执行):私有查询必须按 user_id / owner_id 过滤。对于主体,使用 ctx.user_id()。仅对共享/管理员数据使用 #[query(unscoped)] 退出范围限制。
  • 事务性分派(由编译时强制执行):dispatch_job 和 start_workflow 要求使用事务性变更操作。由于默认启用事务,只需确保不要在会分派任务的变更操作上设置 transactional = false。
  • 禁止访问系统表(由 forge check 强制执行):绝不对 forge_* 表执行 INSERT/UPDATE/DELETE。请使用 dispatch_job、start_workflow、record_signal。
  • 迁移:仅允许向前迁移——不要使用 -- @down。可选的 -- @up 标记会被移除。使用 SELECT forge_enable_reactivity('table_name'); 启用响应性。不要使用 IF NOT EXISTS。
  • 未找到处理:fetch_optional().await?.ok_or_else(|| ForgeError::NotFound(format!(...)))。

输出要求

完成后,报告:

  • 变更:修改的文件、处理的故障模式、新增的测试(包括故障路径)。
  • 验证:运行的命令、阻碍因素、最终 forge check 结果。
  • 审查:韧性方面的缺口、假设。

每个处理器都必须能应对身份验证被撤销、实体被删除、并发修改和网络中断。

评论

支持 Markdown