Skip to content

Usage overview

High level overview of the Durable Agents system and developer APIs.

1. Entity definition (registry.define())

Agents are entities that handle events, defined as a:

And schemas:

  • creationSchema -- validated spawn args
  • inboxSchemas -- typed message contracts
  • outputSchemas -- what the entity emits (for UI binding)

See Defining entities and EntityDefinition reference.

2. Handler context (ctx)

The context API passed into the handler:

Property/MethodPurpose
ctx.firstWakeBoolean -- is this the entity's first activation?
ctx.entityUrlIdentity -- /type/id
ctx.entityTypeType name string
ctx.argsReadonly spawn arguments
ctx.tagsEntity tags -- key/value metadata
ctx.dbFull TanStack DB: db.actions for writes, db.collections for reads
ctx.stateProxy object keyed by collection name
ctx.eventsChange events that triggered this wake
ctx.useAgent()Set up the LLM agent
ctx.useContext()Declare context sources with token budgets and cache tiers
ctx.timelineMessages()Project the entity timeline into LLM messages
ctx.insertContext(id, entry)Insert a durable context entry
ctx.agent.run()Execute the agent loop
ctx.darixToolsRuntime-provided tools to spread into agent config
ctx.spawn(type, id, args, opts)Create child entity
ctx.observe(source, opts)Subscribe to a source via entity(), cron(), entities(), db()
ctx.send(url, payload, opts)Send message to an entity
ctx.sleep()Return to idle
ctx.mkdb(id, schema)Create cross-entity shared state
ctx.observe(db(id, schema), opts)Join existing shared state
ctx.setTag(key, value)Set a tag on this entity
ctx.removeTag(key)Remove a tag from this entity

See Writing handlers and HandlerContext reference.

3. Agent configuration

ts
ctx.useAgent({
  systemPrompt: string,
  model: string,           // e.g. 'claude-sonnet-4-5-20250929'
  tools: AgentTool[],      // [...ctx.darixTools, ...custom]
  streamFn?: StreamFn,     // optional streaming callback
  testResponses?: string[] // for testing without LLM
})
await ctx.agent.run()      // blocks until agent finishes

See Configuring the agent and AgentConfig reference.

4. Tool definition

Stateless tools are pure functions:

ts
const myTool: AgentTool = {
  name: "calculator",
  description: "...",
  parameters: Type.Object({ expression: Type.String() }), // TypeBox
  execute: async (toolCallId, params) => ({
    content: [{ type: "text", text: result }],
    details: {},
  }),
}

Stateful tools are factories receiving ctx for state access:

ts
function createMemoryTool(ctx: HandlerContext): AgentTool {
  return {
    name: "memory_store",
    execute: async (_, params) => {
      ctx.db.actions.memory_insert({ row: { key, value } }) // writes to entity state
    },
  }
}

Handler-scoped tools are factories receiving ctx:

ts
function createDispatchTool(ctx: HandlerContext): AgentTool {
  return {
    execute: async (_, params) => {
      const child = await ctx.spawn("worker", id, args, { wake: "runFinished" })
      const text = await child.text()
      return { content: [{ type: "text", text }] }
    },
  }
}

See Defining tools and AgentTool reference.

5. State collections (ctx.db)

Custom state is accessed through ctx.db:

Writes via ctx.db.actions:

  • .<name>_insert({ row }) -- add new row
  • .<name>_update({ key, updater: (draft) => { ... } }) -- Immer-style mutation
  • .<name>_delete({ key }) -- remove by primary key

Reads via ctx.db.collections:

  • .<name>?.get(key) -- read one
  • .<name>?.toArray -- read all (getter, not method)

See Managing state.

6. Entity coordination primitives

  • spawn(type, id, args, opts) -> EntityHandle -- create child
    • opts.initialMessage -- first message to deliver
    • opts.wake -- 'runFinished', { on: 'runFinished', includeResponse? }, or { on: 'change', collections?, debounceMs?, timeoutMs? }
  • observe(source, opts) -> EntityHandle | ObservationHandle -- subscribe via entity(), cron(), entities(), db()
  • send(url, payload, opts) -- fire-and-forget message
  • sleep() -- go idle

EntityHandle returned from spawn/observe:

  • .entityUrl, .type, .db (read-only TanStack DB)
  • .run -- Promise that resolves when child completes
  • .text() -- get all completed text output
  • .send(msg) -- send follow-up message
  • .status() -- ChildStatus | undefined (object with .status, .entity_url, .entity_type)

See Spawning & coordinating and EntityHandle reference.

7. Shared state (cross-entity)

Define a schema map, then create/connect:

ts
const schema = {
  findings: {
    schema: z.object({ key: z.string(), text: z.string() }),
    type: "shared:finding",
    primaryKey: "key",
  },
}
// Parent creates:
ctx.mkdb("research-123", schema)
// Children connect:
const shared = await ctx.observe(db("research-123", schema))
shared.findings.insert({ key: "f1", text: "..." })

See Shared state and SharedStateHandle reference.

8. Built-in collections

Every entity automatically has 17 ctx.db.collections:

CollectionPurposeKey fields
runsAgent run lifecyclestatus: started/completed/failed
stepsLLM call stepsstep_number, model_id, duration_ms
textsText message blocksstatus: streaming/completed
textDeltasIncremental text chunkstext_id, delta
toolCallsTool invocation lifecycletool_name, status, args, result
reasoningExtended thinking blocksstatus: streaming/completed
errorsDiagnostic errorserror_code, message
inboxReceived messagesfrom, payload, message_type
wakesWake event historysource, timeout, changes
entityCreatedBootstrap metadataentity_type, args, parent_url
entityStoppedShutdown signaltimestamp, reason
childStatusChild entity statusentity_url, status
manifestsWiring declarationsdiscriminated union: child/source/shared-state/effect/context/schedule
replayWatermarksReplay offset trackingsource_id, offset
tagsEntity tags/labelskey, value
contextInsertedContext additionscontext_id, content
contextRemovedContext removalscontext_id

See Built-in collections.

9. CLI (darix)

Interact with the system using the darix CLI:

CommandPurpose
darix typesList registered entity types
darix types inspect <name>Show type schema
darix spawn /type/id --args '{...}'Create entity
darix send /type/id 'message'Send message
darix observe /type/idStream entity events
darix inspect /type/idShow entity state
darix ps [--type --status --parent]List entities
darix kill /type/idStop entity

See CLI reference.

10. App setup

ts
const registry = createEntityRegistry()
registerMyEntity(registry)

const runtime = createRuntimeHandler({
  baseUrl: DARIX_URL, // runtime server
  serveEndpoint: `${URL}/webhook`, // callback URL
  registry,
})

// Node HTTP server, forward POST /webhook -> runtime.onEnter(req, res)
await runtime.registerTypes() // register all types with runtime server

See App setup and RuntimeHandler reference.