NylorunDocsBeta
Get startedBuildRunDeployReferenceMore
BuildAgents

Agent

Define an agent with instructions and a tool, then add only the capabilities it needs.

An agent is a definition: an id, instructions, and the tools the model may call. You build it with one chained builder, export it from agents/index.ts, and the Runtime picks the model.

agents/assistant/agent.ts
import { Agent, tool } from "@nylorun/agents";
import { z } from "zod";

const lookupOrder = tool({
  name: "lookup_order",
  description: "Look up a sample order by ID. Try demo-123.",
  input: z.object({ orderId: z.string() }),
  output: z.object({ orderId: z.string(), status: z.string() }),
  async run({ orderId }) {
    return { orderId, status: orderId === "demo-123" ? "shipped" : "not found" };
  },
});

export const assistant = Agent({ id: "assistant", name: "Order assistant" })
  .instructions("Help with orders. Always use lookup_order for order questions.")
  .tools(lookupOrder)
  .build();
  • Agent({ id, name?, description?, metadata? }) takes identity only. id is the stable identifier sessions use; name is the label Studio shows.
  • .instructions() tells the model what to do. See Instructions.
  • .tools() adds typed functions that run in your process. See Tools.

Do not set a model on the agent. The Tenant's model settings choose it; see Models.

The builder's rules

  • One method per thing. Every capability has its own method; there is no generic .use().
  • List methods accumulate. .instructions(), .tools(), .subagents(), .mcp(), .skills(), .plugin() and .capability() add to what is there, and each takes several items at once: .tools(lookupOrder, refundOrder).
  • Single values are set once. .output() and .sandbox() fail the build with agent.single-value when called twice.
  • Every call returns a new builder. The original is unchanged, so a shared base agent can be extended in several ways.

The capability map — every authoring method and compose pattern — is on Build overview. Add only what this agent uses.

Hooks

Patch a turn or decide after a model call:

export const assistant = Agent({ id: "assistant", name: "Order assistant" })
  .instructions("Help with orders.")
  .tools(lookupOrder)
  .beforeTurn(({ info }) => ({
    instructions: [`Tenant ${info?.tenantId ?? "unknown"}`],
  }))
  .build();

.beforeTurn(), .beforeModel(), .afterModel(), .afterTurn(), Patch / Decision / TurnDecision, and retry bounds are on Hooks.

Capabilities

Bundle instructions, tools, and hooks, then attach them with .capability():

import { Agent, capability } from "@nylorun/agents";

const support = capability({ id: "support" })
  .instructions("Ask for an order number before using find_order.")
  .tools(findOrder);

export const assistant = Agent({ id: "assistant", name: "Order assistant" }).capability(support);

A capability has the same methods as a ReAct agent. Ordering, ownership, and catalog rows are on Capabilities.

MCP

Declare MCP servers the Runtime discovers:

export const assistant = Agent({ id: "assistant", name: "Order assistant" })
  .instructions("Use the available tools.")
  .mcp({
    github: { type: "streamable-http", url: "https://mcp.example.com/github" },
  });

A server's name defaults to its key. Transports, snapshots, and McpError are on MCP.

Sandbox

Give the agent Runtime-executed computer tools:

export const analyst = Agent({ id: "analyst" })
  .instructions("Analyse the data the user gives you. Use Python.")
  .sandbox();

Images, network presets, backends, idle, and sandbox.* events are on Sandbox.

Skills

Load an Agent Skills catalog folder:

export const assistant = Agent({ id: "assistant", name: "Order assistant" })
  .tools(lookupOrder)
  .skills("./assistant-skills");

Folder layout, the agentskills.io spec, load_skill / read_skill_resource, and build-copy are on Skills.

Agent Plugins

Attach an Agent Plugin package as one capability:

export const assistant = Agent({ id: "assistant", name: "Order assistant" })
  .instructions("Use the plugin tools and skills.")
  .plugin("./plugins/github");

loadPlugin, diagnostics, pluginRoot, and plugin MCP/skills are on Plugins.

.skills() and .plugin() read files, so they are on the Agent from @nylorun/agents. @nylorun/agents/define exports the same builder without them, for code that must run anywhere.

Subagents

Add an agent with .subagents() so the model can delegate a self-contained task:

const researcher = Agent({
  id: "researcher",
  description: "Investigates an order's history. Returns a short summary with the ids it relied on.",
})
  .instructions("Investigate one question about one order.")
  .tools(searchOrders, readTicket);

export const assistant = Agent({ id: "assistant" })
  .instructions(
    "For anything needing more than two lookups, delegate to researcher with a complete, self-contained task.",
  )
  .tools(lookupOrder)
  .subagents(researcher);

{ task: string }, required description, flow agents as subagents, ctx.agent, history({ agent }), delegation.* events, and limits are on Subagents.

Flow agents

Chain stages on the same builder when your code, not the model, decides what runs next:

import { Agent, flow } from "@nylorun/agents";

export const issueDesk = Agent({ id: "issue-desk" })
  .step(triage)
  .switch(
    {
      bug: flow().loop(fixer, { verify: tester, max: 3 }),
      docs: docsWriter,
      default: general,
    },
    { on: ({ input }) => input.kind, id: "route" },
  )
  .parallel({ security: securityReviewer, style: styleReviewer }, { id: "reviews" })
  .step(openPr, { input: ({ results }) => ({ title: results.triage.summary }) });

Every stage is .stage(whatRuns, { how }), and every stage function receives { input, results, flowInput }. See Flow agents.

Details

.build() returns the assembled agent. You can export the builder; generated projects call .build() so the registry holds a built agent. Invalid tool schemas, duplicate tool names, or other incompatible contributions raise AgentBuildError with one diagnostic per problem.

  • description is optional catalog metadata. It is required when this agent is used as a subagent; see Subagents.
  • .output(schema) validates the agent's completed output and types it.
  • .instructions() and .tools() on the agent compile as capability id "agent".
  • JSON.stringify(agent) is the public manifest: manifestSchemaVersion: 4 for a ReAct agent, a workflow manifest (workflowSchemaVersion: 2) for a flow agent. Bindings stay local; getBinding() is not a wire format. Agent.from(manifest, implementations) reconstructs either kind.

Keep runtime concerns outside the agent

Construct service clients in the application and close over them from tools. Do not put API keys, database handles, HTTP routing, or deployment policy in an agent manifest.

Earlier syntax

The options form and .use() still work for one minor release and print a DeprecationWarning once per code. They compile to the same manifest.

BeforeNowWarning code
Agent({ id, instructions, tools, outputSchema })Agent({ id }).instructions(…).tools(…).output(…)NYLORUN_DEP_AGENT_OPTIONS
agents inside tools: [...].subagents(agent)—
.use(mcp(…)), .use(sandbox()).mcp(…), .sandbox()NYLORUN_DEP_USE
.use(skills(dir)), .use(plugin(dir)).skills(dir), .plugin(dir)NYLORUN_DEP_USE
.use(capability({ id, instructions, tools })).capability(capability({ id }).instructions(…).tools(…))NYLORUN_DEP_USE, NYLORUN_DEP_CAPABILITY_OPTIONS
.before("turn"|"step", fn).beforeTurn(fn) · .beforeModel(fn)NYLORUN_DEP_HOOKS
.after("step"|"turn", fn).afterModel(fn) · .afterTurn(fn)NYLORUN_DEP_HOOKS
Chain, Switch, Parallel, Map, LoopFlow agents: Agent({ id }).step(…)—

Full signatures are in Reference → define.

Next step

On this page