mcpField
A
alchemy

alchemy

github.com/darkmatterクラウド・DevOps0303 回インストール5 日前に更新
リポジトリ

alchemy について

TypeScript と Effect のプロジェクトで、Alchemy v2 によるインフラの設定、開発、デプロイ、デバッグを支援するスキルです。インフラを Effect プログラムとして宣言し、ローカル開発、ステージ、状態管理、CI/CD を扱います。

主な機能

  1. 01Effect プログラムでインフラを宣言
  2. 02クラウドプロバイダーとリソースを設定
  3. 03alchemy dev によるローカル開発
  4. 04ステージ、プロファイル、状態の管理
  5. 05上流ドキュメントとサンプルの参照

活用シーン

  1. 01TypeScript プロジェクトの Alchemy デプロイ設定
  2. 02実際のクラウドリソースを使ったローカル実行
  3. 03プレビュー環境と CI/CD デプロイの設定

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/darkmatter/skills --skill alchemy

インストール後、Claude Code で/alchemyを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

reference/
examples.md
provider-implementation.md
upstream-concepts.md

詳細

Alchemy

Alchemy v2 と alchemy-run/alchemy-effect の Effect ネイティブなパターンを使用してインフラストラクチャを構成、開発、デプロイ、またはデバッグする場合に、このスキルを使用してください。Alchemy はインフラストラクチャを Effect プログラムとして扱います。スタックでリソースを宣言し、プロバイダーがクラウドとの連携を提供します。また、ローカル開発では実際のクラウドリソースを使ってアプリコードをローカルで実行でき、デプロイでは宣言されたリソースを実際のクラウド状態に収束させます。

Alchemy は、新しい TypeScript/Effect のデプロイ可能なインフラストラクチャにおいて、Darkmatter が推奨する方法です。リポジトリに明示的な例外がある場合や、変更すべきでない既存の本番システムがある場合を除き、場当たり的なプロバイダースクリプト、手書きの Wrangler/Terraform の接着コード、一度限りのデプロイワークフローよりも、まず Alchemy を検討してください。

Alchemy v2 と alchemy-effect は急速に変化しています。デプロイコードや開発コードを変更する前に、特にパッケージのバージョン、プロバイダー API、alchemy dev の動作、CLI フラグについて、最新の上流ドキュメントを確認してください。このスキルでは、上流の alchemy-run/alchemy-effect リポジトリを、ソース、例、エージェント向けの指示を参照できるローカルサブモジュールとして reference/alchemy-effect に含めています。

使用する場合

  • ユーザーが alchemy.run.ts ファイルのセットアップまたはレビューを依頼している場合。
  • ユーザーが alchemy dev、ローカル Workers、公開プレビュー URL、ホットリロード、Webhook テストを使った開発を依頼している場合。
  • ユーザーが Cloudflare Workers、Vite アプリ、R2、Queues、Durable Objects、D1、AWS Lambda、S3、DynamoDB、ECS、EC2、静的サイト、または関連リソース向けの Alchemy デプロイの構成を依頼している場合。
  • ユーザーが Alchemy のステージ、プロファイル、状態ストア、バインディング、スタックの出力、スタック間参照、CI/CD の使い方を尋ねている場合。
  • ユーザーがデプロイ関連の仕組みを Alchemy v2 に移行すること、または場当たり的なプロバイダースクリプトから移行することを依頼している場合。
  • ユーザーが alchemy-run/alchemy-effect/examples の例を求めている場合。

使用しない場合

  • 依頼がブロックチェーンのデータ/API 企業 Alchemy に関するもので、alchemy.run に関するものではない場合。
  • プロジェクトで TypeScript、Effect、Bun/Node、Alchemy を使用しておらず、ユーザーが一般的なデプロイに関する質問だけをしている場合。
  • 上流の alchemy-effect リポジトリ内でプロバイダーを実装または変更する作業の場合。上流リポジトリの AGENTS.md を直接使用し、その後、デプロイ構成への影響を確認する場合にのみこのスキルを使用してください。
  • デプロイ可能なインフラストラクチャを伴わない、Effect アプリケーションのロジックだけに関する作業の場合。effect-typescript を使用してください。
  • 成熟したリポジトリにすでに本番環境へのデプロイ手段があり、ユーザーが限定的なバグ修正を依頼している場合。移行を明示的に依頼されない限り、動作している手段を維持してください。

上流の確認

編集する前に、最新のドキュメントまたはローカルにインストール済みのパッケージを確認してください。

bun alchemy --help
bun alchemy dev --help
bun pm ls alchemy effect @effect/platform-bun @effect/platform-node

まず、以下の上流リファレンスを使用してください。

  • 現在のインストールコマンド、最初のスタックの構成、デプロイの流れについては、https://v2.alchemy.run/getting-started/ を参照してください。
  • スタック名、出力、ステージ、スタック間参照、状態の分離については、https://v2.alchemy.run/concepts/stack/ を参照してください。
  • alchemy dev については、https://v2.alchemy.run/concepts/local-development/ と https://v2.alchemy.run/tutorial/part-4/ を参照してください。
  • 状態の保存場所については、https://v2.alchemy.run/concepts/state-store/ を参照してください。
  • 非対話型のデプロイと PR プレビュー環境については、https://v2.alchemy.run/guides/ci/ を参照してください。
  • Effect ネイティブなインフラストラクチャの規約については、reference/alchemy-effect/AGENTS.md を参照してください。
  • 現在のプロジェクト概要とインストール方法については、reference/alchemy-effect/README.md を参照してください。
  • 具体的なアプリのパターンについては、reference/alchemy-effect/examples/ を参照してください。
  • プロバイダー/リソースの実装パターンについては、reference/alchemy-effect/packages/alchemy/src/ を参照してください。

上流の内容がこのスキルと食い違う場合は、上流に従い、その相違点に言及してください。

新しいチェックアウトにサブモジュールがない場合は、ローカルのリファレンスを使用する前に初期化してください。

git submodule update --init skills/alchemy/reference/alchemy-effect

アプリ/デプロイ作業中は、サブモジュールを読み取り専用として扱ってください。ユーザーが上流の alchemy-effect への貢献を明示的に依頼した場合に限り編集し、その際はリポジトリ内の規範として reference/alchemy-effect/AGENTS.md に従ってください。

プロジェクトのセットアップ

プロジェクトですでに別のパッケージマネージャーが標準化されている場合を除き、Bun を優先してください。現在の Alchemy v2 のドキュメントでは、Bun または Node.js 22+ を推奨し、Effect プラットフォームパッケージとともに Alchemy をインストールします。

bun add "[email protected]" "effect@>=4.0.0-beta.66 || >=4.0.0" "@effect/platform-bun@>=4.0.0-beta.66 || >=4.0.0" "@effect/platform-node@>=4.0.0-beta.66 || >=4.0.0"

既存のリポジトリのポリシーに従って、パッケージのバージョンを固定してください。リポジトリですでにカタログ、ワークスペースプロトコル、またはロックファイルのみを更新する手順を使っている場合は、ドキュメントのコマンドをそのまま貼り付けるのではなく、そちらに従ってください。

既存のリポジトリに Alchemy を追加する前に、現在のセットアップを確認してください。

rg -n "alchemy|alchemy.run|alchemy dev|alchemy deploy" package.json bun.lock package-lock.json pnpm-lock.yaml yarn.lock .github scripts . --glob '!node_modules'
find . -name 'alchemy.run.ts' -o -name 'alchemy.run.js'

リポジトリで Alchemy がまだ設定されていない場合は、デプロイだけでなくローカル開発にも Alchemy を設定するか、ユーザーに確認してください。デプロイ専用のセットアップを黙って作成しないでください。alchemy dev は実際のクラウドリソースをプロビジョニングし、公開プレビュー URL を公開して、ローカルコードを使った Webhook/OAuth コールバックのテストを可能にするため、ローカルのワークフローが変わります。ユーザーが希望した場合は、最初の実装に dev スクリプト、dev ステージ/プロファイルに関する案内、公開プレビュー出力の扱い、Webhook テストに関する注意事項を含めてください。

リポジトリに複数のアプリがある場合は、スタックへのパスが明確になるスクリプトを追加してください。

{
  "scripts": {
    "dev": "alchemy dev ./alchemy.run.ts",
    "deploy": "alchemy deploy ./alchemy.run.ts",
    "destroy": "alchemy destroy ./alchemy.run.ts",
    "deploy:prod": "alchemy deploy ./alchemy.run.ts --stage prod --profile prod"
  }
}

ルートにある alchemy.run.ts が曖昧さなく特定できる小規模なリポジトリでのみ、プレーンな bun alchemy deploy を使用してください。

組織のデフォルト

Darkmatter の TypeScript/Effect プロジェクトでは、デプロイ可能なインフラに Alchemy を優先してください。

  • 新しい Cloudflare Workers、Vite/フロントエンド、キュー、R2/KV、ワークフロー、AI Gateway、トンネル、GitHub デプロイ自動化には、まず Alchemy を使用してください。
  • アプリケーションデータには、まず Postgres を使用してください。クエリの多い TypeScript アダプターには Kysely + pg を、Effect ネイティブのデータベースサービスには Effect SQL Postgres を使用します。プロバイダーが対応している場合は、そのデータベースを取り巻くデプロイ設定、バインディング、シークレット、ネットワークリソースを Alchemy に任せてください。
  • D1/sqlite は、用途を限定したエッジローカルの状態、デモ、またはプロジェクトで明示的に決定した場合にのみ使用してください。データモデルが Postgres に適している場合は、アプリが Cloudflare 上にあることを理由に D1 を選ばないでください。
  • 新しい AWS Lambda、S3、DynamoDB、API Gateway、ECS/EC2/EKS/RDS、静的サイトのデプロイでは、まず Alchemy を検討してください。
  • 共有プレビュー環境には、独自の名前変換ではなく Alchemy のステージを使用してください。
  • Alchemy で経路を提供できる場合は、ローカルの Webhook テストに別個の ngrok/Cloudflare Tunnel スクリプトではなく、alchemy dev または Alchemy が管理するトンネル/プレビューフローを使用してください。
  • 手書きのプロバイダー CLI は診断に役立つ場合がありますが、理由がない限り、恒久的なデプロイ制御プレーンにしないでください。

スタックの構成

すべてのデプロイファイルでは、Alchemy.Stack(name, options, Effect.gen(...)) をデフォルトエクスポートしてください。

import * as Alchemy from "alchemy";
import * as Cloudflare from "alchemy/Cloudflare";
import * as Effect from "effect/Effect";

export default Alchemy.Stack(
  "MyApp",
  {
    providers: Cloudflare.providers(),
    state: Cloudflare.state(),
  },
  Effect.gen(function* () {
    const bucket = yield* Cloudflare.R2Bucket("Bucket");

    return {
      bucketName: bucket.bucketName,
    };
  }),
);

重要な構成要素は次のとおりです。

  • スタック名:安定した論理デプロイ単位です。状態と名前はスタック名から派生するため、安易に変更しないでください。
  • プロバイダー:クラウド認証とプロバイダー実装です。たとえば Cloudflare.providers() や AWS.providers() です。
  • 状態:意図を持って選択してください。Cloudflare のデプロイでは一般的に Cloudflare.state() を使用し、シンプルな AWS の例では Alchemy.localState() を使用できます。
  • Effect 本体:yield* でリソースを宣言し、参照とバインディングを通じて依存関係を組み立て、スモークチェックに役立つ出力を返します。

Effect ネイティブなプロバイダーモジュールの構成

共通の可読性に関するルールについては、codebase-design に従ってください。プロバイダーは、リソースを収束させる操作と、それらの操作が失敗または完了した際に必要なクリーンアップを担います。API 名や登録形式を選ぶ前に、インストール済みの Alchemy のバージョンと、固定された上流プロバイダーを確認してください。上流への貢献では、そのリポジトリ独自の構成に従ってください。

Darkmatter アプリまたはパッケージでプロバイダーを実装する場合:

  • リソースまたはプロバイダーのドメインごとにまとめ、その役割に明確な責務がある場合は models/、services/、adapters/、workflows/ を使用してください。単一ドメインのパッケージでは、それ自体が所有者となります。
  • リソースのスキーマと推論される型はまとめてください。明示的なパッケージエントリーを通じて、リソースのコントラクトとサポートするプロバイダーレイヤーを公開してください。
  • 採用、比較、マッピング、ステータスに関するヘルパーは、それらを必要とするライフサイクル実装と一緒に置いてください。複雑さを隠したり、有用な再利用を可能にしたりする場合は切り出し、ヘルパーごとのファイルや、別々の Types と Schemas の複製は避けてください。
  • 共有クライアントは、API リクエスト、レスポンスのデコード、型付きの失敗を担うことができます。Effect ネイティブな SDK を直接使用し、Promise ベースの SDK はその境界でのみラップしてください。設定と認証情報は既存の設定/プロバイダーレイヤーに置いてください。
  • Alchemy のリソース/プロバイダーのコレクションおよびバインディングのコントラクトを維持してください。公開側の構成では、内部ヘルパーをすべてバレルの連鎖を通じて再エクスポートせずに、複数のリソースレイヤーを登録できます。
  • 設定済みのファイルサイズ制限を守ってください。無理な分割によって一貫性のあるリコンサイラーが分散してしまう場合は、対象を絞った制限の引き上げを記録してください。

リファクタリングは、リソースまたはプロバイダーのインターフェースを通じてテストしてください。該当する場合は、作成、繰り返しのデプロイ、採用、更新、破棄のライフサイクルテストを維持してください。実際のプロバイダークライアントを使うか、Layer を通じて外部サービスを置き換えてください。テストのためだけにプライベートな選択/マッピングヘルパーを切り出したり、エクスポートしたりしないでください。独自のコントラクトを持つ公開された純粋関数ヘルパーには、個別のテストを維持できます。

ローカル開発

アプリを Alchemy 経由で実行できる場合は、デフォルトのローカル開発ループとして alchemy dev を使用してください。

bun alchemy dev ./alchemy.run.ts

Alchemy の開発モードでは、実際のクラウドプロバイダーにインフラストラクチャをデプロイし、サポート対象のアプリコードをローカルで実行して、ファイル変更時にホットリロードします。Cloudflare Workers の場合、Worker は workerd でローカル実行され、クラウドプロキシが公開クラウドエンドポイントとローカルプロセスの間でリクエストをルーティングします。

これは Webhook の作業で重要です。外部サービスには公開 URL が必要である一方、開発者にはローカルコード、ブレークポイント、ホットリロードが必要です。利用可能であれば、Webhook コールバックには Alchemy の開発/プレビュー URL を優先し、そのセッションまたはプレビュー段階ではサードパーティーの Webhook ターゲットをその URL に設定してください。

アプリに複数のローカルサービスがある場合や、固定のコールバック URL が必要な場合は、開発ポートを明示してください。

export const Worker = Cloudflare.Worker("Worker", {
  main: "./src/worker.ts",
  dev: {
    port: 3000,
  },
});

開発モードのルール:

  • alchemy dev が作成するクラウドリソースは、エミュレーターではなく実際のリソースとして扱ってください。
  • 共有アカウントに関わる作業では、ステージ/プロファイルを明示してください。
  • エージェントが稼働中のルートをテストできるよう、ローカル/公開 URL をスタック出力として返してください。
  • 利用可能な場合は、プロバイダーの実際の配信ログを使って Webhook のフローを検証してください。
  • 開発プロセスを適切に停止し、不要になった開発/プレビューリソースは、スタックが所有する場合に破棄してください。

ステージとプロファイルのルール

ステージとプロファイルはデプロイ契約の一部として扱ってください。

  • ステージは状態と物理名を分離します。デフォルトは開発者ごとに設定されます。共有環境では、明示的に --stage prod、--stage staging、または --stage pr-123 を使用してください。
  • プロファイルは認証情報を選択します。初回デプロイでは対話形式での入力が求められ、認証情報は ~/.alchemy/profiles.json に保存されることがあります。非対話形式の CI では、デプロイ前にプロファイルまたはプロバイダーの認証情報を準備しておく必要があります。
  • 本番環境用のスクリプトでは、--stage prod と使用する --profile の両方を指定してください。
  • プレビューデプロイでは、PR、ブランチ、または Issue ID から決定的なステージを導出し、不要になった時点でそのステージを破棄してください。

便利なコマンド:

bun alchemy deploy ./alchemy.run.ts --stage dev_cm
bun alchemy deploy ./alchemy.run.ts --stage prod --profile prod
bun alchemy destroy ./alchemy.run.ts --stage pr-123 --profile preview
alchemy login --configure
alchemy login --profile prod --configure

物理名に Date.now() やランダムなタイムスタンプを使用しないでください。Alchemy にスタック、ステージ、論理 ID から名前を生成させるか、環境に紐づいた決定的な名前を使用してください。

バインディングとランタイム依存関係

デプロイ済みの ID を環境変数経由で手動で受け渡すのではなく、バインディングを優先してください。バインディングはランタイムリソースに付加されるデプロイ時のデータであり、関数/ワーカーが必要とするインフラストラクチャ依存関係を正確に受け取れるようにします。

Cloudflare では、プラットフォームのリソースを Worker または Vite アプリに直接バインドします。

export const Bucket = Cloudflare.R2Bucket("Bucket");

export const Worker = Cloudflare.Worker("Worker", {
  main: "./src/worker.ts",
  bindings: {
    Bucket,
  },
});

Postgres の接続情報はアプリの設定/シークレットレイヤーに保持し、ランタイムクライアントはサービス Layer を通じて公開してください。そのデータに Postgres を使用しない明確な理由がリポジトリにある場合に限り、データベースに類する Cloudflare リソースをバインドしてください。

Effect ネイティブのランタイムでは、ランタイムサービスとデプロイ時の配線を分離してください。クラウドリソースとバインディングは Alchemy が管理し、ランタイムの動作は Effect サービスが担います。ランタイム実装が必要なリソースについては、スタックの境界で Layers を使用してください。

機能の構成:Binding.Service + Binding.Policy

Alchemy の各機能は、2 つのレイヤーの組み合わせとして提供されます。

  • Binding.Service — ランタイム SDK のラッパーで、Function/Worker の Effect に提供されます(デプロイ済みアーティファクトにバンドルされます)。
  • Binding.Policy — デプロイ時の IAM/バインディングのアタッチメントで、AWS.providers()() を介して Stack に提供され、バンドルされることはありません。

Cloudflare では、ワーカーの bindings: { ... } フィールドが両方を自動的に処理します。AWS では、Service レイヤーを Function に設定し、Policy レイヤーをスタックレベルで有効にする必要があります。デフォルトの AWS.providers() では一般的なポリシーレイヤーがすでに有効になっています。機能を作成またはオーバーライドする場合にのみ、AWS.providers()(extraLayers) を使用してください。

ランタイム専用メソッドでの Alchemy.RuntimeContext

バインディングは、内側の Effect が Alchemy.RuntimeContext を必要とする、型付けされた呼び出し可能な値を公開します。これを色付き関数として扱ってください。

  • 外側の Effect(関数の初期化時のセットアップ)では、RuntimeContext は不要です。
  • 内側の Effect(実際の SDK 呼び出し)では、RuntimeContext が必須であり、デプロイ済みの Function/Worker 内でのみ実行されます。

サービスがバインディングをラップし、誤って WorkerEnvironment/Lambda.FunctionEnvironment をインターフェースに漏らすと、そのサービスはクラウドに依存するようになります。Layer の構築時にクラウド環境サービスを一度だけ解決してクロージャー内に保持し、コンシューマーの Effect の要件として公開しないでください。

アプリケーション/ランタイムコードにおける Effect プラットフォームのルール

Alchemy のスタックと Worker/Function の本体は、Effect プログラムとして実行されます。Effect.gen の内部では、生の async や Node プリミティブを使用しないでください。

使用しない使用する
import fs from "node:fs/promises"const fs = yield* FileSystem.FileSystem
await fs.readFile(p, "utf8")yield* fs.readFileString(p)
import path from "pathe" / node:pathconst path = yield* Path.Path
await fetch(...)yield* HttpClient.HttpClient + HttpClientRequest
new Promise((res) => setTimeout(res, ms))yield* Effect.sleep(Duration.millis(ms))
Effect.promise(() => listSqlFiles(dir))ヘルパー自体が Effect を返すようにする

純粋な変換を Effect でラップする必要はありません。環境の読み取りと副作用は Effect 内でサスペンドし、外部境界を越える際には、想定されるスロー例外を分類してください。CPU 計算をラップしても、その計算が中断可能になるわけではありません。ドライバーを適合させた後は、内部処理も Effect 内で行い、必要とするホストまたはランタイムの境界でのみ実行してください。

これは スタック本体、カスタムリソースヘルパー、テスト に適用されます。テストでファイルまたはパスにアクセスする場合は、FileSystem.FileSystem/Path.Path を使用してください。

デプロイ/ランタイムのテストにおけるポーリングのルール:

  • Schedule と until 述語を組み合わせた Effect.repeat を使用し、times: N で上限を設定してください。
  • while (Date.now() < deadline) ループは使用しないでください。これは中断を無視し、vitest のタイムアウトまで処理が続く原因になります。
// good — declarative, bounded, interruption-safe
const value =
  yield *
  fetchValue.pipe(
    Effect.repeat({
      schedule: Schedule.spaced("5 seconds"),
      until: (v) => v.ready,
      times: 36,
    }),
  );

プロバイダーのライフサイクルテスト

カスタム Alchemy プロバイダー/リソースを作成する場合は、ヘルパー関数の単体テストだけでなく、alchemy/Test/Vitest を使ったプロバイダー形式のテストを追加してください。これらのテストでは、実際の Alchemy の計画/適用エンジン、プライベートなスクラッチ状態、デプロイの繰り返し、破棄の動作を、1 つの Effect プログラム内で検証します。

リソースのライフサイクルテストには、次の形式を使用してください。

import * as Test from "alchemy/Test/Vitest";
import { expect } from "@effect/vitest";
import * as Effect from "effect/Effect";
import * as ProviderNamespace from "../src/ProviderNamespace/index.ts";

const { test } = Test.make({ providers: ProviderNamespace.providers() });

test.provider("create, update, and delete resource", (stack) =>
  Effect.gen(function* () {
    const client = yield* ProviderNamespace.Client;

    const created = yield* stack.deploy(
      Effect.gen(function* () {
        return yield* ProviderNamespace.Resource("TestResource", {
          name: "v1",
        });
      }),
    );
    expect(created.resourceId).toBeDefined();

    // Verify live provider state through the provider SDK/client, not only
    // through returned attributes.
    const live1 = yield* client.get(created.resourceId);
    expect(live1.name).toBe("v1");

    const updated = yield* stack.deploy(
      Effect.gen(function* () {
        return yield* ProviderNamespace.Resource("TestResource", {
          name: "v2",
        });
      }),
    );
    expect(updated.resourceId).toBe(created.resourceId);

    const live2 = yield* client.get(updated.resourceId);
    expect(live2.name).toBe("v2");

    yield* stack.destroy();
  }),
);

プロバイダーテストのルール:

  • ファイルごとに const { test } = Test.make({ providers: Namespace.providers() }) を使ってプロバイダーを一度だけ構成してください。
  • 統合テストでは、実際のプロバイダー SDK/クライアントのアサーションを優先してください。実際の認証情報やリソースの使用が高コストまたは危険な場合は、フェイクのサービスレイヤーを使用してもかまいませんが、test.provider、stack.deploy(...)、デプロイの繰り返し、stack.destroy() を通じて実行してください。
  • Alchemy の状態がデプロイ間で共有されるよう、同じ test.provider 本体内で、適切に create → update/noop/replace → destroy をテストしてください。
  • テストに渡されるスクラッチスタックを使用してください。プロバイダーテストから .alchemy/ や共有状態に書き込まないでください。
  • プロバイダーの実装では、プロバイダーの構築時にサービスをクロージャーへ取り込んでください(ライフサイクルメソッドを返す前に const client = yield* Client とするなど)。Cloudflare プロバイダーと同じ方法です。Effect が明示的にサービスを提供している場合を除き、read/diff/reconcile/delete 内に yield* Client の要件を残さないでください。これを行うと、test.provider が「Service not found」エラーを検出するはずです。
  • 認証情報が必要な実プロバイダーのテストでは、alchemy deploy と同じ AuthProvider/設定経路(たとえば、環境変数方式の認証情報や alchemy login のテスト用プロファイル)を使って解決してください。認証情報がない場合はテストをスキップするか、実行を条件付きにしてください。シークレットをコミットしないでください。
  • 純粋な計算を含む、有用なパブリックコントラクトのテストは維持してください。すべてのプライベートな選択/名前/ステータス/マッピングのヘルパーに単体テストを必須とする必要はありません。プロバイダーテストでは、実際のライフサイクルの意味を引き続き検証してください。

ビルドと型チェック

スタック、カスタムリソース、またはランタイムバインディングに変更を加える場合は、コミット前に必ず型チェックを実行してください。

bun tsc -b

このコマンドは、プロジェクト参照モードでワークスペースのビルドを実行します。CI は型エラーで失敗するため、これは必須です。古い成果物や依存関係の不整合が原因で説明のつかない失敗が起きた場合は、クリーンビルドに切り替えてください。

bun run build       # clean + tsc + build the alchemy package
bun build:clean     # full reset: clean . + bun i + build + download env

bun build:clean は、未追跡ファイル(.env は保持)を削除し、依存関係を再インストールして、再ビルドし、環境ファイルを更新します。通常のコマンドではなく、復旧用のコマンドとして扱ってください。

シークレットと設定

リポジトリがリモートの状態バックエンドを明示的に管理しており、そのファイルがバージョン管理用に設計されている場合を除き、プロバイダートークン、API キー、生成されたプロファイル、状態ファイルをコミットしないでください。

次のルールに従ってください。

  • デプロイ認証情報には、プロバイダープロファイルまたは CI シークレットを優先して使用してください。
  • ランタイムシークレットには、Alchemy シークレットリソースまたはプロバイダー標準のシークレットリソースを使用してください。
  • シークレットではない設定をシークレットリソースに含めないでください。ランタイム設定は、リポジトリ内の名前付き設定ファイルとして管理し、effect/Config を通じて読み込みます。Workers では、名前付き設定をバンドルし、デプロイ時にはセレクター変数のみを設定してください(ADR-0014)。
  • darkmatter リポジトリでは、新しい .env の慣例を導入するのではなく、既存の SOPS/Himitsu/CI シークレット経路を使って、永続化が必要なシークレットを扱ってください。
  • 各デプロイ先を管理するプロファイル、アカウント、ゾーン、リージョン、またはプロジェクトを文書化してください。

CI デプロイ

CI は決定的で、対話を必要としないものである必要があります。

  1. リポジトリで固定されているパッケージマネージャーのコマンドで依存関係をインストールします。
  2. デプロイ前に型チェックを実行します。
  3. ブラウザーでのプロンプトを表示せずにプロバイダーを認証します。
  4. スタックパス、ステージ、プロファイルを明示してデプロイします。
  5. スモークテスト用に、スタックの出力を表示または取得します。
  6. ワークフローが一時的なインフラストラクチャを管理する場合、ブランチ/PR のクリーンアップ時にプレビューステージを破棄します。

CI コマンドの例:

bun install --frozen-lockfile
bun tsc -b
bun alchemy deploy ./alchemy.run.ts --stage "$ALCHEMY_STAGE" --profile "$ALCHEMY_PROFILE"

デプロイの失敗がプロバイダー認証、プロファイルの検索、状態ロック/状態の永続化、または CI シークレットの不足に起因する場合は、リソースコードを変更する前に、その層の問題を修正してください。

プレビュー URL と Webhook

パブリックプレビューは、Alchemy で想定されているワークフローです。

  • PR のデプロイでは --stage pr-<number> を使用し、リポジトリに GitHub へのアクセス権がある場合は、生成されたアプリの URL を PR に投稿してください。
  • Webhook や共同作業者がローカルコードを使ったパブリック URL にアクセスする必要がある場合は、ローカル開発で alchemy dev を使用してください。
  • プレビュー URL は、PR 番号から推測するのではなく、スタックの出力またはプロバイダーリソースから取得してください。
  • 可能な場合、Webhook テストでは curl だけでなく、実際の外部送信元を使用してください。
  • PR のクローズ/マージ時には、プレビューステージを破棄し、一時的な Webhook 登録を解除してください。

検証

デプロイ動作に関する依頼では、必ず実際のデプロイ先を検証してください。

bun alchemy deploy ./alchemy.run.ts --stage "$STAGE" --profile "$PROFILE"
curl -fsS "$DEPLOYED_URL"

ローカル開発の動作を確認する場合は、開発サーバーを起動し、Alchemy がローカル URL とパブリック/プロキシ URL の両方を表示する場合は、どちらにもアクセスしてください。

bun alchemy dev ./alchemy.run.ts --stage "$STAGE" --profile "$PROFILE"
curl -fsS "$LOCAL_URL"
curl -fsS "$PUBLIC_PREVIEW_URL"

Effect ネイティブのワーカー/関数では、ローカルだけのアサーションより、デプロイ済みのフィクスチャまたはスモークルートを優先してください。新しい Workers、Lambda URL、キュー、cron、DNS では、伝播に一定の範囲内での再試行が必要になることがよくあります。手動のポーリングループではなく、Schedule を使った Effect.retry または Effect.repeat を使用してください。

レビューチェックリスト

  • リポジトリに複数のアプリやパッケージがある場合、スタックのパスが明示されています。
  • リポジトリに明確な理由がない限り、デプロイ/開発のコントロールプレーンには Alchemy を使用しています。
  • スタック名、論理 ID、ステージ名、物理名が安定しており、決定的です。
  • プロバイダーと状態ストアの選択が、環境に応じて意図的に行われています。
  • 本番環境へのデプロイでは、--stage と --profile を明示的に指定しています。
  • 実際のクラウドリソース、公開プレビュー URL、または Webhook のテストが必要なローカル開発ループでは、alchemy dev を設定しています。
  • Alchemy がバインディングに対応している場合、ランタイムリソースでは、文字列の環境変数を各所に散在させる代わりにバインディングを使用しています。
  • シークレットをコミットしたり、ログに出力したり、スタック出力に埋め込んだりしていません。
  • CI でのデプロイは非対話型で、スタック出力または稼働中のエンドポイントを検証しています。
  • プレビューデプロイには削除手段があります。
  • Effect のコードでは、型付きエラー、Layer、再試行用の Schedule を使用しています。Promise ベースの SDK は境界で変換し、純粋な変換処理には通常の TypeScript を使用しています。
  • プロバイダーの操作が完了処理、エラー、クリーンアップを担っています。ファイル分割によって実際の複雑さを隠さず、設定された制限を維持したうえで、文書化された限定的な例外を設けています。

alchemy-effect へのコントリビューション

darkmatter のリポジトリで不足しているプロバイダー機能が必要な場合は、通常、ローカルでフォークするのではなく、上流に PR を送ります。PR を作成する際に重要な規約は 2 つあります。

  • PR タイトルには、Conventional Commits 形式を使用します(feat(aws/s3): add bucket lifecycle rules、fix(website): mobile theme metas)。
  • PR の説明は、# または ## の見出しで始めてはいけません。GitHub がタイトルをすでにその上に表示するためです。複数のセクションが本当に必要な場合に限り、最大でも ### を使用します。短い文章の要約、または新しい形式を示すコードスニペットから始め、差分ですでに示されている内容を繰り返す部分は削除します。「テスト計画」やチェックリストは含めないでください。
  • 未完了の作業については、PR の本文ではなく、PR 作成時のチャットで伝えます。未完了の項目や手動での確認が必要な項目がある場合は、PR をドラフトとして作成し、未完了の内容をユーザーに伝えてください。
  • 本文の受け渡しでは、本文を一時ファイルに書き込み、gh pr create/gh pr edit に --body-file を渡します。ヒアドキュメントや --body "$(cat …)" を使うと、gh のバージョンによってバッククォートが正しく扱われません。

website/src/content/docs/tutorial/ 配下のチュートリアルドキュメントを編集する場合は、1 つの概念につき、## 見出し 1 つ、差分スニペット 1 つ、文章の段落 1 つにします。「2 つ/3 つのことが起きました」という説明と番号付きリストの組み合わせは、スニペットを分割すべきサインです。

リソースの JSDoc を編集する場合は、bun generate:api-reference を実行して website/src/content/docs/providers/{Cloud}/{Resource}.md を更新してください。生成された Markdown は再生成のたびに上書きされるため、手動で編集しないでください。

上流の packages/alchemy/src/ 配下を変更する前に必要となる詳しい規約については、reference/provider-implementation.md を参照してください。

参考資料

  • reference/upstream-concepts.md — アプリやデプロイの作業で適用する Alchemy v2 と alchemy-effect の概念。
  • reference/examples.md — alchemy-run/alchemy-effect/examples のディレクトリと一般的なデプロイシナリオとの対応。
  • reference/provider-implementation.md — 上流へのプロバイダーコントリビューションに関するファイルシステム、リコンシリエーターの方針、機能の形、タグ、ランタイムコンテキスト、テスト用フィクスチャ、JSDoc/ドキュメント、チュートリアルの規約。
  • reference/alchemy-effect/ — 現在のソース、例、ドキュメント、上流のエージェント向け指示を含む、alchemy-run/alchemy-effect の特定コミットに固定された Git サブモジュール。

コメント