alchemy
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseAlchemy
Alchemy
Use this skill when configuring, developing, deploying, or debugging infrastructure with Alchemy v2 and the Effect-native patterns from . Alchemy treats infrastructure as an Effect program: stacks declare resources, providers supply cloud integrations, local dev can run app code locally against real cloud resources, and deploys converge declared resources into live cloud state.
alchemy-run/alchemy-effectAlchemy is the preferred Darkmatter path for new TypeScript/Effect deployable infrastructure. Reach for it before ad hoc provider scripts, hand-written Wrangler/Terraform glue, or one-off deploy workflows unless a repo has an explicit exception or an existing production system that should not be disturbed.
Alchemy v2 and move quickly. Verify upstream docs before changing deploy or dev code, especially package versions, provider APIs, behavior, and CLI flags. This skill carries the upstream repo as a local submodule at for source, examples, and agent instructions.
alchemy-effectalchemy devalchemy-run/alchemy-effectreference/alchemy-effect当你使用Alchemy v2以及提供的Effect原生模式配置、开发、部署或调试基础设施时,可使用此技能。Alchemy将基础设施视为一个Effect程序:栈(stack)声明资源,提供商(provider)提供云集成能力,本地开发可以在真实云资源上运行应用代码,部署则会将声明的资源收敛为实际的云状态。
alchemy-run/alchemy-effect对于新的TypeScript/Effect可部署基础设施,Alchemy是Darkmatter的首选方案。优先使用Alchemy,而非临时编写的提供商脚本、手写的Wrangler/Terraform粘合代码,或是一次性部署工作流——除非仓库有明确的例外规定,或是存在不应被改动的现有生产系统。
Alchemy v2和迭代很快。在修改部署或开发代码之前,请先查阅上游文档,尤其是包版本、提供商API、的行为以及CLI参数。此技能将上游的仓库作为本地子模块放在路径下,可用于查看源码、示例和Agent操作说明。
alchemy-effectalchemy devalchemy-run/alchemy-effectreference/alchemy-effectWhen to use
适用场景
- The user asks to set up or review an file.
alchemy.run.ts - The user asks to develop with , local Workers, public preview URLs, hot reload, or webhook testing.
alchemy dev - The user asks to configure an Alchemy deploy for Cloudflare Workers, Vite apps, R2, Queues, Durable Objects, D1, AWS Lambda, S3, DynamoDB, ECS, EC2, static sites, or related resources.
- The user asks how to use Alchemy stages, profiles, state stores, bindings, stack outputs, cross-stack references, or CI/CD.
- The user asks to migrate deploy plumbing toward Alchemy v2 or away from ad hoc provider scripts.
- The user asks for examples from .
alchemy-run/alchemy-effect/examples
- 用户要求设置或审查文件。
alchemy.run.ts - 用户要求使用、本地Workers、公共预览URL、热重载或webhook测试进行开发。
alchemy dev - 用户要求为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
When NOT to use
不适用场景
- The request is about the blockchain data/API company Alchemy and not .
alchemy.run - The project does not use TypeScript, Effect, Bun/Node, or Alchemy, and the user is only asking a generic deployment question.
- The task is to implement or modify a provider inside the upstream repo. Use the upstream repo's
alchemy-effectdirectly, then use this skill only for deploy-configuration implications.AGENTS.md - The task is purely Effect application logic with no deployable infrastructure. Use .
effect-typescript - A mature repo already has a production deploy path and the user asks for a narrow bug fix. Preserve the working path unless they explicitly ask to migrate.
- 请求涉及的是区块链数据/API公司Alchemy,而非。
alchemy.run - 项目不使用TypeScript、Effect、Bun/Node或Alchemy,且用户只是询问通用的部署问题。
- 任务是在上游仓库中实现或修改提供商。请直接使用上游仓库的
alchemy-effect,此技能仅用于处理部署配置相关的影响。AGENTS.md - 任务是纯Effect应用逻辑,不涉及可部署基础设施。请使用技能。
effect-typescript - 成熟的仓库已有生产部署路径,且用户只要求修复特定bug。请保留现有可用路径,除非用户明确要求迁移。
Upstream check
上游检查
Before editing, inspect the current docs or local installed package:
bash
bun alchemy --help
bun alchemy dev --help
bun pm ls alchemy effect @effect/platform-bun @effect/platform-nodeUse these upstream references first:
- for the current install command, first stack shape, and deploy flow.
https://v2.alchemy.run/getting-started/ - for stack names, outputs, stages, cross-stack references, and state isolation.
https://v2.alchemy.run/concepts/stack/ - and
https://v2.alchemy.run/concepts/local-development/forhttps://v2.alchemy.run/tutorial/part-4/.alchemy dev - for where state is persisted.
https://v2.alchemy.run/concepts/state-store/ - for non-interactive deploys and PR preview environments.
https://v2.alchemy.run/guides/ci/ - for upstream Effect-native infrastructure conventions.
reference/alchemy-effect/AGENTS.md - for the current project overview and install shape.
reference/alchemy-effect/README.md - for concrete app patterns.
reference/alchemy-effect/examples/ - for provider/resource implementation patterns.
reference/alchemy-effect/packages/alchemy/src/
If upstream conflicts with this skill, follow upstream and mention the drift.
If the submodule is missing in a fresh checkout, initialize it before relying on local references:
bash
git submodule update --init skills/alchemy/reference/alchemy-effectTreat the submodule as read-only during app/deploy work. Edit it only when the user explicitly asks for an upstream contribution, and then follow as the repo-local authority.
alchemy-effectreference/alchemy-effect/AGENTS.md在编辑之前,请检查当前文档或本地安装的包:
bash
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/ - 和
https://v2.alchemy.run/concepts/local-development/:了解https://v2.alchemy.run/tutorial/part-4/的用法。alchemy dev - :了解状态的持久化位置。
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/
如果上游文档与此技能存在冲突,请遵循上游文档,并说明差异。
如果在新克隆的代码中子模块缺失,请先初始化子模块,再依赖本地参考资料:
bash
git submodule update --init skills/alchemy/reference/alchemy-effect在应用/部署工作中,请将子模块视为只读。仅当用户明确要求向上游贡献代码时才可编辑,且需遵循作为仓库本地的权威规范。
alchemy-effectreference/alchemy-effect/AGENTS.mdProject setup
项目设置
Prefer Bun unless the project already standardizes on another package manager. Current Alchemy v2 docs recommend Bun or Node.js 22+ and install Alchemy with Effect platform packages:
bash
bun add "alchemy@2.0.0-beta.40" "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"Pin package versions according to the existing repo policy. If a repo already uses a catalog, workspace protocol, or lockfile-only upgrade lane, follow that instead of pasting the docs command blindly.
Before adding Alchemy to an existing repo, inspect the current setup:
bash
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'If the repo does not already have Alchemy configured, ask the user whether they want Alchemy set up for local development as well as deploys. Do not silently create a deploy-only setup: changes the local workflow by provisioning real cloud resources, exposing public preview URLs, and enabling webhook/OAuth callback testing against local code. If the user says yes, include the script, dev-stage/profile guidance, public preview output handling, and webhook test notes in the first implementation.
alchemy devdevAdd scripts that make the stack path explicit when the repo has more than one app:
json
{
"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"
}
}Use plain only in tiny repos where at the root is unambiguous.
bun alchemy deployalchemy.run.ts除非项目已标准化使用其他包管理器,否则优先使用Bun。当前Alchemy v2文档推荐使用Bun或Node.js 22+,并通过Effect平台包安装Alchemy:
bash
bun add "alchemy@2.0.0-beta.40" "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"请根据现有仓库的策略锁定包版本。如果仓库已使用目录、workspace协议或仅lockfile升级路径,请遵循该策略,不要盲目粘贴文档中的命令。
在向现有仓库添加Alchemy之前,请检查当前的配置:
bash
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,请询问用户是否需要同时配置本地开发和部署功能。不要静默创建仅用于部署的配置:会通过供应真实云资源、暴露公共预览URL、支持针对本地代码的webhook/OAuth回调测试,来改变本地工作流。如果用户同意,请在首次实现中包含脚本、开发阶段/配置文件指引、公共预览输出处理以及webhook测试说明。
alchemy devdev当仓库中有多个应用时,请添加脚本以明确栈的路径:
json
{
"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.tsbun alchemy deployOrg default
组织默认规范
For Darkmatter TypeScript/Effect projects, prefer Alchemy for deployable infrastructure:
- New Cloudflare Workers, Vite/frontends, queues, R2/KV, workflows, AI Gateway, tunnels, and GitHub deploy automation should start with Alchemy.
- Application data is Postgres-first. Use Kysely + for query-heavy TypeScript adapters, or Effect SQL Postgres for Effect-native database services. Let Alchemy own the deploy wiring, bindings, secrets, and network resources around that database where the provider supports it.
pg - Use D1/sqlite only for narrow edge-local state, demos, or an explicit project decision. Do not pick D1 because the app is on Cloudflare if the data model belongs in Postgres.
- New AWS Lambda, S3, DynamoDB, API Gateway, ECS/EC2/EKS/RDS, and static-site deploys should consider Alchemy first.
- Shared preview environments should use Alchemy stages instead of bespoke name mangling.
- Local webhook testing should use or an Alchemy-managed tunnel/preview flow instead of separate ngrok/Cloudflare Tunnel scripts when Alchemy can provide the route.
alchemy dev - Hand-written provider CLIs can still be useful for diagnostics, but should not become the durable deploy control plane without a reason.
对于Darkmatter的TypeScript/Effect项目,可部署基础设施优先使用Alchemy:
- 新的Cloudflare Workers、Vite/前端应用、队列、R2/KV、工作流、AI Gateway、隧道和GitHub部署自动化,都应从Alchemy开始。
- 应用数据优先使用Postgres。对于查询密集的TypeScript适配器,使用Kysely + ;对于Effect原生数据库服务,使用Effect SQL Postgres。在提供商支持的情况下,由Alchemy负责该数据库的部署配置、绑定、密钥和网络资源。
pg - 仅在有限的边缘本地状态、演示或明确的项目决策下,才使用D1/sqlite。如果数据模型适合Postgres,不要因为应用部署在Cloudflare上就选择D1。
- 新的AWS Lambda、S3、DynamoDB、API Gateway、ECS/EC2/EKS/RDS和静态站点部署,应优先考虑Alchemy。
- 共享预览环境应使用Alchemy的阶段,而非自定义的名称拼接。
- 当Alchemy可以提供路由时,本地webhook测试应使用或Alchemy管理的隧道/预览流程,而非单独的ngrok/Cloudflare Tunnel脚本。
alchemy dev - 手写的提供商CLI对于诊断仍然有用,但不应无故成为长期的部署控制平面。
Stack shape
栈结构
Every deploy file should default-export .
Alchemy.Stack(name, options, Effect.gen(...))ts
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,
};
}),
);The load-bearing pieces are:
- Stack name: stable logical deployment unit. Do not casually rename it; state and names derive from it.
- Providers: cloud auth and provider implementations, for example or
Cloudflare.providers().AWS.providers() - State: choose deliberately. Cloudflare deploys commonly use ; simple AWS examples may use
Cloudflare.state().Alchemy.localState() - Effect body: declare resources with , compose dependencies through references and bindings, and return useful outputs for smoke checks.
yield*
每个部署文件都应默认导出。
Alchemy.Stack(name, options, Effect.gen(...))ts
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部署通常使用;简单的AWS示例可能使用
Cloudflare.state()。Alchemy.localState() - Effect主体:使用声明资源,通过引用和绑定组合依赖,并返回有用的输出用于冒烟测试。
yield*
Effect-native provider module layout
Effect原生提供商模块结构
Follow codebase-design for shared readability
rules. A provider owns the operations that converge a resource and the cleanup
needed when those operations fail or finish. Inspect the installed Alchemy
version and pinned upstream provider before choosing API names or registration
shapes. Upstream contributions follow that repository's own layout.
For a provider implemented in a Darkmatter app or package:
- Group by the resource or provider domain, then use ,
models/,services/, andadapters/where those roles have real responsibilities. A single-domain package already supplies the owner.workflows/ - Keep resource schemas and inferred types together. Expose the resource contract and supported provider layer through explicit package entries.
- Keep adoption, comparison, mapping, and status helpers with the lifecycle
implementation that needs them. Extract when it hides complexity or enables
useful reuse; avoid a file per helper or separate and
Typescopies.Schemas - A shared client can own API requests, response decoding, and typed failures. Use an Effect-native SDK directly; wrap a Promise SDK only at that edge. Keep configuration and credentials in the existing config/provider layers.
- Preserve Alchemy's resource/provider collection and binding contracts. Public composition may register several resource layers without re-exporting every internal helper through a chain of barrels.
- Keep configured file limits. Document a targeted increase when a forced split would scatter one coherent reconciler.
Test refactors through the resource or provider interface. Retain lifecycle
coverage for create, repeated deploy, adoption, update, and destroy as applicable.
Use real provider clients or substitute an external service through a Layer.
Do not extract or export private selection/mapping helpers just to test them;
a public pure helper with its own contract can retain focused tests.
请遵循代码库设计中的通用可读性规则。提供商负责资源收敛操作,以及操作失败或完成后的清理工作。在选择API名称或注册形式之前,请检查已安装的Alchemy版本和锁定的上游提供商。上游贡献需遵循对应仓库自身的结构规范。
对于在Darkmatter应用或包中实现的提供商:
- 按资源或提供商领域分组,然后根据实际职责使用、
models/、services/和adapters/目录。单领域包本身已经明确了归属。workflows/ - 将资源schema和推断类型放在一起。通过明确的包入口暴露资源契约和支持的提供商层。
- 将采纳、比较、映射和状态辅助函数与需要它们的生命周期实现放在一起。仅当这些辅助函数能隐藏复杂性或实现有用的复用才提取出来;避免每个辅助函数一个文件,或是分离出和
Types的副本。Schemas - 共享客户端可以负责API请求、响应解码和类型化错误。直接使用Effect原生SDK;仅在边界处封装Promise SDK。将配置和凭证保存在现有的配置/提供商层中。
- 保留Alchemy的资源/提供商集合和绑定契约。公共组合可以注册多个资源层,而无需通过一连串的重新导出文件暴露每个内部辅助函数。
- 遵守配置的文件数量限制。如果强制拆分导致一个连贯的协调器被分散,请记录针对性的文件数上调说明。
通过资源或提供商接口测试重构。根据适用情况,保留对创建、重复部署、采纳、更新和销毁的生命周期覆盖。使用真实的提供商客户端,或通过Layer替换外部服务。不要为了测试就提取或导出私有的选择/映射辅助函数;具有自身契约的公共纯函数可以保留针对性的测试。
Local development
本地开发
Use for the default local loop when the app can run through Alchemy:
alchemy devbash
bun alchemy dev ./alchemy.run.tsAlchemy dev mode deploys infrastructure to the real cloud provider, runs supported app code locally, and hot reloads on file changes. For Cloudflare Workers, the Worker runs locally in while a cloud proxy routes requests between public cloud endpoints and the local process.
workerdThis matters for webhook work: external services need a public URL, while the developer needs local code, breakpoints, and hot reload. Prefer an Alchemy dev/preview URL for webhook callbacks when available, then configure the third-party webhook target to that URL for the session or preview stage.
Use explicit dev ports when the app has multiple local services or a fixed callback URL:
ts
export const Worker = Cloudflare.Worker("Worker", {
main: "./src/worker.ts",
dev: {
port: 3000,
},
});Dev-mode rules:
- Treat cloud resources created by as real resources, not emulators.
alchemy dev - Keep stage/profile explicit when working near shared accounts.
- Return local/public URLs from stack outputs so the agent can test the live route.
- Verify webhook flows with the provider's actual delivery logs when available.
- Stop the dev process cleanly; destroy dev/preview resources when they are no longer needed and the stack owns them.
当应用可以通过Alchemy运行时,使用作为默认的本地开发循环:
alchemy devbash
bun alchemy dev ./alchemy.run.tsAlchemy开发模式会将基础设施部署到真实的云提供商,在本地运行支持的应用代码,并在文件变更时热重载。对于Cloudflare Workers,Worker在本地的中运行,同时云代理在公共云端点和本地进程之间路由请求。
workerd这对于webhook开发很重要:外部服务需要公共URL,而开发者需要本地代码、断点和热重载。在可用的情况下,优先使用Alchemy开发/预览URL作为webhook回调地址,然后将第三方webhook目标配置为该URL,用于当前会话或预览阶段。
当应用有多个本地服务或固定的回调URL时,请使用明确的开发端口:
ts
export const Worker = Cloudflare.Worker("Worker", {
main: "./src/worker.ts",
dev: {
port: 3000,
},
});开发模式规则:
- 将创建的云资源视为真实资源,而非模拟器。
alchemy dev - 在共享账户上工作时,保持阶段/配置文件的明确性。
- 从栈输出中返回本地/公共URL,以便Agent可以测试实时路由。
- 在可用的情况下,使用提供商的实际投递日志验证webhook流程。
- 干净地停止开发进程;当开发/预览资源不再需要且属于该栈时,销毁这些资源。
Stage and profile rules
阶段与配置文件规则
Treat stage and profile as part of the deployment contract:
- Stage isolates state and physical names. The default is developer-specific; use explicit ,
--stage prod, or--stage stagingfor shared environments.--stage pr-123 - Profile selects credentials. First deploy may prompt interactively and save credentials under ; non-interactive CI must have profiles or provider credentials prepared before deploy.
~/.alchemy/profiles.json - Production scripts should pass both and the intended
--stage prod.--profile - Preview deploys should derive a deterministic stage from the PR, branch, or issue id and should destroy that stage when it is no longer needed.
Useful commands:
bash
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 --configureNever use or random timestamps in physical names. Let Alchemy generate names from stack, stage, and logical id, or use a deterministic name tied to the environment.
Date.now()将阶段和配置文件视为部署契约的一部分:
- 阶段用于隔离状态和物理名称。默认是开发者专属的;对于共享环境,请使用明确的、
--stage prod或--stage staging。--stage pr-123 - 配置文件用于选择凭证。首次部署可能会交互式提示,并将凭证保存在下;非交互式CI必须在部署前准备好配置文件或提供商凭证。
~/.alchemy/profiles.json - 生产环境脚本应同时传递和目标
--stage prod。--profile - 预览部署应从PR、分支或issue ID派生出确定性的阶段,并在不再需要时销毁该阶段。
常用命令:
bash
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切勿在物理名称中使用或随机时间戳。让Alchemy根据栈、阶段和逻辑ID生成名称,或使用与环境绑定的确定性名称。
Date.now()Bindings and runtime dependencies
绑定与运行时依赖
Prefer bindings over manually threading deployed identifiers through environment variables. A binding is deploy-time data attached to a runtime resource so the function/worker receives exactly the infrastructure dependency it needs.
For Cloudflare, bind platform resources directly into a Worker or Vite app:
ts
export const Bucket = Cloudflare.R2Bucket("Bucket");
export const Worker = Cloudflare.Worker("Worker", {
main: "./src/worker.ts",
bindings: {
Bucket,
},
});Keep Postgres connection details in the app's config/secrets layer and expose
the runtime client through a service Layer. Only bind a database-like Cloudflare
resource when the repo has an explicit reason not to use Postgres for that data.
For Effect-native runtimes, keep runtime services and deploy wiring separate. Alchemy owns cloud resources and bindings; Effect services own runtime behavior. Use Layers at the stack boundary when the resource requires a runtime implementation.
优先使用绑定,而非通过环境变量手动传递部署后的标识符。绑定是附加在运行时资源上的部署时数据,这样函数/worker就能准确接收其所需的基础设施依赖。
对于Cloudflare,将平台资源直接绑定到Worker或Vite应用:
ts
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。
Capability shape: Binding.Service
+ Binding.Policy
Binding.ServiceBinding.Policy能力结构:Binding.Service
+ Binding.Policy
Binding.ServiceBinding.PolicyEvery Alchemy capability ships as a pair of layers:
- — runtime SDK wrapper, provided on the Function/Worker Effect (bundled into the deployed artifact).
Binding.Service - — deploy-time IAM/binding attachment, provided on the Stack via
Binding.Policy, never bundled.AWS.providers()()
For Cloudflare, the worker field handles both sides automatically. For AWS, the Service layer goes on the Function and the Policy layer must be enabled at the stack level. The default already enables the common policy layers; only reach for when you author or override a capability.
bindings: { ... }AWS.providers()AWS.providers()(extraLayers)每个Alchemy能力都以一对层的形式提供:
- — 运行时SDK封装器,在Function/Worker的Effect上提供(被打包到部署产物中)。
Binding.Service - — 部署时IAM/绑定附件,通过
Binding.Policy在栈上提供,永远不会被打包。AWS.providers()()
对于Cloudflare,worker的字段会自动处理这两部分。对于AWS,Service层位于Function上,而Policy层必须在栈级别启用。默认的已经启用了常用的策略层;仅当你编写或覆盖某个能力时,才需要使用。
bindings: { ... }AWS.providers()AWS.providers()(extraLayers)Alchemy.RuntimeContext
on runtime-only methods
Alchemy.RuntimeContext仅运行时方法上的Alchemy.RuntimeContext
Alchemy.RuntimeContextBindings expose a typed callable whose inner Effect carries an requirement. Treat that as a colored function:
Alchemy.RuntimeContext- The outer Effect (setup at function init) does NOT require .
RuntimeContext - The inner Effect (the actual SDK call) MUST require and only runs inside a deployed Function/Worker.
RuntimeContext
If a service wraps a binding and accidentally leaks / into its interface, that service becomes cloud-coupled. Resolve cloud env services once during Layer construction and close over them — do not expose them as requirements on consumer Effects.
WorkerEnvironmentLambda.FunctionEnvironment绑定暴露一个类型化的可调用对象,其内部Effect带有依赖。请将其视为一种「有色函数」:
Alchemy.RuntimeContext- 外层Effect(在函数初始化时设置)不需要。
RuntimeContext - 内层Effect(实际的SDK调用)必须依赖,且仅在已部署的Function/Worker中运行。
RuntimeContext
如果某个服务封装了一个绑定,却不小心将 / 泄露到其接口中,那么该服务就会与云耦合。在Layer构造期间一次性解析云环境服务并将其闭包起来——不要将它们作为依赖暴露给消费者的Effect。
WorkerEnvironmentLambda.FunctionEnvironmentEffect platform rules in app/runtime code
应用/运行时代码中的Effect平台规则
Alchemy stacks and Worker/Function bodies run as Effect programs. Do not reach for raw async or Node primitives inside :
Effect.gen| Don't | Do |
|---|---|
| |
| |
| |
| |
| |
| Make the helper itself return an |
Pure transformations do not need Effect wrappers. Suspend environment reads
and side effects in Effect; classify expected thrown failures when crossing an
external boundary. Wrapping a CPU calculation does not make that calculation
interruptible. Keep internal operations in Effect once a driver has been adapted,
and run them only at the host or runtime boundary that requires it.
This applies to stack bodies, custom resource helpers, and tests. Tests must use / for any file/path access.
FileSystem.FileSystemPath.PathPolling rules for deploy/runtime tests:
- Use with
Effect.repeat+ anSchedulepredicate and a boundeduntilcap.times: N - Do not write loops — they ignore interruption and leak into the vitest timeout.
while (Date.now() < deadline)
ts
// good — declarative, bounded, interruption-safe
const value =
yield *
fetchValue.pipe(
Effect.repeat({
schedule: Schedule.spaced("5 seconds"),
until: (v) => v.ready,
times: 36,
}),
);Alchemy栈和Worker/Function体都作为Effect程序运行。不要在中使用原始的async或Node原语:
Effect.gen| 不要这样做 | 应该这样做 |
|---|---|
| |
| |
| |
| |
| |
| Make the helper itself return an |
纯转换不需要Effect封装。将环境读取和副作用挂起到Effect中;在跨越外部边界时,对预期的抛出错误进行分类。封装CPU计算并不会让该计算变得可中断。一旦适配了驱动程序,就将内部操作放在Effect中,并仅在需要的主机或运行时边界执行它们。
这适用于栈主体、自定义资源辅助函数和测试。测试中任何文件/路径访问都必须使用 / 。
FileSystem.FileSystemPath.Path部署/运行时测试的轮询规则:
- 使用带
Effect.repeat+Schedule谓词,并设置有界的until上限。times: N - 不要编写循环——它们会忽略中断,并且会超出vitest的超时时间。
while (Date.now() < deadline)
ts
// good — declarative, bounded, interruption-safe
const value =
yield *
fetchValue.pipe(
Effect.repeat({
schedule: Schedule.spaced("5 seconds"),
until: (v) => v.ready,
times: 36,
}),
);Provider lifecycle tests
提供商生命周期测试
When authoring custom Alchemy providers/resources, add provider-style tests with rather than only unit-testing helper functions. These tests exercise the real Alchemy plan/apply engine, private scratch state, repeated deploys, and destroy behavior in one Effect program.
alchemy/Test/VitestUse this shape for resource lifecycle tests:
ts
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();
}),
);Provider test rules:
- Configure providers once per file with .
const { test } = Test.make({ providers: Namespace.providers() }) - Prefer real provider SDK/client assertions for integration tests. If live credentials or real resources are expensive/dangerous, use a fake service layer but still run through ,
test.provider, repeated deploy, andstack.deploy(...).stack.destroy() - Test create → update/noop/replace as appropriate → destroy in the same body so Alchemy state is shared across deploys.
test.provider - Use the scratch stack handed to the test; do not write to or shared state from provider tests.
.alchemy/ - Provider implementations should close over services at provider construction (before returning lifecycle methods), matching Cloudflare providers. Do not leave
const client = yield* Clientrequirements insideyield* Client/read/diff/reconcileunless the effect is explicitly provided there;deleteshould catch this with a “Service not found” failure.test.provider - For live provider tests that need credentials, resolve them through the same AuthProvider/config path as (for example env-method credentials or an
alchemy deploytest profile). Skip or gate the test when credentials are absent; do not commit secrets.alchemy login - Preserve useful public-contract tests, including pure calculations. Do not require unit tests for every private selection/name/status/mapping helper; provider tests should continue to verify real lifecycle semantics.
在编写自定义Alchemy提供商/资源时,请使用添加提供商风格的测试,而不仅仅是对辅助函数进行单元测试。这些测试会在一个Effect程序中验证真实的Alchemy计划/应用引擎、私有临时状态、重复部署和销毁行为。
alchemy/Test/Vitest资源生命周期测试请使用以下结构:
ts
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 - 使用传递给测试的临时栈;不要从提供商测试中写入或共享状态。
.alchemy/ - 提供商实现应在提供商构造时闭包服务(在返回生命周期方法之前执行),与Cloudflare提供商保持一致。不要在
const client = yield* Client/read/diff/reconcile中留下delete依赖,除非该Effect在那里被明确提供;yield* Client应该会通过「Service not found」错误捕获到这种情况。test.provider - 对于需要凭证的真实提供商测试,请通过与相同的AuthProvider/配置路径解析凭证(例如环境变量方式的凭证或
alchemy deploy的测试配置文件)。当缺少凭证时,跳过或限制测试;不要提交密钥。alchemy login - 保留有用的公共契约测试,包括纯计算。不要要求每个私有的选择/名称/状态/映射辅助函数都有单元测试;提供商测试应继续验证真实的生命周期语义。
Build and type checking
构建与类型检查
Always type-check before committing changes that touch a stack, custom resource, or runtime binding:
bash
bun tsc -bThis runs the workspace build in project-reference mode. CI fails on type errors, so this is non-negotiable. When stale artifacts or dependency drift cause unexplained failures, fall back to a clean rebuild:
bash
bun run build # clean + tsc + build the alchemy package
bun build:clean # full reset: clean . + bun i + build + download envbun build:clean.env提交涉及栈、自定义资源或运行时绑定的更改之前,务必进行类型检查:
bash
bun tsc -b这会以项目引用模式运行工作区构建。CI会因类型错误而失败,因此这是必须执行的。当过时的产物或依赖漂移导致无法解释的失败时,请回退到干净重建:
bash
bun run build # clean + tsc + build the alchemy package
bun build:clean # full reset: clean . + bun i + build + download envbun build:clean.envSecrets and config
密钥与配置
Do not commit provider tokens, API keys, generated profiles, or state files unless the repo explicitly owns a remote state backend and the file is designed for version control.
Use these rules:
- Prefer provider profiles or CI secrets for deploy credentials.
- Use Alchemy secret resources or provider-native secret resources for runtime secrets.
- Keep non-secret config out of secret resources. Runtime configuration is a named config file in the repo, read through ; on Workers, bundle the named configs and let the deploy set only the selector var (ADR-0014).
effect/Config - In darkmatter repos, route durable secrets through the repo's existing SOPS/Himitsu/CI secret path instead of inventing a new convention.
.env - Document which profile, account, zone, region, or project owns each deploy target.
不要提交提供商令牌、API密钥、生成的配置文件或状态文件,除非仓库明确拥有远程状态后端,且该文件是为版本控制设计的。
请遵循以下规则:
- 部署凭证优先使用提供商配置文件或CI密钥。
- 运行时密钥使用Alchemy密钥资源或提供商原生的密钥资源。
- 非密钥配置不要放在密钥资源中。运行时配置是仓库中的命名配置文件,通过读取;在Workers上,打包命名配置,让部署仅设置选择器变量(ADR-0014)。
effect/Config - 在Darkmatter仓库中,持久化密钥通过仓库现有的SOPS/Himitsu/CI密钥路径传递,不要发明新的约定。
.env - 记录每个部署目标所属的配置文件、账户、区域、地区或项目。
CI deploys
CI部署
CI should be deterministic and non-interactive:
- Install dependencies with the repo's locked package manager command.
- Run type checks before deploy.
- Authenticate the provider without a browser prompt.
- Deploy with explicit stack path, stage, and profile.
- Print or capture stack outputs for smoke tests.
- Destroy preview stages on branch/PR cleanup when the workflow owns temporary infrastructure.
Example CI command shape:
bash
bun install --frozen-lockfile
bun tsc -b
bun alchemy deploy ./alchemy.run.ts --stage "$ALCHEMY_STAGE" --profile "$ALCHEMY_PROFILE"If a deploy failure starts in provider auth, profile lookup, state lock/state persistence, or missing CI secrets, fix that layer before changing resource code.
CI应具有确定性且非交互式:
- 使用仓库锁定的包管理器命令安装依赖。
- 在部署前运行类型检查。
- 无需浏览器提示即可完成提供商认证。
- 使用明确的栈路径、阶段和配置文件进行部署。
- 打印或捕获栈输出以用于冒烟测试。
- 当工作流拥有临时基础设施时,在分支/PR清理时销毁预览阶段。
CI命令示例格式:
bash
bun install --frozen-lockfile
bun tsc -b
bun alchemy deploy ./alchemy.run.ts --stage "$ALCHEMY_STAGE" --profile "$ALCHEMY_PROFILE"如果部署失败始于提供商认证、配置文件查找、状态锁/状态持久化或缺少CI密钥,请先修复该层,再修改资源代码。
Preview URLs and webhooks
预览URL与webhook
Public previews are an expected Alchemy workflow:
- PR deploys should use and post the resulting app URL back to the PR when the repo has GitHub access.
--stage pr-<number> - Local development should use when a webhook or collaborator needs to reach a public URL backed by local code.
alchemy dev - Preview URLs should be derived from stack outputs or provider resources, not guessed from PR numbers.
- Webhook tests should exercise the real external sender when feasible, not only .
curl - Cleanup should destroy preview stages on PR close/merge and retire temporary webhook registrations.
公共预览是Alchemy的标准工作流:
- PR部署应使用,并在仓库有GitHub访问权限时将生成的应用URL回发到PR。
--stage pr-<number> - 当webhook或协作者需要访问由本地代码支持的公共URL时,本地开发应使用。
alchemy dev - 预览URL应从栈输出或提供商资源中获取,而非根据PR编号猜测。
- 可行的话,webhook测试应使用真实的外部发送方,而不仅仅是。
curl - 清理时应在PR关闭/合并时销毁预览阶段,并注销临时webhook注册。
Verification
验证
Always verify the real deployed target when the request concerns deploy behavior:
bash
bun alchemy deploy ./alchemy.run.ts --stage "$STAGE" --profile "$PROFILE"
curl -fsS "$DEPLOYED_URL"For local dev behavior, run the dev server and hit both local and public/proxied URLs when Alchemy prints both:
bash
bun alchemy dev ./alchemy.run.ts --stage "$STAGE" --profile "$PROFILE"
curl -fsS "$LOCAL_URL"
curl -fsS "$PUBLIC_PREVIEW_URL"For Effect-native workers/functions, prefer a deployed fixture or smoke route over a purely local assertion. Fresh Workers, Lambda URLs, queues, cron, and DNS often need bounded retries for propagation; use or with , not manual polling loops.
Effect.retryEffect.repeatSchedule当请求涉及部署行为时,务必验证真实的部署目标:
bash
bun alchemy deploy ./alchemy.run.ts --stage "$STAGE" --profile "$PROFILE"
curl -fsS "$DEPLOYED_URL"对于本地开发行为,当Alchemy同时打印本地和公共/代理URL时,请运行开发服务器并访问这两个URL:
bash
bun alchemy dev ./alchemy.run.ts --stage "$STAGE" --profile "$PROFILE"
curl -fsS "$LOCAL_URL"
curl -fsS "$PUBLIC_PREVIEW_URL"对于Effect原生的workers/functions,优先使用已部署的测试夹具或冒烟路由,而非纯本地断言。新的Workers、Lambda URL、队列、cron和DNS通常需要有界的重试来完成传播;使用带有的或,而非手动轮询循环。
ScheduleEffect.retryEffect.repeatReview checklist
审查清单
- The stack path is explicit where the repo has multiple apps or packages.
- Alchemy is used as the deploy/dev control plane unless the repo has an explicit reason not to.
- Stack name, logical IDs, stage names, and physical names are stable and deterministic.
- Provider and state store choices are intentional for the environment.
- Prod deploys pass explicit and
--stage.--profile - is configured for local loops that need real cloud resources, public preview URLs, or webhook testing.
alchemy dev - Runtime resources use bindings rather than scattered string env vars where Alchemy supports bindings.
- Secrets are not committed, echoed in logs, or encoded into stack outputs.
- CI deploys are non-interactive and verify stack outputs or live endpoints.
- Preview deploys have a destroy path.
- Effect code uses typed errors, Layers, and for retries; Promise SDKs are adapted at their edge, and pure transformations stay plain TypeScript.
Schedule - Provider operations own completion, errors, and cleanup. File splits hide real complexity and retain configured limits with documented, targeted exceptions.
- 当仓库有多个应用或包时,栈路径是明确的。
- Alchemy被用作部署/开发控制平面,除非仓库有明确的理由不这样做。
- 栈名称、逻辑ID、阶段名称和物理名称是稳定且确定的。
- 提供商和状态存储的选择是针对环境有意选择的。
- 生产部署传递了明确的和
--stage。--profile - 已为需要真实云资源、公共预览URL或webhook测试的本地开发循环配置好。
alchemy dev - 在Alchemy支持绑定的情况下,运行时资源使用绑定,而非分散的字符串环境变量。
- 密钥没有被提交、在日志中回显,或是被编码到栈输出中。
- CI部署是非交互式的,并验证栈输出或实时端点。
- 预览部署有销毁路径。
- Effect代码使用类型化错误、Layers和进行重试;Promise SDK在边界处被适配,纯转换保持为普通TypeScript。
Schedule - 提供商操作负责完成、错误和清理。文件拆分应隐藏真实复杂性,并通过记录在案的针对性例外保留配置的限制。
Contributing back to alchemy-effect
alchemy-effect向alchemy-effect
贡献代码
alchemy-effectIf a darkmatter repo needs a missing provider feature, the path is usually a PR upstream rather than a local fork. Two conventions matter when you open that PR:
- PR title uses conventional commits (,
feat(aws/s3): add bucket lifecycle rules).fix(website): mobile theme metas - PR description never starts with a or
#heading — GitHub already renders the title above it. Use##at most, and only when the description genuinely has multiple sections. Lead with a short prose summary or a code snippet that shows the new shape; cut anything that restates what the diff already shows. Never include a "Test plan" or checklist.### - Outstanding work belongs in the PR-creation chat, not in the PR body. If something is unfinished or needs manual verification, mark the PR as draft and tell the user what is outstanding.
- Body delivery: write the body to a temp file and pass to
--body-file/gh pr create. Heredoc/gh pr editmangles backticks across--body "$(cat …)"versions.gh
If you edit tutorial docs under , one concept gets one heading, one diff snippet, and one prose paragraph. "Two/three things just happened" + a numbered list is the smell that says split the snippet.
website/src/content/docs/tutorial/##If you edit resource JSDoc, run to refresh . The generated markdown is overwritten on every regeneration — never hand-edit it.
bun generate:api-referencewebsite/src/content/docs/providers/{Cloud}/{Resource}.mdreference/provider-implementation.mdpackages/alchemy/src/如果Darkmatter仓库需要某个缺失的提供商功能,通常的做法是向上游提交PR,而非本地分叉。提交PR时需要注意两个约定:
- PR标题使用约定式提交(例如、
feat(aws/s3): add bucket lifecycle rules)。fix(website): mobile theme metas - PR描述不要以或
#标题开头——GitHub已经在上方渲染了标题。最多使用##,且仅当描述确实有多个部分时才用。以简短的文字摘要或展示新结构的代码片段开头;删掉任何重复diff已经展示内容的部分。永远不要包含「测试计划」或清单。### - 未完成工作应放在PR创建的聊天中,而非PR正文中。如果有未完成的内容或需要手动验证,请将PR标记为草稿,并告知用户未完成的内容。
- 正文传递:将正文写入临时文件,并将传递给
--body-file/gh pr create。Heredoc/gh pr edit的方式在不同--body "$(cat …)"版本中会破坏反引号。gh
如果你编辑下的教程文档,一个概念对应一个标题、一个diff片段和一段文字说明。如果出现「刚刚发生了两三件事」+编号列表的情况,就说明应该拆分片段了。
website/src/content/docs/tutorial/##如果你编辑资源的JSDoc,请运行来刷新。生成的markdown在每次重新生成时都会被覆盖——永远不要手动编辑它。
bun generate:api-referencewebsite/src/content/docs/providers/{Cloud}/{Resource}.md在接触上游下的任何内容之前,中有你需要的详细约定。
packages/alchemy/src/reference/provider-implementation.mdReferences
参考资料
- — Alchemy v2 and
reference/upstream-concepts.mdconcepts applied during app/deploy work.alchemy-effect - —
reference/examples.mddirectories mapped to common deploy scenarios.alchemy-run/alchemy-effect/examples - — file system, reconciler doctrine, capability shape, tags, runtime context, test fixtures, JSDoc/docs, and tutorial standards for upstream provider contributions.
reference/provider-implementation.md - — pinned git submodule of
reference/alchemy-effect/for current source, examples, docs, and upstream agent instructions.alchemy-run/alchemy-effect
- — 应用/部署工作中用到的Alchemy v2和
reference/upstream-concepts.md概念。alchemy-effect - — 映射到常见部署场景的
reference/examples.md目录。alchemy-run/alchemy-effect/examples - — 上游提供商贡献的文件系统、协调器原则、能力结构、标签、运行时上下文、测试夹具、JSDoc/文档和教程标准。
reference/provider-implementation.md - —
reference/alchemy-effect/的固定git子模块,用于查看当前源码、示例、文档和上游Agent操作说明。alchemy-run/alchemy-effect