Documentation menu

Getting started

Build a composable agent with the Efferent SDK and its first-party plugins.

Efferent

Compose the agent. Own the harness.

An Effect-native agent framework for Node 24 and Bun. The model, agent loop, memory, sessions, tool discovery, background tasks and rendering are configurable plugins. The SDK composes them into one validated graph.

Install

Install the SDK and the plugins your application uses:

npm install @xandreed/sdk @xandreed/plugin-agent-loop @xandreed/plugin-models @xandreed/plugin-sessions

All framework packages are published at 0.14.0 under npm’s latest tag. @xandreed/plugin-models needs Node 24.5 or newer.

Compose

import { Context, Effect, Layer, Option } from "effect"
import { LanguageModel } from "effect/ai"
import { Sessions, SessionLogMemoryLive, TurnAdmissionOpen, UserMessage } from "@xandreed/core"
import { Agent } from "@xandreed/sdk"
import { stepLoopPlugin } from "@xandreed/plugin-agent-loop"
import { memoryWindowPlugin } from "@xandreed/plugin-memory-window"
import { toolDiscoveryPlugin } from "@xandreed/plugin-tool-discovery"
import { SessionsPluginLive } from "@xandreed/plugin-sessions"

declare const model: LanguageModel.LanguageModel // from @xandreed/plugin-models or any effect/ai provider

const reply = Effect.scoped(Effect.gen(function* () {
  const sessions = Context.get(yield* Layer.build(SessionsPluginLive({ ownership: { mode: "process" } }).pipe(
    Layer.provide(Layer.merge(SessionLogMemoryLive, TurnAdmissionOpen)),
  )), Sessions)
  const agent = yield* Agent.define({
    plugins: [{ plugin: memoryWindowPlugin, options: { digestOnWriteChars: 4_000 } }, toolDiscoveryPlugin, stepLoopPlugin],
    turnServices: [LanguageModel.LanguageModel],
    system: "You are a helpful assistant.",
  })
  const view = yield* sessions.create({ owner: "user-1" })
  const outcome = yield* agent.turn({
    turn: { session: { id: view.header.id, owner: "user-1" }, userMessage: new UserMessage({ text: "Hello" }), runId: crypto.randomUUID() },
    services: Context.merge(Context.make(LanguageModel.LanguageModel, model), Context.make(Sessions, sessions)),
  }, (turn) => turn.run({}).pipe(Effect.map((result) => ({ outcome: result.outcome, reply: Option.some(result.text) }))))
  return outcome.reply
}))

A plugin declares an Effect Schema, defaults, required/provided service tags, and a scoped Layer. The runtime rejects invalid options, missing dependencies, cycles, ambiguous providers, and incompatible plugin API versions before use. Override a service through an explicit binding.

SessionLogMemoryLive keeps sessions in memory and runs anywhere; SessionLogSqliteLive(path) from @xandreed/plugin-session-sqlite stores them in a SQLite file on Bun, and any other store can implement the SessionLog port.

Configuration

Plugins are configured where the agent is defined: an entry in Agent.define({ plugins }) is a plugin, or { plugin, id?, options }. Options merge over the plugin’s defaults and decode through its schema; undeclared keys are refused. The plugin reference lists every first-party plugin with its defaults and configuration schema, and plugin configuration shows how to point the models plugin at any OpenAI-compatible endpoint.

Packages

PackageResponsibility
@xandreed/coreShared schemas, ports, messages and protocol helpers
@xandreed/runtimePlugin graph validation and scoped activation
@xandreed/sdkAgent.define and Agent.turn: the agent’s plugin graph and its turns, over durable sessions
@xandreed/plugin-agent-loopThe agent step loop
@xandreed/plugin-modelsModel routing and provider adapters
@xandreed/plugin-memory-window, -memory-summary, -memory-digestConversation memory strategies and tool-result digests
@xandreed/plugin-tool-discoveryTool and skill discovery
@xandreed/plugin-sessionsConversation sessions and the turn lifecycle
@xandreed/plugin-session-sqliteSQLite session store (Bun)
@xandreed/plugin-tasksBackground tasks
@xandreed/plugin-renderRender surfaces, event feeds and streaming
@xandreed/plugin-workspaceThe local file system and shell as FileSystem and Bash (localSystemPlugin), the workspace tools read, write, edit, ls, find, grep and bash (workspaceToolsPlugin), and skills from directories of SKILL.md files (skillsDirectoryPlugin); Linux and macOS
@xandreed/plugin-telemetryUsage, cost and tool metrics per turn and OTLP/HTTP export of traces and metrics (observability)
@xandreed/evals, -evals-cli, -evals-langfuse, -evals-langsmithTasks, trials, graders and suites; the efferent-eval CLI; exporters (Node 24)

Build and verify

bun install
bun run typecheck
bun test
bun run foundry demo
bun run build:packages
bun run verify:packages
bun run --cwd packages/website check

The distribution build prepares artifacts under .artifacts/ using each package’s manifest version and matching internal dependency versions. The consumer check installs local tarballs outside the monorepo, runs a composable agent’s turn, a session fork and an eval composition on Bun, imports every Node-capable package on Node, runs the FileSystem and Bash kits over the local adapters of @xandreed/plugin-workspace, loads a SKILL.md tree through the packed skills directory plugin, and runs an agent turn that reads, edits and runs a command through the workspace tools, and exports a turn’s span and usage metric through @xandreed/plugin-telemetry to a local OTLP collector, on both.

See the framework guide and the source and contributing guide.

MIT · Xand Reed