Skip to content

Defining agents

How-to — turn a directory of files into a runnable agent.

An agent is a directory. No registration, no framework classes:

my-crew/
  agent.yaml            # identity + limits (see reference/agent-yaml.md)
  instructions.md       # the system prompt, plain markdown
  workflow.ts           # optional — how work fans out (see workflows guide)
  tools/                # optional — one defineTool() default export per file
  subagents/
    researcher/         # nested agent: own agent.yaml, instructions.md, tools/
    writer/

Scaffold one with toren init my-crew — the template runs offline on the mock provider.

Tools

ts
// tools/send-report.ts
import { defineTool } from "@toren/core";
import { z } from "zod";

export default defineTool({
  name: "send_report",
  description: "Email the finished report.",       // the model reads this — say when to use it
  input: z.object({ to: z.string(), body: z.string() }),
  effects: "external",      // recorded once; never re-executed on resume
  idempotency: "keyed",     // retries/resumes carry a stable idempotency key
  approval: "always",       // park the run until a human approves (or "never")
  handler: async ({ to, body }) => `sent to ${to}`,
});

The three durability attributes are the point: they tell toren what is safe to re-run, what must never run twice, and what needs a human. Mark anything side-effectful keyed.

Subagents

Each subagents/<ref>/ directory is a full agent (own model, prompt, tools). The workflow addresses them by directory name: ctx.task("researcher", input). Different subagents can use different providers — mock/echo for tests, anthropic/claude-opus-5 for production — routed per call by model prefix.

Declared env

Declare what your tools need; toren validates at startup and fails fast with the full list of what's missing — instead of a run dying mid-wave:

yaml
env:
  required: [SERP_API_KEY]
  optional: { REGION: "eu" }

Handlers receive the resolved values as ctx.env.SERP_API_KEY — never read raw process.env in a tool. Values come from your environment (locally .env; in AWS, Secrets Manager via agent_env_secret_arns) — toren never stores them. Never pass secrets in a run's input: inputs are recorded in the durable event log forever, by design.

Models

Set model: in each agent.yaml. mock/echo runs offline; anthropic/... needs ANTHROPIC_API_KEY in the environment. Toren calls providers directly — no gateway in the middle.