---
title: "AI Assistant subagents | Nutrient"
canonical_url: "https://www.nutrient.io/guides/ai-assistant/features/subagents/"
md_url: "https://www.nutrient.io/guides/ai-assistant/features/subagents.md"
last_updated: "2026-08-24T00:00:00.000Z"
description: "Learn how AI Assistant subagents let the main agent delegate a task to a named child agent with its own prompt, tools, approval policy, and model."
---

# Subagents

A subagent is a named, separately configured agent that the main agent can delegate a task to. Each subagent has its own system prompt, tools, and tool-approval policy, and it runs in isolation — the main agent sees only its final answer.

Use a subagent when part of a job needs a different set of instructions or a different tool surface than the main agent: a contract reviewer with a legal prompt and read-only access, a form filler restricted to a single Model Context Protocol (MCP) server, or a researcher that may only search.

## Overview

Subagents are configured with the `subagents` field. Each entry either defines an inline [agent configuration](https://www.nutrient.io/guides/ai-assistant/features/agent-configuration.md) with a `name` and a `description` or references a saved agent by its `agentId`:

```json

{
  "subagents": [
    {
      "name": "contract-reviewer",
      "description": "Reviews contracts for key terms, dates and liability clauses.",
      "systemPromptTemplate": "You are a contract specialist. Cite the clause number for every finding."
    }
  ]
}

```

Send the configuration in `context` with the agent run request:

```json

{
  "assistant_id": "agentic",
  "input": { "messages": [{ "role": "user", "content": "Review clause 4 of the lease." }] },
  "context": {
    "subagents": [{ "name": "contract-reviewer", "description": "Reviews contracts." }]
  }
}

```

The main agent uses each subagent’s `description` to choose the right specialist for a task. Make each description specific about what the subagent should handle.

## Configuration schema

```typescript

interface SubagentConfiguration {
  name: string                     // Required. 1–64 chars, /^[a-zA-Z0-9_-]+$/
  description: string              // Required. 1–500 chars. Shown to the main agent.

  systemPromptTemplate?: string    // The subagent's own instructions.
  seedMessages?: SeedMessages      // Messages injected on every model call.
  mcps?: MCPServerConfig[]         // The subagent's own MCP servers.
  skills?: Skill[]                 // The subagent's own skills.
  toolApproval?: ToolApproval      // The subagent's own approval policy.
  toolCalling?: "direct" | "code"  // The subagent's own tool-calling mode.
  responseSchema?: object          // JSON Schema for the subagent's answer.
  modelServices?: ModelServicesInput  // Run this subagent on a different model than the main agent.
}

interface SubagentReferenceConfiguration {
  agentId: string                  // Required. ID of the saved agent.
  name: string                     // Required. 1–64 chars, /^[a-zA-Z0-9_-]+$/
  description?: string             // Uses the saved agent's description when omitted.
}

type SubagentEntry = SubagentConfiguration | SubagentReferenceConfiguration

```

An inline subagent contains its configuration directly in the request. A reference instead loads a saved agent from the agent catalog:

```json

{
  "subagents": [
    {
      "agentId": "saved-contract-reviewer",
      "name": "contract-reviewer",
      "description": "Reviews contracts for key terms and liability clauses."
    }
  ]
}

```

Every reference requires a `name`. You can omit `description` when the saved agent already defines one. To change other fields, update the saved agent or define the subagent inline.

A subagent may declare its own `modelServices` to use a different model from the main agent. For example, a fast model can summarize pages, while a more capable model handles complex review. When `modelServices` is omitted, the subagent inherits the main agent’s model configuration.

An inline subagent can’t declare `subagents` of its own. However, a referenced saved agent may have its own saved `subagents`, allowing bounded delegation trees. For example, save `contract-team` with a reference to `clause-reviewer`:

```json

{
  "subagents": [
    {
      "agentId": "saved-clause-reviewer",
      "name": "clause-reviewer"
    }
  ]
}

```

The main agent can then reference `contract-team`:

```json

{
  "subagents": [
    {
      "agentId": "saved-contract-team",
      "name": "contract-team"
    }
  ]
}

```

This creates the delegation path `main agent` → `contract-team` → `clause-reviewer`. See [limits](#limits).

## Inheritance

A subagent inherits every field it doesn’t declare. A subagent that declares only a name, a description, and a prompt is the main agent with different instructions — same tools, same MCP servers, same approval policy, same model.

Referenced saved agents follow the same inheritance rules: their declared fields replace inherited values, while omitted fields come from the parent agent. Configure fields such as `toolApproval` explicitly when a saved agent needs a different policy.

```json

{
  "mcps": [{ "transport": "inmemory", "name": "nutrient-ai-assistant" }],
  "toolApproval": { "defaults": { "default": "allow", "write": "ask" } },
  "subagents": [
    {
      "name": "contract-reviewer",
      "description": "Reviews contracts.",
      "systemPromptTemplate": "You are a contract specialist."
    }
  ]
}

```

Here `contract-reviewer` gets the main agent’s `mcps` and its `toolApproval` — writes still require approval inside the subagent — and only the prompt differs.

Declaring a field replaces the inherited value; it doesn’t merge with it. A subagent that declares `mcps` gets only the servers it lists:

```json

{
  "mcps": [
    { "transport": "inmemory", "name": "nutrient-ai-assistant" },
    { "transport": "inmemory", "name": "document-engine" }
  ],
  "subagents": [
    {
      "name": "researcher",
      "description": "Searches documents. Cannot modify them.",
      "mcps": [{ "transport": "inmemory", "name": "nutrient-ai-assistant" }],
      "toolApproval": { "defaults": { "default": "deny", "read": "allow" } }
    }
  ]
}

```

`researcher` can reach only the `nutrient-ai-assistant` server, and only its read tools — regardless of what the main agent is allowed to do.

`nutrient-ai-assistant` and `document-engine` are Nutrient’s built-in MCP servers. List the built-in servers a subagent can use with the `inmemory` transport. To connect an external MCP server, use the `http` transport described in [MCP servers](https://www.nutrient.io/guides/ai-assistant/features/agent-configuration.md#mcp-servers).

`responseSchema` is an exception to inheritance. Declare it on the subagent when its answer must use structured output; otherwise, the subagent returns text.

## Delegation behavior

The main agent delegates tasks based on the available subagent names and descriptions. After a subagent finishes, the main agent uses its answer to continue the run and respond to the user.

Only the subagent’s final answer is returned to the main agent. Intermediate steps and tool calls aren’t streamed to the client.

## Tool approval inside a subagent

A subagent’s tools use its `toolApproval` configuration, inherited from the main agent, unless the subagent declares its own. The modes match the main agent’s [tool approval](https://www.nutrient.io/guides/ai-assistant/features/agent-configuration.md#tool-approval) modes:

- `allow` — The subagent’s tool runs automatically.

- `ask` — The run pauses and presents the approval through the main run.

- `deny` — The tool is never surfaced to the subagent’s model.

- `defer` — The tool is made available only when it’s relevant to the turn.

Because approval is inherited, a subagent that declares no policy of its own doesn’t escape the main agent’s policy:

```json

{
  "toolApproval": { "defaults": { "default": "allow", "write": "ask" } },
  "subagents": [{ "name": "form-filler", "description": "Fills form fields." }]
}

```

`form-filler` inherits `write: "ask"`, so a form-field write inside the subagent still pauses for approval.

To give a subagent a stricter policy than the main agent, declare one:

```json

{
  "toolApproval": { "defaults": { "default": "allow" } },
  "subagents": [
    {
      "name": "researcher",
      "description": "Read-only research.",
      "toolApproval": { "defaults": { "default": "deny", "read": "allow" } }
    }
  ]
}

```

## Examples

### A specialist with the same tools

Different instructions, everything else inherited. This is the most common shape.

```json

{
  "subagents": [
    {
      "name": "summarizer",
      "description": "Produces a one-paragraph summary of a document.",
      "systemPromptTemplate": "Summarize in one paragraph. No preamble, no bullet points."
    }
  ]
}

```

### A saved agent by reference

Reference an agent from the agent catalog instead of repeating its configuration inline:

```json

{
  "subagents": [
    {
      "agentId": "saved-contract-reviewer",
      "name": "contract-reviewer"
    }
  ]
}

```

Here, the main agent exposes the saved agent as `contract-reviewer`. Because the reference omits `description`, the saved agent must provide one.

### A subagent with restricted tools

Declare `mcps` and `toolApproval` to give a subagent a restricted tool set and policy:

```json

{
  "subagents": [
    {
      "name": "external-lookup",
      "description": "Looks up counterparties in the company registry.",
      "systemPromptTemplate": "Use the registry to resolve company names to registration numbers.",
      "mcps": [
        { "transport": "http", "name": "registry", "url": "https://registry.example.com/mcp" }
      ],
      "toolApproval": { "defaults": { "default": "deny", "read": "allow" } }
    }
  ]
}

```

### A cheap subagent alongside an expensive one

Each subagent declares its own `modelServices`, so a fast model handles routine summarization, while a stronger model handles complex review:

```json

{
  "subagents": [
    {
      "name": "summarizer",
      "description": "Produces a one-paragraph summary of a document section.",
      "systemPromptTemplate": "Summarize in one paragraph. No preamble, no bullet points.",
      "modelServices": {
        "models": [{ "labels": ["default-llm"], "model": "openai:gpt-4o-mini" }]
      }
    },
    {
      "name": "reviewer",
      "description": "Reviews contracts for liability exposure and non-standard terms.",
      "systemPromptTemplate": "You are a senior contract reviewer. Flag every non-standard clause with a risk rating.",
      "modelServices": {
        "models": [{ "labels": ["default-llm"], "model": "openai:gpt-4o" }]
      }
    }
  ]
}

```

### A subagent with structured output

Declare `responseSchema` on the subagent to require a structured answer instead of free text:

```json

{
  "subagents": [
    {
      "name": "clause-extractor",
      "description": "Extracts clause numbers and their risk level.",
      "responseSchema": {
        "type": "object",
        "properties": {
          "clauses": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "number": { "type": "string" },
                "risk": { "type": "string", "enum": ["low", "medium", "high"] }
              },
              "required": ["number", "risk"]
            }
          }
        },
        "required": ["clauses"]
      }
    }
  ]
}

```

## Limits

- Subagent names must be unique within the configuration. Don’t use the reserved name `discover_tools`.

- An inline subagent can’t set `modelOverrides` or `userId`.

- An inline subagent can’t declare `subagents`.

- A referenced saved agent may contain its own `subagents`. References can be nested up to five levels, with up to 64 subagents in a run. Circular references aren’t supported.

- `toolCalling: "code"` can’t be combined with `subagents`.

- A subagent that uses `toolCalling: "code"` can’t use `ask` or `defer` tool approval.

- Only the subagent’s final answer is available to the main agent and client.

- A subagent is part of the main agent’s run and can’t be resumed independently.

`toolCalling: "code"` and `subagents` are mutually exclusive. A configuration that sets both is rejected at startup.

## What’s next

- [Agents](https://www.nutrient.io/guides/ai-assistant/features/agents.md) — Choose the built-in agent the subagents delegate from.

- [Agent configuration](https://www.nutrient.io/guides/ai-assistant/features/agent-configuration.md) — Configure the shared fields a subagent inherits or overrides.
---

## Related pages

- [Agent configuration](/guides/ai-assistant/features/agent-configuration.md)
- [Agents](/guides/ai-assistant/features/agents.md)
- [AI text comparison](/guides/ai-assistant/features/ai-text-comparison.md)

