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

# Drafts overview

> A draft is a per-user, per-branch staging area for unpublished agent edits.

A **draft** holds the unpublished edits one user is making on one branch of one agent. Drafts are scoped to the requester — two users can edit the same branch concurrently without colliding, and each user only ever sees their own draft. Publishing a draft promotes it to a new immutable [version](/api-reference/versions/overview) on the branch and clears the draft row.

A draft owns:

* A **config** — the same JSON shape stored in `agent_version.config`. In this release that's just `{ system_prompt }`.
* An **updated\_at** timestamp set by the most recent `PUT`.

There is no "draft id." Drafts are addressed by `(agent_id, branch_id, user_id)`.

## Lifecycle

```mermaid theme={null}
flowchart LR
  Get([GET .../draft]) --> Edit[(Local edits)]
  Edit --> Put([PUT .../draft])
  Put --> Publish([POST .../publish])
  Put --> Discard([DELETE .../draft])
  Publish --> Version[(New version on branch)]
```

`PUT` is idempotent and upserts the current user's draft on the branch. `DELETE` discards it. `POST .../publish` runs the draft under a row-level `FOR UPDATE` lock on the branch — autosaves that race with publish either land before the lock and are published, or land after and survive, but never get silently dropped.

## Publishing

`POST /v1/agents/{agentId}/branches/{branchId}/publish`:

1. Reads the draft inside the transaction (under the branch lock).
2. Returns `400 no_draft` if the requester has no draft on this branch.
3. Allocates the next `version_number` for the branch under the same lock — concurrent publishes serialize behind it instead of racing the unique `(branch_id, version_number)` index.
4. Inserts a new `agent_version`, advances the branch's `head_version_id` to it, and deletes the draft row.
5. Returns the new version's full detail (config + audit fields).

The new version's `parent_version_id` is the branch's `head_version_id` as observed under the lock, so a publish that races a merge into the same branch still chains correctly.

## Authorization

Same rules as [Branches](/api-reference/branches/overview): organization-scoped, `404 no_active_organization` when the session has no active org. Drafts themselves are user-scoped within that org — there is no cross-user read of another user's draft.
