# Branches (/concepts/branches)



A **branch** is an append-only line of events inside a [session](/concepts/sessions). It is how agent history grows: each turn adds one immutable [event](/concepts/sessions) to the head of a branch, and the branch advances. Branches let you fork a workflow to explore an alternative without disturbing the line you forked from.

```json
{
  "id": "br_01jy...",
  "object": "session_branch",
  "session_id": "ses_01jy...",
  "parent_branch_id": null,
  "forked_from_event_id": null,
  "head_event_id": "evt_01jy...",
  "version": 17
}
```

## Append-only with a single causal parent [#append-only-with-a-single-causal-parent]

Events are immutable and form a causal chain. Every event has exactly one parent, except the branch root. You never edit history; you only extend it. This is what makes a branch replayable and auditable: the sequence of events that produced any state is fixed for all time.

## Optimistic concurrency [#optimistic-concurrency]

Two writers must not silently clobber each other's appends. So an append is a compare-and-swap: you state what you believe the branch head is, and the write only succeeds if you are right.

```bash
POST /v2/sessions/{session_id}/branches/{branch_id}/events
```

```json
{
  "expected_version": 17,
  "expected_head_event_id": "evt_017",
  "event": { "event_type": "user_message", "payload_ref": "art_..." }
}
```

If the branch head moved since you read it, the append is rejected:

```
409 branch_version_conflict
```

<Note>
  On a conflict, re-read the branch head, decide whether your event still makes sense in the new context, and retry against the current version. The platform never resolves the conflict for you, because it cannot know your intent.
</Note>

## Creating a branch [#creating-a-branch]

Forking is explicit. You name the branch and the exact event you are forking from:

```json
POST /v2/sessions/{session_id}/branches
{
  "fork_from_branch_id": "br_main",
  "fork_from_event_id": "evt_017",
  "label": "alternative-debug-path"
}
```

The new branch shares all history up to the fork point and diverges after it.

## Merges are explicit, never automatic [#merges-are-explicit-never-automatic]

There is no automatic branch merge. An opaque, machine-decided merge would silently rewrite causal history, which the model forbids. Instead you choose how to bring lines back together:

<AccordionGroup>
  <Accordion title="Append a selected checkpoint">
    Write a human-chosen `checkpoint` artifact onto the target branch as a new event.
  </Accordion>

  <Accordion title="Compact into a summary">
    Compact a branch into a `compaction_summary` artifact and append that, replacing a long tail with a short reference.
  </Accordion>

  <Accordion title="Rebase onto a selected event">
    Reapply a branch's events onto a chosen base event, producing a new ordered line.
  </Accordion>

  <Accordion title="Fork with chosen references">
    Create a new branch that references exactly the events you want to carry forward.
  </Accordion>
</AccordionGroup>

<Warning>
  Every merge strategy produces new, explicit events. None of them mutate or delete existing events. History is always additive.
</Warning>

## Branches and retries [#branches-and-retries]

The optimistic-concurrency discipline is also how retries stay safe. A transport retry reuses an idempotency key so a failed-then-retried append commits once. A provider failover preserves the logical response and adds a new attempt without touching branch history. Assistant output is committed to a branch exactly once. See [idempotency and retries](/guides/idempotency-and-retries) for the full retry model.

<CardGroup cols="2">
  <Card title="Snapshots" icon="camera" href="/concepts/snapshots">
    Pinning a branch head for a single response.
  </Card>

  <Card title="Branches API" icon="code" href="/api-v2/branches">
    Fork branches and append events.
  </Card>
</CardGroup>
