# Agent (/docs/build/agent)



```ts title="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](/docs/build/instructions).
* `.tools()` adds typed functions that run in your process. See [Tools](/docs/build/tools).

Do not set a model on the agent. The Tenant's model settings choose it; see
[Models](/docs/run/models). Give a session a sandbox when you open it; see
[Sandboxes](/docs/run/sandboxes).

## The builder's rules [#the-builders-rules]

* **One method per thing.** Every capability has its own method.
* **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()` fails 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 is on [Build](/docs/build). Add only what this agent uses.

## Hooks [#hooks]

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

`.beforeTurn()`, `.beforeModel()`, `.afterModel()`, `.afterTurn()`, `Patch` /
`Decision` / `TurnDecision`, and retry bounds are on [Hooks](/docs/build/hooks).

## Capabilities [#capabilities]

```ts
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);
```

Ordering, ownership, and catalog rows are on [Capabilities](/docs/build/capabilities).

## MCP, skills, plugins [#mcp-skills-plugins]

```ts
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" },
  })
  .skills("./assistant-skills")
  .plugin("./plugins/github");
```

Stdio MCP servers from plugins must live under the Tenant's `plugins/`
directory. See [MCP](/docs/build/mcp), [Skills](/docs/build/skills), and
[Plugins](/docs/build/plugins).

`.skills()` and `.plugin()` read files, so they are on the `Agent` from
`@nylorun/agents`. `@nylorun/agents/define` exports the same builder without
them.

## Subagents and flows [#subagents-and-flows]

```ts
const researcher = Agent({
  id: "researcher",
  description: "Investigates an order's history.",
})
  .instructions("Investigate one question about one order.")
  .tools(searchOrders);

export const assistant = Agent({ id: "assistant" })
  .instructions("Delegate research that needs more than two lookups.")
  .tools(lookupOrder)
  .subagents(researcher);
```

Limits and `delegation.*` events are on [Subagents](/docs/build/subagents).
Stages and `flow()` are on [Flow agents](/docs/build/flows).

## Details [#details]

`.build()` returns the assembled agent. Generated projects call `.build()` so
the registry holds a built agent. Invalid tool schemas or duplicate tool names
raise `AgentBuildError` with one diagnostic per problem.

* `description` is required when this agent is used as a subagent.
* `.output(schema)` validates the completed output and types it.
* `JSON.stringify(agent)` is the public manifest: `manifestSchemaVersion: 4`
  for a ReAct agent, a workflow manifest (`workflowSchemaVersion: 2`) for a flow
  agent.

<Callout title="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, or HTTP routing in an agent manifest.
</Callout>

Older option-form constructors and hook names are listed on
[Compatibility](/docs/compatibility#breaking-changes).

## Next step [#next-step]

<Cards>
  <Card title="Tools" description="Give the agent a typed function it can call." href="/docs/build/tools" />

  <Card title="Call it from code" description="Create a session and send input." href="/docs/run/sessions" />
</Cards>
