What is Effect Agent?
Effect Agent is an interpreter for autonomous agents inside Effect applications. An Agent is an immutable, Schema-defined value; pair it with an Effect AI Model and the runtime interprets it as an Effect result or a semantic Stream. Failures remain typed in E, dependencies remain visible in R, and every resource remains owned by a Scope. This page shows one complete Agent, explains what the framework adds on top of Effect AI, and names the three persistence levels it supports.
One Agent, end to end
An Effect Agent combines Schema-defined input and output, native Effect AI Tools, an explicit Model binding, and application Layers. AgentRuntime.run interprets that binding as a scoped Effect program.
import { OpenAiClient, OpenAiLanguageModel } from "@effect/ai-openai";
import { Agent, AgentPolicy, IdGenerator } from "@effect-agent/core";
import { AgentRuntime } from "@effect-agent/engine";
import { Config, Effect, Layer, Schema } from "effect";
import { Tool, Toolkit } from "effect/unstable/ai";
import { FetchHttpClient } from "effect/unstable/http";
// 1. Describe what enters and leaves the Agent.
const Question = Schema.Struct({ question: Schema.String });
const Answer = Schema.Struct({ answer: Schema.Number });
// 2. Define a native Effect AI Tool and its handler Layer.
const Add = Tool.make("add", {
description: "Add two numbers exactly.",
parameters: Schema.Struct({ left: Schema.Number, right: Schema.Number }),
success: Schema.Struct({ total: Schema.Number }),
});
const Calculator = Toolkit.make(Add);
const CalculatorLive = Calculator.toLayer({
add: ({ left, right }) => Effect.succeed({ total: left + right }),
});
// 3. Define finite autonomous behavior, then bind exactly one Model.
const Definition = Agent.define("calculator", {
input: Question,
output: Answer,
instructions: ({ question }) =>
`Use the calculator Tool to answer: ${question}. Return {"answer": number}.`,
toolkit: Calculator,
policy: AgentPolicy.make({
maxTurns: 3,
maxToolCalls: 2,
maxDuration: "30 seconds",
toolConcurrency: 1,
}),
});
const CalculatorAgent = Agent.withModel(Definition, OpenAiLanguageModel.model("gpt-4.1-mini"));
// 4. Build the application's Effect environment.
const OpenAiLive = OpenAiClient.layerConfig({
apiKey: Config.redacted("OPENAI_API_KEY"),
}).pipe(Layer.provide(FetchHttpClient.layer));
const AppLive = Layer.mergeAll(CalculatorLive, IdGenerator.layer, OpenAiLive);
// 5. The Agent is still an Effect until the application entrypoint runs it.
const program = AgentRuntime.run(CalculatorAgent, {
question: "What is 20 + 22?",
}).pipe(
Effect.tap((result) => Effect.logInfo("answer", result.output)),
Effect.provide(AppLive),
Effect.scoped,
);
void Effect.runPromise(program);2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
Definition contains the immutable Agent configuration. CalculatorLive supplies Tool behavior, CalculatorAgent fixes the Model selection, and AppLive provides the runtime dependencies. IdGenerator.layer is the framework's default Web Crypto identity authority; the testing guide replaces it with deterministic IDs. The result remains an Effect until the application entrypoint executes it:
AgentRuntime.run(agent, input);
// Effect<AgentResult<Output>, AgentFailure | DomainFailure, Requirements | Scope>
AgentRuntime.stream(agent, input);
// Stream<RunEvent, AgentFailure | DomainFailure, Requirements>2
3
4
5
That signature is more than API styling. It means:
- success is Schema-decoded rather than trusted because a model emitted JSON;
- expected AI, Tool, and application failures remain visible in
E; - Models, Tool handlers, domain services, clocks, and stores remain visible in
R; - interruption closes the Run Scope and finalizes everything it owns.
The missing layer
Effect AI already owns Models, Language Models, Prompts, Responses, Tools, Toolkits, approval parts, and provider Layers. Effect Agent uses those values directly.
It adds only the concepts needed to interpret autonomous work:
| Effect AI owns | Effect Agent adds |
|---|---|
Model, LanguageModel | Agent Definition and explicit Binding |
Tool, Toolkit | bounded Tool-batch scheduling |
Prompt, Response | multi-Turn state machine |
| provider Layers | Run, Conversation, Submission, Settlement |
| response streams | stable semantic RunEvent stream |
There is no framework provider registry, second Tool type, callback middleware runtime, or Promise-first facade.
Three levels of persistence
The runtime makes three distinct claims, and keeping them separate is deliberate. All three are implemented and tested.
Ephemeral execution. A Run executes now, inside one Scope. It supports bounded model Turns, Tool Calls, interruption, semantic events, steering, follow-up, approval, budgets, context management, MCP, and a local sandbox adapter. If the process disappears, active work disappears with it.
Persistent Conversations. Canonical Conversation records survive restart through memory or SQLite adapters. History can be replayed, projected, exported, checkpointed, and observed from an opaque offset. Persistence does not mean the runtime has accepted an obligation to finish active work.
Durable accepted work. The durable runtime first commits a Submission obligation, then returns a Receipt. Attempts may be replaced after a crash, but exactly one terminal Settlement is eventually recorded. Unresolved external Tool effects stop at an explicit Unknown Outcome instead of replaying, and the same contract runs on Node/SQLite and on Cloudflare Durable Objects. No level claims exactly-once external side effects. See Persistence & durability.
What the framework optimizes for
Effect Agent is designed for Effect application teams that want autonomous behavior without adopting a second application runtime. It is especially opinionated about:
- retaining typed domain failures and service requirements;
- replacing live integrations with deterministic Layers in tests;
- bounding autonomy by default;
- preserving one canonical, replayable history;
- refusing to label ambiguous external effects "exactly once."
It is not a hosted control plane, visual builder, turnkey chat product, generic workflow engine, or secure remote code sandbox. The project is pre-1.0: packages are private, Effect v4 is pinned to a beta release, and there is no compatibility window yet.
Next steps
- Getting started shows how to build a Definition and Binding.
- Effect-native by construction explains how the architecture keeps these properties.