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

# Versions, environments and deploying

> Draft, publish, activate and roll back — for agents, workflows and prompt blocks — and how Dev, Staging and Prod relate.

Three kinds of object are versioned — agents, workflows and prompt blocks —
and all three use the same lifecycle. Networks are not versioned; they exist
once per environment and are promoted by deploying. This page covers both
mechanisms and how they meet.

## One lifecycle, three objects

Every agent, workflow and prompt block has:

* **A draft**, version 0. Mutable. Where you edit.
* **Published versions**, 1, 2, 3, … Immutable. Publishing copies the draft
  into a new numbered version; nothing ever updates one in place.
* **An active pointer.** Exactly one published version serves traffic. The
  pointer can move to any published version at any time.

| Action         | Endpoint                                                     | What changes                                      |
| -------------- | ------------------------------------------------------------ | ------------------------------------------------- |
| Save the draft | `PATCH /v1/{agents\|workflows\|prompt-blocks}/{id}/draft`    | Nothing live. The draft's `rev` counter advances. |
| Publish        | `POST …/{id}/publish`                                        | A new frozen version exists. Nothing live.        |
| Activate       | `POST …/{id}/activate` with `version_number` or `version_id` | What serves traffic.                              |
| Roll back      | `POST …/{id}/activate` with an older version                 | The same. Rollback is repointing, not re-editing. |

Publishing is where validation happens. An agent publish resolves every
prompt-block reference strictly, then does a trial build. A workflow publish
runs full semantic validation — unknown or forward references, cycles,
orphan steps, code that does not compile — then a trial build. All three
refuse to publish a draft identical to the latest version with a `422`, so a
version always carries a change. Workflows and prompt blocks accept a
`change_message` on publish; agents do not.

Every read tells you where things stand:

```json theme={null}
{
  "agent": {
    "activeVersionNumber": 4,
    "latestPublishedVersionNumber": 5,
    "draftDirty": true
  }
}
```

Version 5 was published but not activated; the draft has moved on since.

## Selecting a version on read

`GET /v1/agents/{id}`, `GET /v1/workflows/{id}` and
`GET /v1/prompt-blocks/{id}` take one query parameter:

| `?version=`         | Returns                                                       |
| ------------------- | ------------------------------------------------------------- |
| omitted or `active` | The active version, or the draft if nothing is activated yet. |
| `draft` (or `0`)    | The draft.                                                    |
| `latest`            | The newest published version, active or not.                  |
| `3` (or `v3`)       | That version number.                                          |
| a version id        | That version.                                                 |

An unknown version answers `404` with a message naming what was asked for;
anything unparsable answers `400`.

## The pinning guarantee

When an agent publishes, every `prompt_block_ref` in its instructions is
frozen to the block version it resolved to at that moment. A published agent
version therefore renders **exactly the same prompt forever**: publishing or
activating a new version of a shared block changes nothing an agent is
already saying. The agent's draft is different — its references float to the
block's current active version, which is what makes editing a block and
previewing an agent feel live.

Pins are server-owned. Sending `versionId` on a reference yourself is a
`400`. See [Prompt blocks](/docs/prompt-blocks#pinning-the-part-worth-understanding).

### Rolling a block update out

After you publish and activate a new block version, agents keep their old pin
until they publish again. Two endpoints make that deliberate rather than
accidental:

* `GET /v1/prompt-blocks/{id}/references` lists every agent using the block,
  whether from its draft or its active version, what it is pinned to, and
  whether that is behind.
* `POST /v1/prompt-blocks/{id}/rollout` republishes and reactivates those
  agents onto the new version. Pass `agentIds` to limit the scope, or
  `activate: false` to publish without moving live pointers.

An agent whose draft differs from its active version is **skipped**, because
publishing ships the whole draft and a prompt rollout must never quietly
release someone's half-finished model or tool changes. The response lists
`rolledOut`, `skipped` and `failed` separately; partial success is a `200`.

### Drift detection

Every agent read carries the signal:

```json theme={null}
{
  "blocksOutdated": true,
  "referencedBlocks": [
    { "id": "…", "name": "Brand voice", "pinnedVersionNumber": 3, "activeVersionNumber": 4, "outdated": true }
  ]
}
```

`blocksOutdated` is independent of `draftDirty`: an agent can be perfectly
clean and still be serving an older copy of a shared block. In the Studio,
a block's **Used by** table shows the same information with an
**Update N agents** button that runs the rollout.

## Previewing before publishing

* **Chat against a draft.** `POST /v1/chat` and `POST /v1/agents/{id}/run`
  take `agentVersionId`, which runs that exact version — the draft, or an
  older published one — bypassing the active pointer and routing. The
  Studio's test chat on an agent page does this for whichever version you
  are viewing.
* **Render the composed prompt.** `POST /v1/agents/{id}/instructions/preview`
  with `version` (`draft` by default, a number, or a version id) and sample
  `variables` returns the rendered prompt block by block, with anything
  missing named.
* **Run a workflow draft.** `POST /v1/workflows/{id}/run?version=draft`.

## Environments

A network exists once per environment: **Dev**, **Staging** and **Prod** are
three network records sharing one identity. Only the Dev network can be
edited directly — attaching agents, changing routing instructions, editing
the chat configuration. Editing Staging or Prod answers `409` with an
instruction to change Dev and deploy.

Deploying copies the Dev network's runnable configuration onto the next
environment:

```bash theme={null}
curl -X POST https://api.sidenet.ai/v1/copilots/DEV_NETWORK_ID/deploy \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "target_copilot_id": "STAGING_NETWORK_ID" }'
```

What moves: the **roster** (agents and workflows), the **routing
instructions**, the **follow-up guidance** and the **chat configuration**
(`sdk_ui`). In the Studio the environment switcher on a network page has a
**Deploy** action that promotes to the next stage and is enabled only when
something differs.

<Warning>
  Deploying overwrites the target. Networks have no version history, so
  there is no rollback for a network: the way back is to edit Dev to the
  previous state and deploy again. Version history lives on the agents,
  workflows and blocks a network is made of.
</Warning>

Traces are tagged with the environment of the network that served them, so
Staging traffic never contaminates Prod's cost and usage figures. A chat
addressed directly to an agent id, outside any network, is tagged Dev.

### What deploying does not require

Agents and workflows attached to a network resolve to **their own active
version** at request time. Activating a new agent version reaches every
environment that lists the agent without a deploy — the roster holds agent
ids, not version ids. A network's resolved roster is cached for up to five
minutes, so a newly activated agent version reaches a network within that
window rather than on the very next turn.

The corollary: environment separation is about the *network's* configuration
— who is on the roster, how routing works, what the widget looks like — not
about the agents' code. If you need an agent to behave differently in
Staging, that is a second agent, or a variable filled per environment.

## Putting it together

A typical change to a shared paragraph:

<Steps>
  <Step title="Edit and publish the block">
    Save the block draft, preview it, publish with a change message, activate.
    No agent has changed yet.
  </Step>

  <Step title="Check who is behind">
    `GET /v1/prompt-blocks/{id}/references` — or the block's Used by table.
  </Step>

  <Step title="Roll out">
    `POST /v1/prompt-blocks/{id}/rollout`. Agents with dirty drafts are
    skipped; finish or discard those drafts and run it again.
  </Step>

  <Step title="Nothing to deploy">
    The networks already list those agents. Every environment picks up the
    new versions within minutes.
  </Step>
</Steps>
