forge-idiomatic-engineer について
Forge のフルスタック Rust フレームワークを扱うエンジニア向けのコーディングスキルです。プロジェクトの把握からハンドラー実装、検証、障害に備えた設計までを案内します。
主な機能
- 01Forge プロジェクトの把握と環境確認
- 02ハンドラーの種類と登録方法の案内
- 03forge コマンドによる生成と検証
- 04Rust、SQLx、マイグレーション、フロントエンドの参照情報
- 05レジリエンスと障害対応の原則
活用シーン
- 01既存の Forge プロジェクトで作業を始める
- 02バックエンドハンドラーを追加して検証する
- 03Forge のビルドやマイグレーションの問題を調べる
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ isala404/ forge --skill forge-idiomatic-engineerインストール後、Claude Code で/forge-idiomatic-engineerを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/api.mdfrontend.mdpatterns.mdpitfalls.mdrecipes.mdresilience.mdtesting.mdreferences/frontend/dioxus.mdsvelte.mdscripts/orient.sh詳細
Forge Idiomatic Engineer
フルスタックの Rust フレームワークです。単一バイナリで、PostgreSQL をバックエンドに使用します。Axum + Tokio + SQLx を採用しています。マクロがランタイムの配線とフロントエンドのバインディングを生成します。各ハンドラーは src/main.rs に登録する必要があります(マクロだけでは配線されません)。
コンパイルループの厳守事項
見落とすと、デバッグに何時間も無駄にすることになります。コードを書く前に、以下をしっかり把握してください。
- 手動で
cargo check/cargo buildを実行する場合は、必ずSQLX_OFFLINE=trueを設定してください。 CI ではグローバルに設定されています。設定しないと、sqlx はライブのDATABASE_URLに対してすべてのsqlx::query!()を検証しようとします。編集できない公開済みのforge-runtimeクレートのファイル内にあるクエリも対象となり、サードパーティーのコードについて「column does not exist」というエラーが大量に出ます。最も簡単な解決方法は、シェルの 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を実行します。forge checkは、前回の prepare 以降に新しい編集を行った場合、または検証スイートの残り(登録、スキーマ、clippy)を実行する場合にのみ使ってください。
セッション開始時:一度読んだら、記憶を信頼する
まず 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 アクションのヒントです。これを一度実行すれば、個別に5回読み込む必要はありません。
スクリプトでは表示されないため、各セッションで 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 から十分な上限を指定して、一度に読み込んでください。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 エージェントツール | #[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をインポートして明示的な型を書かないでください。
ワークフロー
- 状況を把握する — 上記のセッション開始時のファイル一覧に加え、
references/pitfalls.mdとreferences/resilience.mdを読みます。frontend/package.json(Svelte)またはfrontend/Cargo.toml(Dioxus)でフロントエンドを判別します。 - 作業範囲を計画する — コードを書く前に、この PR に含めるハンドラー、マイグレーション、フロントエンドの変更を決めます。変更は的を絞り、垂直に一つの機能にまとめます。
- ハンドラーごとにチェックポイントを設けて進める:
- ファイルを手動で書くのではなく、
forge new <kind> <name>を実行します。適切なマクロのデフォルトを含むスキャフォールドを生成し、src/functions/mod.rsにpub mod <name>;を追加し、必要な場合はsrc/main.rsにmod functions;を挿入します。種類:query、mutation、job、cron、workflow、daemon、webhook、mcp_tool、model、enum。 - スキャフォールドされたファイルを編集し、プレースホルダーの SQL/ビジネスロジックを実際の実装に置き換えます。
forge checkを実行します。ソースのほうが新しい場合は.sqlx/キャッシュが自動で準備されるため、通常は別途forge migrate prepareを実行する必要はありません。- 失敗した場合は根本原因を修正し、失敗したステップだけを再実行します。エラーが残った状態で次のハンドラーを書かないでください。
- 次のハンドラーに進みます。
- ファイルを手動で書くのではなく、
- バックエンドの変更が確定したら、
forge generateを実行します。生成されたファイルは編集しないでください。 - フロントエンド — 生成されたバインディングを使って UI を接続します。Playwright の E2E テストには
forge testを実行します。 - 最終確認 —
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を設定しないでください。 - 共有ロジック:2 つのハンドラーで必要になった時点で、
src/utils/に切り出してください。
リファレンスの選択ガイド
| タスク | リファレンス |
|---|---|
| 新しいハンドラー全般(必読) | references/resilience.md |
| マクロ、コンテキスト、エラー、設定、CLI | references/api.md |
| バックエンドのパターン:ジョブ、ワークフロー、認証、Webhook、コンパイルループ | references/patterns.md |
| コピー&ペースト可能なレシピ(ユーザー取得、プラン制御、メール、S3、決済、AI) | references/recipes.md |
| フロントエンドの原則(リアクティビティ、サブスクリプション、エラー、アップロード) | references/frontend.md |
| SvelteKit の詳細(runes、ストア、認証ヘルパー) | 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が deny に設定されています。 - 差分は最小限にする: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の結果。 - レビュー:レジリエンス上の不足、前提条件。
すべてのハンドラーは、認証の失効、エンティティの削除、同時変更、ネットワーク切断に耐えられる必要があります。