> ## Documentation Index
> Fetch the complete documentation index at: https://docs.karta.sh/llms.txt
> Use this file to discover all available pages before exploring further.

# Sub-agents

> Harness-native sub-agents defined inside one agent project, discovered automatically, routed and handed off at runtime.

A **sub-agent** is an optional harness-native role inside one agent project.
For Claude Code, it is usually a `.claude/agents/*.md` file; for OpenCode, it
is the equivalent `.opencode/agents/*.md` file. Karta discovers those files and
lets sessions route to them, but it does not deploy them as separate top-level
agents with their own stable URLs.

## Where sub-agents come from

| Harness     | Agent files             | Shared context               |
| ----------- | ----------------------- | ---------------------------- |
| Claude Code | `.claude/agents/*.md`   | `CLAUDE.md` (or `AGENTS.md`) |
| OpenCode    | `.opencode/agents/*.md` | `AGENTS.md`                  |

Each sub-agent is a Markdown file with YAML frontmatter and a prompt body:

```markdown .claude/agents/billing.md theme={null}
---
name: billing-specialist
description: Handles invoice and billing questions
model: claude-sonnet-4-6        # optional
temperature: 0.3                 # optional
tools:                           # optional
  read: true
  write: false
permissions:                     # optional
  skill:
    billing-lookup: allow
type: primary                    # primary | auxiliary
---

You are a billing specialist. Help customers with invoices and charges.
Be precise, cite invoice numbers, and never guess at amounts.
```

The discovered definition exposes `name`, `description`, `prompt`,
optional `model`, `tools`, `skills`, `permissions`, `temperature`, and `type`.
With a single sub-agent, it is selected automatically; with several, you route
by name.

## Routing

Send a turn to a named sub-agent, or let the default handle it. The API field is
still named `agent` because it names the harness actor for that turn:

```python theme={null}
from karta import Karta

app = Karta()

app.agents                 # {"billing-specialist": Agent, "shipping": Agent, ...}
app.default_agent          # the fallback when none is specified

# Route a one-off message to a sub-agent:
response = app.send_sync("Audit my last invoice", agent="billing-specialist")
```

## Handoff within a session

A session has a *current sub-agent*. Reassign it to hand off
mid-conversation; the change fires an `agent.handoff`
[hook](/sdks/python/hooks-and-policies).

```python theme={null}
session = app.session(metadata={"customer_id": "abc123"})
session.send_sync("I have a question about my order")   # -> default agent
session.current_agent = app.agents["billing-specialist"] # handoff
session.send_sync("Was invoice #789 charged twice?")    # -> billing specialist
```

This is how a general intake agent can hand a thread to a specialist without
losing context. The [session](/concepts/sessions-and-participants) and its
history carry across the handoff.

## Runtime authority

When a deployed agent runs, the resulting karta - a durable computer for a
user-agent relationship, virtual employee, backend job, account role, or fleet
member - is itself an actor with shell and tool access.
It can be steered by user input or by data it fetches (prompt injection). Karta
treats it as its **own actor**: its authority is scoped to the current karta and
session, not the platform, so a prompt-injected or misbehaving karta is contained
to its own boundary.

<CardGroup cols={2}>
  <Card title="Sub-agent files" icon="users-gear" href="/build/defining-agents">
    The full frontmatter format and conventions.
  </Card>

  <Card title="Skills" icon="wand-magic-sparkles" href="/build/skills">
    Give agents reusable capabilities.
  </Card>
</CardGroup>
