# Create a draft

Stages a change set without touching the live agent.

|  |  |
| --- | --- |
| REST | `POST /api/v1/agents/{agent_id}/drafts` |
| MCP tool | `create_draft` |
| Classification | **Write** |
| Scope | `agents:write` |
| Minimum role on the agent | editor |
| Confirmation | Not needed |
| Retry safety | Send an `Idempotency-Key` header (REST) or `idempotency_key` argument (MCP) to retry safely |
| Success status | 201 |

## What it does

Stages a change set without touching the live agent. The draft shows its diff against the current agent and the validation of the result, so a person can review it before apply_draft.

## Side effects

Stores a draft. Nothing visitors see changes until the draft is applied.

## Inputs

| Name | Type | Required | In | Description |
| --- | --- | --- | --- | --- |
| `agent_id` | string | yes | path | The agent id (agt_...), from list_agents. |
| `title` | string | no | body | Default "". |
| `changes` | object | yes | body | Changes by section. identity and personality take the fields to change. links, offers, knowledge and places take add (new items), update (items with id plus the fields to change) and remove (ids). Get ids and current values from get_agent_configuration; get the full schema from get_configuration_schema. |

## Example

REST:

```bash
curl -X POST "https://covo.lanaai.io/api/v1/agents/agt_4edc89bb2964/drafts" \
  -H "Authorization: Bearer $COVO_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"title":"Experiment","changes":{"personality":{"tone":"Playful."}}}'
```

MCP (POST /mcp):

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "create_draft",
    "arguments": {
      "agent_id": "agt_4edc89bb2964",
      "title": "Experiment",
      "changes": {
        "personality": {
          "tone": "Playful."
        }
      }
    }
  }
}
```

## Response

Returns an object with `id`, `title`, `status`, `base_revision`, `current_revision`, `stale`, `change_set`, `changes`, `problems`, `removes`, `validation`, `client`, `created_at` and `updated_at`. This is a real response, shortened to two items per list.

201 response:

```json
{
  "id": "ba5e403e-7650-449d-b575-beaffff3401b",
  "title": "Experiment",
  "status": "open",
  "base_revision": 7,
  "current_revision": 7,
  "stale": false,
  "change_set": {
    "personality": {
      "tone": "Playful."
    }
  },
  "changes": [
    {
      "path": "personality.tone",
      "operation": "replace",
      "before": "Warm, direct and practical.",
      "after": "Playful."
    }
  ],
  "problems": [],
  "removes": 0,
  "validation": {
    "valid": true,
    "state": "ready",
    "errors": [],
    "warnings": [
      {
        "step": "knowledge",
        "field": null,
        "severity": "recommended",
        "message": "Add a few common questions. Short, specific answers work best."
      },
      {
        "step": "publish",
        "field": null,
        "severity": "recommended",
        "message": "Ask the preview a question before you publish."
      }
    ]
  },
  "client": {
    "name": "docs-examples",
    "interface": "rest"
  },
  "created_at": "2026-10-07T20:14:41.897Z",
  "updated_at": "2026-10-07T20:14:41.897Z"
}
```

Over MCP the same object comes back as the tool result, in `structuredContent` and as JSON text.

## Errors

| Status | Code | Meaning |
| --- | --- | --- |
| 401 | `unauthorized` | No token, or it is unknown, revoked or expired. OAuth apps refresh or reconnect. |
| 403 | `account_suspended` | The account that owns the token is paused. |
| 403 | `insufficient_scope` | The token lacks `agents:write`. |
| 404 | `agent_not_found` | Unknown agent, or not reachable with this token. |
| 400 | `bad_request` | An input is invalid; `field` names it. |
| 409, 422 | `idempotency_in_progress`, `idempotency_key_reused` | See Idempotency on the REST page. |
| 403 | `plan_limit` | The plan is full; `details` has the limit. |
| 429 | `rate_limited` | Wait `Retry-After` seconds. |
