# Subagents and personas

> Spawn and constrain child agents: agent types, personas, capability modes, isolation/worktree behavior, and headless Agent(...) denylist entries.

- Repository: xai-org/grok-build
- GitHub: https://github.com/xai-org/grok-build
- Human docs: https://grok-wiki.com/public/docs/xai-org-grok-build-90205de50458
- Complete Markdown: https://grok-wiki.com/public/docs/xai-org-grok-build-90205de50458/llms-full.txt

## Source Files

- `crates/codegen/xai-grok-pager/docs/user-guide/16-subagents.md`
- `crates/codegen/xai-grok-subagent-resolution/src/lib.rs`
- `crates/codegen/xai-grok-subagent-resolution/src/types.rs`
- `crates/codegen/xai-agent-lifecycle/src/lib.rs`
- `crates/codegen/xai-grok-agent/src`
- `crates/codegen/xai-grok-pager/docs/user-guide/14-headless-mode.md`

---

---
title: "Subagents and personas"
description: "Spawn and constrain child agents: agent types, personas, capability modes, isolation/worktree behavior, and headless Agent(...) denylist entries."
---

Grok Build spawns **subagents** as independent child sessions through the `task` / `spawn_subagent` tool (`TaskTool` in `xai-grok-tools`). Each child gets its own context window, a toolset from its agent type plus optional capability filtering, and an optional persona/role layer resolved by `xai-grok-subagent-resolution`. Nesting is hard-capped at depth 1 (`MAX_SUBAGENT_DEPTH = 1`): only the top-level session may spawn children. Subagents are enabled by default; disable with `GROK_SUBAGENTS=0` or `[subagents] enabled = false` in `config.toml`.

## Agents vs personas

| | **Agents** | **Personas** |
|---|---|---|
| **What they configure** | Whole session: model, tools, prompt mode, system prompt | Behavioral overlay on a subagent's prompt |
| **Scope** | Primary session or subagent | Subagents (roles/personas in config) |
| **How you set them** | Startup agent, or `.md` files under `.grok/agents/` (and compat paths) | `[subagents.personas]` in `config.toml` or `.toml` under `.grok/personas/` |
| **What they control** | Model, tool availability, prompt body, skills | Tone, output format, task focus, IO contracts |
| **Examples** | `general-purpose`, `explore`, `plan` | `researcher`, `concise` |

An agent defines the session itself. A persona shapes behavior within a child session. The spawn path always selects an agent type (`subagent_type`); resolution may layer a role and persona on top.

Manage both in the agents modal: `/config-agents` (alias `/agents`), or open Personas with `/personas`.

## Spawn surface: `task` / `spawn_subagent`

The model-facing tool is registered as `spawn_subagent` (Claude alias: `Agent` / `Task`). Input schema is `TaskToolInput` in `xai-tool-types`.

| Field | Type | Default | Notes |
| --- | --- | --- | --- |
| `prompt` | string | required | Full task for the child |
| `description` | string | required | Short label (3–5 words) |
| `subagent_type` | string | `general-purpose` | Built-ins: `general-purpose`, `explore`, `plan`; project agents may add names |
| `run_in_background` | bool | `true` | Return immediately with subagent ID; poll with `get_task_output` / `get_command_or_subagent_output` |
| `capability_mode` | enum | role default | `read-only` \| `read-write` \| `execute` \| `all` |
| `isolation` | enum | `none` | `none` \| `worktree` |
| `resume_from` | string | — | Continue a **completed** peer subagent by ID |
| `cwd` | string | parent cwd | Mutually exclusive with `isolation=worktree` when both would set a real directory |
| `model` | string | parent model | Soft-ignored when `resume_from` is set (source model is pinned) |

There is **no** model-facing `persona` parameter on `TaskToolInput`. Personas/roles apply through config resolution and harness overrides (`SubagentRuntimeOverrides.persona`), not as a free-form spawn argument from the parent model.

Background children survive parent-turn cancellation so results can be polled later. Blocking children report a summary back on the parent turn.

## Built-in agent types

`BuiltinAgentName::subagent_variants()` advertises three types to the Task tool:

| Type | Role |
| --- | --- |
| `general-purpose` | Default full-capability agent |
| `explore` | Codebase investigation; reads/searches/shell; no file edits by default toolset |
| `plan` | Architecture/implementation planning; same non-edit bias as explore |

Other built-ins (`grok-build`, `codex`, `opencode`, …) are top-level profiles resolvable by name but not listed as default subagent types.

### Discovery and shadowing

Agent definitions load from:

1. Project: `.grok/agents/`, `.claude/agents/` (walk cwd → repo root)
2. User: `~/.grok/agents/`, `~/.claude/agents/`
3. Bundled agents (lowest priority for non-built-in names)

Merge rules for the **callable subagent list**:

- Start with built-in `general-purpose` / `explore` / `plan`
- **Only project-level** agents may shadow a built-in name (e.g. project `.grok/agents/explore.md`)
- User-level or bundled files that reuse a built-in name are skipped so the visible list matches spawn resolution
- Spawn name lookup priority: **project > built-in > user > bundled**
- `[subagents.toggle]` can disable individual types

## Personas and roles

### Personas

A persona is a named behavioral overlay. Instructions are injected into the child conversation (persona/system-reminder layer) without changing the agent type or base tool catalog.

Define inline:

```toml
[subagents.personas.researcher]
instructions = "You are a thorough researcher. Always cite specific file paths."
description = "Deep investigator."
```

Or as one `.toml` file per persona. Discovery priority:

1. `.grok/personas/*.toml` (project)
2. `~/.grok/personas/*.toml` (user)
3. Bundled personas (lowest)

File stem = persona name. Inline `config.toml` personas win over files. Only `.toml` is discovered. Bundled personas are read-only in the UI; user/project personas are editable.

| Field | Purpose |
| --- | --- |
| `instructions` | Inline instruction text |
| `instructions_file` | Path loaded at spawn; merged after inline `instructions` |
| `description` | Catalog summary (else first paragraph of instructions) |
| `inputs` / `outputs` | Declared IO contract (`name`, `io_type` default `file`, `required`, `description`) |
| `model` | Model override when persona applies |
| `reasoning_effort` | Reasoning effort override |
| `default_isolation` | `none` or `worktree` |

Persona **file I/O** failures are fatal (spawn aborts). Missing persona name / empty instructions set `persona_error` without always short-circuiting other fields the same way. Role `prompt_file` load failures soft-degrade with a warning.

### Roles

Roles are named presets referenced as `subagent_type` (or config role keys):

```toml
[subagents.roles.researcher]
description = "Deep research agent"
default_capability_mode = "read-only"
model = "grok-build"
prompt_file = ".grok/prompts/researcher.md"
default_isolation = "none"
```

File discovery: `.grok/roles/*.toml` (and user-level counterparts). Inline config wins over files. Role prompts become a `<role-instructions>` block when `prompt_file` loads successfully.

### Effective override precedence

`resolve_effective_overrides` in `xai-grok-subagent-resolution` merges fields as:

1. Explicit spawn-time override (`SubagentRuntimeOverrides`)
2. Role default
3. Persona default
4. Parent inheritance / defaults downstream

Isolation uses the same cascade for the first three steps, then defaults to `SubagentIsolationMode::None` (shared workspace)—it does **not** inherit the parent's isolation mode.

## Capability modes

Optional coarse filter over tool **kinds** (`SubagentCapabilityMode::filter_tool_config`). Tools without a `kind` (for example many MCP tools built via bare IDs) are preserved. Mode `all` is a no-op filter.

| Mode | Read / search / web / LSP | File write/edit/delete/move | Shell execute | Notes |
| --- | --- | --- | --- | --- |
| `read-only` | Yes | No | No | Plan/enter-exit plan, memory get/search, skills, ask-user kept |
| `read-write` | Yes | Yes | No | Plus image/video gen kinds |
| `execute` | Yes | No | Yes | Shell/background bash kinds |
| `all` | Yes | Yes | Yes | Full set from agent definition |

Wire strings are kebab-case (`read-only`, `read-write`, `execute`, `all`) with common aliases accepted at parse time. If `capability_mode` is omitted, the child uses its agent type's toolset (and any role default).

After filtering, orphaned background-task tools (`get_task_output` / `kill_task`) are pruned when no Task tool or background-capable bash remains.

## Isolation: shared workspace vs worktree

| Mode | Behavior |
| --- | --- |
| `none` (default) | Child shares the parent workspace cwd |
| `worktree` | Child runs in an isolated git worktree; edits stay out of the parent tree until merged |

`cwd` and `isolation=worktree` are mutually exclusive when both would set a real directory. On `resume_from`, the child reuses the source's cwd/worktree (and may rehydrate from a completion snapshot ref if the worktree directory was removed). Completion output can include `worktree_path`. Worktree apply/merge is exposed through `x.ai/git/worktree/*` extension methods.

```text
Parent session (depth 0)
├── spawn_subagent ──► Child (depth 1)
│     tools: type + capability_mode
│     isolation: none | worktree
│     resume_from: optional peer ID
└── child cannot spawn further subagents
```

## Resume (`resume_from`)

Resume continues a **completed** peer in the same parent session:

- Inherits raw transcript, tool state, and model
- Re-renders system prompt / tools from the current agent definition
- Appends the new `prompt` as the next user message
- Requires matching `subagent_type`; persona must match if a persona is requested
- Model overrides on resume are soft-ignored (source model pinned)

Validation lives in `validate_resume_identity`. Invalid/sentinel IDs (`""`, `"null"`, `"none"`, `"undefined"`) are treated as absent.

## Depth limit

`SubagentDepthCounter` tracks nesting. When `depth >= MAX_SUBAGENT_DEPTH` (1), `task` fails with an invalid-arguments error: nested subagents cannot spawn further children. That keeps the tree flat (parent → children only).

## Configuration

```toml
[subagents]
enabled = true

[subagents.toggle]
explore = true
plan = false

[subagents.models]
explore = "grok-build"

[subagents.roles.researcher]
description = "Deep research agent"
default_capability_mode = "read-only"
model = "grok-build"
prompt_file = ".grok/prompts/researcher.md"

[subagents.personas.concise]
instructions = "Be concise. No filler words."
```

| Control | Effect |
| --- | --- |
| `GROK_SUBAGENTS=0` / `enabled = false` | Removes Task tool from the parent agent toolset |
| `[subagents.toggle]` | Disable specific types |
| `[subagents.models]` | Per-type model override (else inherit parent) |
| Roles / personas | Defaults for capability, model, isolation, prompts |

## Headless `Agent(...)` denylist

In headless mode (`-p` / `--single`, `--prompt-file`, `--prompt-json`), `--disallowed-tools` and `--tools` accept special **Agent** tokens (case-insensitive; `Task(...)` is an alias form in the same classifier):

| Entry | Effect |
| --- | --- |
| `Agent` | Block all subagent spawning (empty allowed type list; Task deps removed) |
| `Agent(explore)` | Deny the `explore` type |
| `Agent(explore, plan)` | Deny multiple types |

```bash
# No subagents at all
grok -p "Fix this bug" --disallowed-tools "Agent"

# Block only explore
grok -p "Refactor this module" --disallowed-tools "Agent(explore)"
```

Tokenizer keeps `Agent(a, b)` as a single token so commas inside parentheses do not split types. On agent definitions, the same grammar appears in frontmatter `tools` / `disallowedTools` and becomes `allowed_subagent_types`. Bare `Agent` deny forces an empty allow list and strips `task`, `get_task_output`, `kill_task`, and `wait_tasks`. When both allowlist and denylist apply, denylist wins for tool IDs; Agent type filtering intersects allow and deny type sets.

`--tools` / `--disallowed-tools` are headless-only flags (ignored with a warning in the interactive TUI).

## TUI surfaces

| Surface | Binding / action |
| --- | --- |
| Tasks pane | `Ctrl+B` — active/completed subagents and background commands |
| Todo pane | `Ctrl+T` |
| Agents modal | `Ctrl+P` → Manage Agents, or `/config-agents` / `/personas` |
| Parent scrollback | Lifecycle blocks: running / started / completed / failed / cancelled |
| Open child | Enter / Ctrl-F on a block, or from tasks pane — framed observational transcript |

Child views are largely observational (no normal top-level prompt like the parent). Close with `q`, Esc, or the frame close control.

## Operational constraints

- **Depth:** max 1; recursive spawn errors out
- **Background default:** `run_in_background` defaults to `true` on the tool schema
- **Cancellation:** background children outlive parent-turn cancel; foreground children tied to `parent_prompt_id` are cancelled with that turn
- **Provider neutrality:** agent definitions, personas, and roles are file/config portable; model IDs are free-form slugs (parent, role, persona, or explicit `model`), not tied to a single host provider
- **Good uses:** parallel research, tests, review of independent work
- **Poor uses:** trivial one-shot work, tight interactive user dialog, tasks where setup cost exceeds parallelism benefit

## Related pages

<CardGroup>
  <Card title="Headless mode" href="/headless-mode">
    `-p` runs, tool allow/deny lists, and `Agent(...)` denylist entries.
  </Card>
  <Card title="Permissions and safety" href="/permissions-and-safety">
    PreToolUse, allow/deny rules, and permission modes that still gate child tools.
  </Card>
  <Card title="Sandbox profiles" href="/sandbox">
    OS-level isolation for filesystem/network, orthogonal to subagent worktrees.
  </Card>
  <Card title="Plan mode" href="/plan-mode">
    Structured planning before edits; plan subagent type and enter/exit plan tools.
  </Card>
  <Card title="Configuration reference" href="/configuration-reference">
    `[subagents]` keys and related config.toml schema.
  </Card>
  <Card title="Sessions" href="/sessions">
    Session lifecycle, resume/continue, and persistence for parent and child IDs.
  </Card>
</CardGroup>
