Adding an Agent to an Effect Golem Component
SkillAI & modelsGuides your agent through writing and registering an Effect-based agent in a Golem component, with schemas, methods, and durable state.
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the Adding an Agent to an Effect Golem Component skill
About this capability
Adding an Effect-based agent to a Golem component. Use when creating or defining an agent type, adding agent methods, schemas, durable state, or Effect implementations in an @golemcloud/effect-golem project.
What this skill tells your AI
The instructions your AI receives, as published by golemcloud/golem in golem-skills/skills/effect/golem-add-agent-effect/SKILL.md and read by ahel’s review.
Effect Golem agents declare their public contract with Effect Schema and implement every method
as an Effect. A top-level defineAgent(...).implement({ init, methods }) call registers the agent when its
module is imported.
Steps
- Add
src/<agent-name>.tswith the schemas, definition, and implementation. - Declare constructor identity and method contracts with
defineAgentandmethod. - Implement
initas an Effect and derive all handlers from its shared state withmethods. - For snapshot-enabled
Refstate, declareSnapshot.define(...)and usesnapshot: Snapshot.ref<Saved>(). - Add
import "./<agent-name>.js"tosrc/main.tsso the implementation registers. - Run
golem buildto type-check and build the component.
Durable Agent Example
import { Effect, Ref, Schema } from "effect";
import { defineAgent, method, Snapshot } from "@golemcloud/effect-golem";
const Item = Schema.Struct({
id: Schema.String,
name: Schema.String,
});
const RepositoryState = Schema.Struct({
items: Schema.Record(Schema.String, Item),
});
export const ItemRepositoryAgent = defineAgent({
name: "ItemRepositoryAgent",
mode: "durable",
id: {
repositoryName: Schema.String,
},
snapshotting: Snapshot.define({
schema: RepositoryState,
policy: Snapshot.policy.everyN(10),
}),
methods: {
createItem: method({
input: { item: Item },
success: Item,
}),
getItem: method({
input: { id: Schema.String },
success: Item,
}),
updateItem: method({
input: { item: Item },
success: Item,
}),
deleteItem: method({
input: { id: Schema.String },
success: Schema.Boolean,
}),
listItems: method({
input: {},
success: Schema.Array(Item),
}),
},
}).implement({
init: () => Ref.make({ items: {} as Record<string, typeof Item.Type> }),
methods: (state) => ({
createItem: ({ item }) =>
Ref.update(state, ({ items }) => ({
items: { ...items, [item.id]: item },
})).pipe(Effect.as(item)),
getItem: ({ id }) =>
Ref.get(state).pipe(
Effect.map(({ items }) => items[id]),
Effect.flatMap((item) =>
item === undefined
? Effect.die(new Error(`item not found: ${id}`))
: Effect.succeed(item),
),
),
updateItem: ({ item }) =>
Ref.update(state, ({ items }) => ({
items: { ...items, [item.id]: item },
})).pipe(Effect.as(item)),
deleteItem: ({ id }) =>
Ref.modify(state, ({ items }) => {
if (!(id in items)) return [false, { items }] as const;
const { [id]: _, ...remainingItems } = items;
return [true, { items: remainingItems }] as const;
}),
listItems: () =>
Ref.get(state).pipe(Effect.map(({ items }) => Object.values(items))),
}),
snapshot: Snapshot.ref<{ items: Record<string, typeof Item.Type> }>(),
});
Register the implementation from the component entry point:
// src/main.ts
import "./item-repository-agent.js";
Local imports use the emitted .js suffix because generated Effect projects use ESM and
NodeNext module resolution.
Method Contracts and Errors
input is a record of named method parameters. A method with one record parameter declares the
record schema as that parameter's value:
createItem: method({
input: { item: Item },
success: Item,
});
Expected domain failures belong in the Effect error channel and need a matching error schema:
const ItemNotFound = Schema.Struct({
_tag: Schema.Literal("ItemNotFound"),
id: Schema.String,
});
getItem: method({
input: { id: Schema.String },
success: Item,
error: ItemNotFound,
});
// In the implementation:
Effect.fail({ _tag: "ItemNotFound" as const, id });
Use defects such as Effect.dieMessage(...) only for unexpected failures that should fail and
retry the invocation. Do not use defects to represent normal business outcomes.
Key Constraints
- Import Effect APIs from
effectand Golem APIs from@golemcloud/effect-golem. - Use Effect Schema values for every agent id field, method parameter, success, and typed error.
- Constructor parameters define durable agent identity.
- Handlers return
Effectvalues; do not implement them as plainasyncfunctions. - Use
Snapshot.ref<Saved>()when a snapshottedRefcontains the saved schema value. - Keep snapshot values schema-serializable; do not put JavaScript
Map, functions, or services in snapshot state. - Agents are created on first invocation and process invocations sequentially.
- Import every implementation module from
src/main.tsfor side-effect registration. - Do not edit files under
golem-temp/.
Signals
- GitHub stars
- 2k
- Forks
- 211
- Last commit
- Sep 2026
Advanced
- Catalog kind
- skill
- Gateway key
golem-add-agent-effect- Source
- github.com/golemcloud/golem