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

# Configure HQ agents

> List, create, update, enable/disable, default, and equip agents with skills, MCP servers, and avatars over the HQ API.

An **agent** is a configurable persona in your workspace: a routing slug, a display name, system-prompt instructions, personality settings, a runtime profile and model, and an enabled subset of skills and MCP servers. This guide walks the full lifecycle using the `/v1/agents` endpoints.

All requests go to the base URL `https://api.hq.zone` and authenticate with a personal access token:

```bash theme={null}
export HQ_TOKEN="hq_pat_..."
# Authorization: Bearer $HQ_TOKEN
```

<Note>
  Read operations require the `agents:read` scope. Every write operation (create, update, disable, enable, set default, replace skills/MCP, upload avatar, suggest instructions) requires the `admin` scope. Each endpoint is scoped to your own workspace; you can never see or modify another workspace's agents.
</Note>

## Discover what's available

<Steps>
  <Step title="List your agents">
    Returns every agent in your workspace, ordered with the default agent first, then enabled agents, then by slug. See [List agents](/api-reference/agents/list-agents).

    ```bash theme={null}
    curl https://api.hq.zone/v1/agents \
      -H "Authorization: Bearer $HQ_TOKEN"
    # → { "agents": [ { "id": "...", "slug": "...", "display_name": "...",
    #                   "is_default": true, "status": "enabled", ... } ] }
    ```

    Each agent carries `id`, `slug`, `display_name`, `description`, `instructions`, `instructions_is_default`, `tone`, `verbosity`, `cautions`, `languages`, `aliases`, `runtime_profile`, `model`, `delivery_mode`, `is_default`, `status`, `avatar_url`, and `created_at`.
  </Step>

  <Step title="List selectable models">
    The agent editor's model picker. Pass the optional `runtime` query parameter (`claude-sdk`, `openai-agents`, or `opencode`) to restrict to one runtime profile; otherwise all selectable models are returned. See [List models](/api-reference/agents/list-models).

    ```bash theme={null}
    curl "https://api.hq.zone/v1/models?runtime=claude-sdk" \
      -H "Authorization: Bearer $HQ_TOKEN"
    # → { "models": [ { "slug": "...", "display_name": "...", "family": "...",
    #                   "runtime_profile": "claude-sdk", "vendor": "...",
    #                   "is_default": true } ] }
    ```

    <Tip>A model is only valid for an agent if its `runtime_profile` matches the agent's `runtime_profile`. Pick a `slug` from this list whose `runtime_profile` equals the runtime you plan to use.</Tip>
  </Step>
</Steps>

## Create an agent

<Steps>
  <Step title="POST a new agent">
    Only `slug` and `display_name` are required. Everything else is optional. See [Create agent](/api-reference/agents/create-agent).

    ```bash theme={null}
    curl -X POST https://api.hq.zone/v1/agents \
      -H "Authorization: Bearer $HQ_TOKEN" -H "Content-Type: application/json" \
      -d '{
        "slug": "cfo",
        "display_name": "Anna the CFO",
        "description": "Finance questions for the leadership team.",
        "instructions": "You are Anna, the CFO assistant.",
        "tone": "formal",
        "verbosity": "concise",
        "cautions": ["Do not quote private legal opinions"],
        "languages": ["en", "sv"],
        "aliases": ["anna", "finance"],
        "runtime_profile": "claude-sdk",
        "model": "claude-opus-4-8"
      }'
    # → the created agent (same shape as a list entry)
    ```
  </Step>

  <Step title="Know the field rules">
    The request accepts: `slug`, `display_name`, `description`, `instructions`, `tone`, `verbosity`, `cautions`, `languages`, `aliases`, `runtime_profile`, `model`, `avatar_url`, `enabled_skill_slugs`, and `enabled_mcp_slugs`.

    * **`slug`** and each entry of **`aliases`** must be 2-32 characters, lowercase ASCII letters/digits/hyphens, not starting or ending with a hyphen, with no `--`, and not a reserved token (`hq`, `me`, `help`, `default`, `none`, `agent`, `anyone`, `all`, `system`, `admin`, `bot`). An alias must differ from the slug and must not collide with any other agent's slug or alias in the workspace.
    * **`tone`** must be one of `formal`, `friendly`, `direct`, `casual` (or omitted).
    * **`verbosity`** must be one of `concise`, `balanced`, `detailed` (or omitted).
    * **`instructions`** is capped at 8 KiB; longer content should live in a skill.
    * **`languages`** are BCP-47 codes (e.g. `en`, `sv`, `pt-BR`), max 8.
    * **`cautions`** are short phrases, max 120 characters each, max 8 items.
    * **`runtime_profile`** defaults to `claude-sdk` if omitted.
    * **`model`** must be a selectable model belonging to `runtime_profile`; omit it to use the runtime's platform default.
  </Step>
</Steps>

<Note>
  If you omit `avatar_url`, an avatar is generated automatically for the new agent (best-effort, asynchronous). To set one explicitly at create time, `avatar_url` must be an internal artifact path produced by the avatar upload flow — external URLs are rejected. See [Upload an avatar](#upload-an-avatar) below.
</Note>

<Warning>
  A bad slug, an alias conflict, or an out-of-range field returns `400`.
</Warning>

## Update an agent

`PATCH /v1/agents/{id}` changes only the fields you send; omitted fields are left unchanged. For nullable fields (`description`, `instructions`, `tone`, `verbosity`, `model`, `avatar_url`), sending an explicit `null` clears the value back to its default. See [Update agent](/api-reference/agents/update-agent).

```bash theme={null}
curl -X PATCH https://api.hq.zone/v1/agents/<AGENT_ID> \
  -H "Authorization: Bearer $HQ_TOKEN" -H "Content-Type: application/json" \
  -d '{
    "display_name": "Anna (Finance)",
    "verbosity": "balanced",
    "description": null
  }'
# → the updated agent
```

The request accepts the same editable fields as create: `slug`, `display_name`, `description`, `instructions`, `tone`, `verbosity`, `cautions`, `languages`, `aliases`, `runtime_profile`, and `model`, `avatar_url`. Slug and alias rules match creation, including the collision check.

<Tip>
  Renaming the slug automatically preserves the old slug as an alias, so existing `@hq <old-slug>` references keep routing. Writing any `instructions` value (including clearing it) sets `instructions_is_default` to `false`.
</Tip>

A `400` is returned for an invalid slug, alias conflict, or bad field; `404` if the agent is not in your workspace.

## Enable, disable, and set the default

<Steps>
  <Step title="Disable an agent">
    Sets `status` to `disabled` so it stops routing on every surface. The default agent cannot be disabled. See [Disable agent](/api-reference/agents/disable-agent).

    ```bash theme={null}
    curl -X DELETE https://api.hq.zone/v1/agents/<AGENT_ID> \
      -H "Authorization: Bearer $HQ_TOKEN"
    # → the now-disabled agent
    ```

    <Warning>Disabling the default agent returns `400` — promote another agent to default first.</Warning>
  </Step>

  <Step title="Re-enable an agent">
    Flips `status` back to `enabled`. It is idempotent — calling it on an already-enabled agent is a no-op. See [Enable agent](/api-reference/agents/enable-agent).

    ```bash theme={null}
    curl -X POST https://api.hq.zone/v1/agents/<AGENT_ID>/enable \
      -H "Authorization: Bearer $HQ_TOKEN"
    # → the re-enabled agent
    ```
  </Step>

  <Step title="Promote to default">
    Atomically clears the default flag from whichever agent held it and sets this one. The target must be enabled. See [Set default](/api-reference/agents/set-default).

    ```bash theme={null}
    curl -X POST https://api.hq.zone/v1/agents/<AGENT_ID>/default \
      -H "Authorization: Bearer $HQ_TOKEN"
    # → the now-default agent
    ```

    <Warning>A disabled agent cannot be made the default — that returns `400`.</Warning>
  </Step>
</Steps>

All three return `404` if the agent is not in your workspace.

## Attach skills and MCP servers

Each agent has an enabled **subset** of skills and MCP servers. An **empty list means "use everything installed for the workspace."** The `PUT` endpoints **fully replace** the current subset — they do not merge with what's already there.

<Steps>
  <Step title="Inspect the current subsets">
    See [List skills](/api-reference/agents/list-skills) and [List MCP](/api-reference/agents/list-mcp).

    ```bash theme={null}
    curl https://api.hq.zone/v1/agents/<AGENT_ID>/skills \
      -H "Authorization: Bearer $HQ_TOKEN"
    # → { "enabled": ["..."] }   (empty = all installed)

    curl https://api.hq.zone/v1/agents/<AGENT_ID>/mcp \
      -H "Authorization: Bearer $HQ_TOKEN"
    # → { "enabled": ["..."] }   (empty = all installed)
    ```
  </Step>

  <Step title="Replace the skill subset">
    Send the complete `enabled` list. Each slug must be a skill currently installed for the workspace. See [Replace skills](/api-reference/agents/replace-skills).

    ```bash theme={null}
    curl -X PUT https://api.hq.zone/v1/agents/<AGENT_ID>/skills \
      -H "Authorization: Bearer $HQ_TOKEN" -H "Content-Type: application/json" \
      -d '{"enabled": ["web-search", "calendar"]}'
    # → { "enabled": ["calendar", "web-search"] }
    ```
  </Step>

  <Step title="Replace the MCP subset">
    Same contract for MCP servers. See [Replace MCP](/api-reference/agents/replace-mcp).

    ```bash theme={null}
    curl -X PUT https://api.hq.zone/v1/agents/<AGENT_ID>/mcp \
      -H "Authorization: Bearer $HQ_TOKEN" -H "Content-Type: application/json" \
      -d '{"enabled": ["github"]}'
    # → { "enabled": ["github"] }
    ```
  </Step>
</Steps>

<Warning>
  These are **replace, not merge**. The request body is the new complete subset — any slug you leave out is removed. To reset an agent to "all installed," send `{"enabled": []}`. If any requested slug is not installed for your workspace, the whole request is rejected with `400`. A missing agent returns `404`.
</Warning>

## Upload an avatar

`POST /v1/agents/{id}/avatar` uploads an avatar image. The image is sent as **base64 in a JSON body** (not multipart). The body has three fields: `filename`, `content_type`, and `body_b64`. See [Upload avatar](/api-reference/agents/upload-avatar).

```bash theme={null}
curl -X POST https://api.hq.zone/v1/agents/<AGENT_ID>/avatar \
  -H "Authorization: Bearer $HQ_TOKEN" -H "Content-Type: application/json" \
  -d "{
    \"filename\": \"anna.png\",
    \"content_type\": \"image/png\",
    \"body_b64\": \"$(base64 -w0 anna.png)\"
  }"
# → the agent, with its new avatar_url
```

* `content_type` must be one of `image/png`, `image/jpeg`, `image/svg+xml`, `image/webp`, or `image/gif`.
* The decoded image must be non-empty and at most 2 MiB.
* The handler stores the bytes and writes the resulting internal artifact path into the agent's `avatar_url`.

<Warning>
  An empty, oversized, or unsupported-type image returns `400`; a missing agent returns `404`. You generally do not set `avatar_url` directly on create/update — only an internal artifact path produced by this upload is accepted there.
</Warning>

## Suggest tailored instructions

`POST /v1/agents/{id}/suggest-instructions` drafts a tailored system prompt for the agent based on your workspace's profile and the agent's current role, and returns it for review. See [Suggest instructions](/api-reference/agents/suggest-instructions).

```bash theme={null}
curl -X POST https://api.hq.zone/v1/agents/<AGENT_ID>/suggest-instructions \
  -H "Authorization: Bearer $HQ_TOKEN"
# → { "instructions": "You are Anna, the CFO assistant for ..." }
```

The draft is **never auto-saved**. Review it, then persist it yourself with a follow-up update:

```bash theme={null}
curl -X PATCH https://api.hq.zone/v1/agents/<AGENT_ID> \
  -H "Authorization: Bearer $HQ_TOKEN" -H "Content-Type: application/json" \
  -d '{"instructions": "<reviewed draft text>"}'
```

<Note>
  A `404` is returned if the agent is not in your workspace; a `500` is returned if the tailor feature is disabled (no Anthropic key configured on the control plane).
</Note>
