- 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.
(agent_id, branch_id, user_id).
Lifecycle
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:
- Reads the draft inside the transaction (under the branch lock).
- Returns
400 no_draftif the requester has no draft on this branch. - Allocates the next
version_numberfor the branch under the same lock — concurrent publishes serialize behind it instead of racing the unique(branch_id, version_number)index. - Inserts a new
agent_version, advances the branch’shead_version_idto it, and deletes the draft row. - Returns the new version’s full detail (config + audit fields).
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: 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.