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

# Agent Profiles

> Reusable agent templates that define how an agent thinks, which tools it can use, and which LLM it runs on.

## What is a Profile?

A **Profile** is the blueprint for an agent. It captures:

* Which LLM runtime and model to use
* What the agent's persona and instructions are (system prompt)
* Which tools the agent is allowed to call
* Which external MCP servers the agent can access

Profiles are **reusable templates** — one profile can back many concurrent sessions. Editing a profile never affects sessions that are already running.

***

## Profile Schema

```go theme={null}
type AgentProfile struct {
  ID           string        // auto-generated "agent-<uuid>"
  Name         string        // unique, human-readable label
  Runtime      string        // "claude" | "codex" | "general"
  SystemPrompt string        // instructions injected as the system message
  Skills       []string      // explicit skill names injected into runs
  Tools        []string      // tool selectors (empty = default safe toolkit)
  MCPServers   []MCPServerSpec
  Model        string        // e.g. "claude-sonnet-4-6", "anthropic:claude-haiku-4-5"
  FS           *FSPolicy     // optional extra filesystem grants/denies
  WorkerMode      string               // "static" (default) | "sandbox"
  WorkerSubstrate string               // "e2b" | "daytona" | "docker" | "process"
  WorkerImage     string               // optional substrate-specific image override
  WorkerPlacement *WorkerPlacementInfo // computed on read; ignored on write
}
```

***

## Creating a Profile

Most operators create and edit profiles in the dashboard. The API and generated SDKs use the same schema for automation, tenant onboarding, and tests.

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://api.orcapods.ai/api/profiles \
    -H 'Content-Type: application/json' \
    -d '{
      "name": "researcher",
      "runtime": "general",
      "model": "anthropic:claude-sonnet-4-6",
      "systemPrompt": "You are a research assistant. Always cite sources. Be concise.",
      "tools": ["web_search", "web_extract", "time_now"]
    }'
  ```

  ```json Response theme={null}
  {
    "id": "agent-4f8a2e1b",
    "name": "researcher",
    "runtime": "general",
    "model": "anthropic:claude-sonnet-4-6",
    "systemPrompt": "You are a research assistant. Always cite sources. Be concise.",
    "tools": ["web_search", "web_extract", "time_now"],
    "mcpServers": []
  }
  ```
</CodeGroup>

***

## Runtime Selection

The `runtime` field determines which agent-worker mode handles runs for this profile.

| Runtime   | SDK                              | Model format                                                      |
| --------- | -------------------------------- | ----------------------------------------------------------------- |
| `claude`  | `@anthropic-ai/claude-agent-sdk` | `claude-sonnet-4-6`, `claude-haiku-4-5`                           |
| `codex`   | `@openai/codex-sdk`              | `codex-mini`, `o4-mini`                                           |
| `general` | Vercel AI SDK                    | `anthropic:claude-*`, `openai:gpt-*`, `google:gemini-*`, `groq:*` |

<Tip>
  Use `runtime: "general"` when you want to switch providers without changing your runner infrastructure. Use `runtime: "claude"` when you need native Claude features like extended thinking or citations.
</Tip>

***

## Worker Placement

`workerMode` selects how the runner reaches the agent-worker without changing the profile's `runtime` or model behavior:

| Value                 | Behavior                                                                                                                                                         |
| --------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| omitted or `"static"` | The runner calls the fixed sidecar URL configured for the runtime. This is the default for existing profiles.                                                    |
| `"sandbox"`           | The runner uses one outbound-only worker per session. The worker calls the runner's authenticated `/worker/*` routes; the runner does not dial into the sandbox. |

Sandbox workers are launched lazily on the session's first run, reused by later runs, and closed when the session shuts down. The runner must have `WORKER_TOKEN_HMAC_KEY` and a worker substrate configured, or an operator must launch the worker out of band. See [Dynamic sandbox workers](/guides/local-development#dynamic-sandbox-workers) for runner configuration.

For sandbox workers, `workerSubstrate` explicitly selects `e2b`, `daytona`,
`docker`, or `process`. When omitted, Orca prefers the profile's
`sandbox.provider` if the runner serves it, then falls back to that runner's
default substrate. An explicit substrate that no runner serves is not rejected
when the profile is saved; session placement fails with the fleet's available
substrates instead.

`workerImage` overrides the runner's image for the selected substrate: an E2B
template id, Daytona snapshot name, or Docker image reference. Because those
artifacts are not interchangeable, set `workerSubstrate` and `workerImage`
together or leave both unset.

On profile reads, a pooled Conductor may add `workerPlacement` with the resolved
`substrate`, its `source` (`explicit`, `shell`, `default`, or `unknown`), whether
it is `servable`, and explanatory `requested` or `detail` fields when needed.
This value reflects the live fleet, is absent for static profiles, and is
ignored rather than persisted when supplied on create or update.

```json theme={null}
{
  "name": "isolated-researcher",
  "runtime": "general",
  "workerMode": "sandbox",
  "workerSubstrate": "e2b",
  "model": "anthropic:claude-sonnet-4-6",
  "tools": ["@default"]
}
```

***

## Tool Selectors

The `tools` array controls which platform tools the agent can invoke. Four forms are supported:

### 1. Named Tools

Include specific tools by name:

```json theme={null}
{
  "tools": ["web_search", "web_extract", "time_now", "runner_info"]
}
```

### 2. Capability Sentinels

Expand all tools in a capability group:

```json theme={null}
{
  "tools": ["@introspection", "@orchestration"]
}
```

| Sentinel         | Expands to                                                                                                                                                                                                     |
| ---------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `@default`       | Curated safe baseline: `@introspection`, `@fs`, `@pool`, `time_now`, `echo`, `math_add`                                                                                                                        |
| `@introspection` | State and utility tools such as `runner_info`, `profile_info`, `list_profiles`                                                                                                                                 |
| `@fs`            | File tools: `read_file`, `write_file`, `list_dir`, `delete_file`                                                                                                                                               |
| `@pool`          | Pool tools: `pool_info`, `pool_post`, `pool_inbox`                                                                                                                                                             |
| `@vfs`           | VirtualFS shell/search tools: `vfs_execute`, `vfs_grep`                                                                                                                                                        |
| `@artifacts`     | Raw run/session artifact tools                                                                                                                                                                                 |
| `@memory`        | Per-profile Memory Bank: `memory_save`, `memory_recall`, `memory_list`, `memory_delete`. Selecting it also enables automatic prompt injection — see [Memory Bank](/concepts/memory-bank)                       |
| `@orchestration` | Delegation and workflow run tools                                                                                                                                                                              |
| `@profiles`      | Profile admin: `create_profile`, `update_profile`, `delete_profile`, `attach_skill`, `detach_skill`.                                                                                                           |
| `@pools.admin`   | Pool admin: `create_pool`, `update_pool`, `delete_pool`, `add_pool_member`, `remove_pool_member`.                                                                                                              |
| `@mcp`           | MCP catalog admin: `add_mcp_server`, `update_mcp_server`, `delete_mcp_server`, `test_mcp_connection`. Secret values are never accepted inline — env/header inputs require a `secretRef` from the Secrets page. |
| `@skills`        | Read-only skills catalog: `list_skills`, `describe_skill`.                                                                                                                                                     |

### 3. Wildcard Patterns

Pattern-match tool names:

```json theme={null}
{
  "tools": ["web_*"]
}
```

This matches `web_search` and `web_extract`.

### Empty = Defaults

```json theme={null}
{
  "tools": []
}
```

An omitted or empty array grants the curated default set (equivalent to `["@default"]`).

<Warning>
  Raw artifact tools (`@artifacts`), Memory Bank tools (`@memory`), and orchestration tools (`@orchestration`) are not in `@default`. Web tools currently sit under `@introspection`; without `TAVILY_API_KEY`, they return a tool-level "not configured" error.
</Warning>

***

## Skills

The `skills` array names instruction bodies from the conductor skill store (see [Skills](/concepts/skills)). Profile create and update requests reject confirmed unknown skill names with `400 Bad Request`, so use the dashboard picker or `GET /api/skills` before attaching them. In Postgres-backed conductor deployments, validation uses the tenant-scoped skill store that backs the dashboard skill list. In local no-DB mode, validation falls back to the in-memory skill catalog; if no catalog is available, Orca skips validation so degraded local setups can still register profiles.

At run dispatch, the conductor resolves the validated names and sends the matched skill bodies, Agent Skills metadata, and resource manifests to the worker. Skills with executable `scripts/` resources are marked `requiresSandbox`; their scripts execute through the runner's `run_skill_script` tool inside the session [sandbox](/concepts/sandboxes).

Tool capability selectors also auto-attach matching platform skills. For example, a profile with `@vfs` receives `using-vfs`, and an omitted or empty `tools` array receives the `using-*` skills for the `@default` bundle. In Postgres deployments, the conductor first reconciles the tenant's platform-skill rows; a tenant-scoped tombstone keeps an intentionally deleted seed absent. Any auto-attached name that remains missing is skipped silently.

***

## MCP Servers and Connected Apps

Profiles can attach inline external MCP servers or grant access to provider-managed connected apps (see [MCP Integration](/concepts/mcp-integration)). Inline servers are sent to the sidecar during a run:

```json theme={null}
{
  "name": "data-agent",
  "runtime": "general",
  "model": "anthropic:claude-sonnet-4-6",
  "systemPrompt": "You are a data analyst.",
  "tools": ["@introspection"],
  "mcpServers": [
    {
      "name": "company-db",
      "transport": "http",
      "url": "https://internal.example.com/mcp",
      "headers": {
        "Authorization": "Bearer ${INTERNAL_API_KEY}"
      }
    }
  ]
}
```

<Note>
  Header values prefixed with `${VAR}` are resolved from the **runner's environment** before the run envelope is sent to the sidecar. Unresolved secrets never reach the sidecar or appear in logs.
</Note>

Connected apps use credential-free catalog references instead:

```json theme={null}
{
  "mcpServers": [
    {
      "name": "composio-gmail",
      "ref": "catalog://composio-gmail"
    }
  ]
}
```

Managed references authorize `search_connected_app_tools` and `call_connected_app_tool`. They are omitted from the worker's native MCP transport configuration, and must not include `transport`, `url`, or `headers`.

### MCP Server Spec

| Field       | Type                | Description                                                                                     |
| ----------- | ------------------- | ----------------------------------------------------------------------------------------------- |
| `name`      | string              | Identifier (cannot be `"runner"` — reserved)                                                    |
| `transport` | `"http"` or `"sse"` | Required for inline servers                                                                     |
| `url`       | string              | Required HTTP(S) URL for inline servers                                                         |
| `headers`   | map\[string]string  | Optional inline-server headers (supports `${VAR}` placeholders)                                 |
| `ref`       | string              | Managed reference in the exact form `catalog://<name>`; mutually exclusive with URL and headers |

***

## Filesystem Policy

Every profile gets an implicit home directory at `/agents/{self}/**` with read/write/delete access. The optional `fs` field adds more grants or denies:

```json theme={null}
{
  "fs": {
    "read": ["/datasets/**"],
    "write": ["/shared/{self}/**"],
    "delete": ["/shared/{self}/tmp/**"],
    "deny": ["/datasets/private/**"],
    "allow_mounts": ["/datasets", "/shared"]
  }
}
```

`delete` defaults to `write` when omitted. `deny` is a hard override. Pool membership can add more access under `/pools/{pool}/...`; see [Agent Pools](/concepts/pools).

When the runtime has a per-session VirtualFS manager, session creation also allocates a VirtualFS session. `fs.allow_mounts` is the explicit mount-prefix allowlist for that lease. If it is omitted, Orca derives the allowlist from the first path segment of the profile's `read`, `write`, and `delete` globs. If no mount prefixes can be derived, the VFS lease is unrestricted.

In the dashboard profile editor, enabling **Limit to specific mounts** under **File access** also adds the `@vfs` tool selector automatically so the profile receives `vfs_execute` and `vfs_grep`. API clients that set `fs.allow_mounts` directly should include `@vfs` in `tools` when the agent needs those VirtualFS tools.

***

## Default Seed Profile

Every fresh deployment includes a `general` profile:

```json theme={null}
{
  "name": "general",
  "runtime": "general",
  "model": "anthropic:claude-haiku-4-5",
  "systemPrompt": "You are a general-purpose assistant. Keep answers concise and use tools when helpful.",
  "tools": ["@default", "web.*"]
}
```

This is what you see in the Workbench out of the box.

<Note>
  The seeded profile still carries the legacy `web.*` selector. The current web tool names are `web_search` and `web_extract`; `@default` selects them today because they carry the `introspection` capability. New explicit web selectors should use exact names or `web_*`.
</Note>

***

## Managing Profiles via API

| Method   | Path                   | Description          |
| -------- | ---------------------- | -------------------- |
| `GET`    | `/api/profiles`        | List all profiles    |
| `GET`    | `/api/profiles/{name}` | Get one profile      |
| `POST`   | `/api/profiles`        | Create a new profile |
| `DELETE` | `/api/profiles/{name}` | Delete a profile     |

<Warning>
  Deleting a profile does not terminate existing sessions. Sessions hold a snapshot of their profile at creation time.
</Warning>

***

## Profile Examples

<AccordionGroup>
  <Accordion title="Code Review Agent">
    ```json theme={null}
    {
      "name": "code-reviewer",
      "runtime": "claude",
      "model": "claude-sonnet-4-6",
      "systemPrompt": "You are an expert code reviewer. Focus on correctness, security, and maintainability. Provide specific, actionable feedback.",
      "tools": ["time_now", "session_info"]
    }
    ```
  </Accordion>

  <Accordion title="Research Coordinator (with delegation)">
    ```json theme={null}
    {
      "name": "research-coordinator",
      "runtime": "general",
      "model": "anthropic:claude-sonnet-4-6",
      "systemPrompt": "You coordinate research tasks by delegating sub-tasks to specialist agents and synthesizing their results.",
      "tools": ["@default", "@orchestration", "web_search"]
    }
    ```

    <Note>Set `AGENT_ORC_ORCHESTRATION_TOOLS=off` on the runner to remove orchestration tools entirely in restricted environments.</Note>
  </Accordion>

  <Accordion title="Data Pipeline Agent (with external MCP)">
    ```json theme={null}
    {
      "name": "data-engineer",
      "runtime": "general",
      "model": "openai:gpt-5.2",
      "systemPrompt": "You build and manage data pipelines. Use the database tools to query and transform data.",
      "tools": ["time_now"],
      "mcpServers": [
        {
          "name": "warehouse",
          "transport": "http",
          "url": "https://warehouse.internal/mcp",
          "headers": { "X-API-Key": "${WAREHOUSE_API_KEY}" }
        }
      ]
    }
    ```
  </Accordion>
</AccordionGroup>
