Skip to content
Takeida
Browse the reference

Agent · /v1/agent

Stacks of proposals

A stack is a chain of proposals, each built on the one below it, so a large change can be reviewed in parts that each make sense on their own. Every layer is an ordinary draft with an ordinary proposal, held to the same review rules as any other.

Layers publish from the bottom. When one lands, the layers above it are rebuilt on what landed. A stack is at most eight layers deep.

Stacks

A stack is addressed by its number within the Concept, and a layer by its position. Position 1 is the bottom, resting on the trunk.

List stacks

GET/v1/agent/c/{identifier}/stacks

Every stack in the Concept, each with its layers.

Request
curl https://your-server.example/v1/agent/c/k7m2xq9d/stacks \
  -H "Authorization: Bearer arb_live_…"
Response200
{
  "items": [
    { "number": 7, "title": "Document the authentication system", "state": "open", "drifted": false, … }
  ]
}

Create a stack

POST/v1/agent/c/{identifier}/stacks

Makes a stack, empty or from drafts that already exist. Given drafts, the first becomes the bottom layer, each rests on the one before it, and a proposal is opened for every layer.

Body

titlestring · 1 to 500 · required
What the whole change is.
descriptionstring · up to 20,000
More about it.
draftsstring[] · up to 8
Drafts that exist already, bottom first.

Refusals

  • 404not_foundA draft named does not exist.
  • 400validation_failedMore than eight drafts.
Request
curl -X POST https://your-server.example/v1/agent/c/k7m2xq9d/stacks \
  -H "Authorization: Bearer arb_live_…" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Document the authentication system",
    "drafts": ["scribe/auth-overview", "scribe/auth-sessions"]
  }'
Response201
{
  "number": 7,
  "title": "Document the authentication system",
  "description": null,
  "state": "open",
  "drifted": false,
  "trunkBranch": "main",
  "owner": { "type": "API_KEY", "id": "…", "name": "Scribe", "agentSlug": "scribe" },
  "layers": [
    {
      "position": 1,
      "draft": "scribe/auth-overview",
      "baseBranch": "main",
      "proposalNumber": 51,
      "proposalState": "approved",
      "state": "pending",
      "documentsChanged": 3,
      "approvals": 1,
      "requiredApprovals": 1,
      "conflicts": [],
      "lastRestackedAt": "2026-10-09T09:12:00.000Z"
    },
    {
      "position": 2,
      "draft": "scribe/auth-sessions",
      "baseBranch": "scribe/auth-overview",
      "proposalNumber": 52,
      "proposalState": "open",
      "state": "pending",
      "documentsChanged": 5,
      "approvals": 0,
      "requiredApprovals": 1,
      "conflicts": [],
      "lastRestackedAt": "2026-10-09T09:12:00.000Z"
    }
  ],
  "createdAt": "2026-10-08T15:30:00.000Z",
  "updatedAt": "2026-10-09T09:12:00.000Z"
}

Read a stack

GET/v1/agent/c/{identifier}/stacks/{n}

One stack, and every layer with where its proposal stands.

What a layer tells you

statepending · blocked · conflicted · published · dropped
Where the layer stands in the stack. Blocked means a layer beneath it conflicted, so this one has not been looked at yet.
proposalStatestring
Where its proposal stands in review.
baseBranchstring
The draft it rests on: the layer below, or the trunk.

And the stack

stateopen · partially_published · published · closed
How much of it has landed.
driftedboolean
Whether its drafts no longer rest on one another the way the stack says they do. See the end of this page.
Request
curl https://your-server.example/v1/agent/c/k7m2xq9d/stacks/7 \
  -H "Authorization: Bearer arb_live_…"
Response200
{
  "number": 7,
  "title": "Document the authentication system",
  "description": null,
  "state": "open",
  "drifted": false,
  "trunkBranch": "main",
  "owner": { "type": "API_KEY", "id": "…", "name": "Scribe", "agentSlug": "scribe" },
  "layers": [
    {
      "position": 1,
      "draft": "scribe/auth-overview",
      "baseBranch": "main",
      "proposalNumber": 51,
      "proposalState": "approved",
      "state": "pending",
      "documentsChanged": 3,
      "approvals": 1,
      "requiredApprovals": 1,
      "conflicts": [],
      "lastRestackedAt": "2026-10-09T09:12:00.000Z"
    },
    {
      "position": 2,
      "draft": "scribe/auth-sessions",
      "baseBranch": "scribe/auth-overview",
      "proposalNumber": 52,
      "proposalState": "open",
      "state": "pending",
      "documentsChanged": 5,
      "approvals": 0,
      "requiredApprovals": 1,
      "conflicts": [],
      "lastRestackedAt": "2026-10-09T09:12:00.000Z"
    }
  ],
  "createdAt": "2026-10-08T15:30:00.000Z",
  "updatedAt": "2026-10-09T09:12:00.000Z"
}

Shaping it

Every change to a stack's shape answers with what it did to the layers above the change: which were rebuilt, which were already current, and where it stopped if one conflicted. Shaping a stack needs the standing to change it, which is its owner's or an editor's.

Add a layer on top

POST/v1/agent/c/{identifier}/stacks/{n}/layers

Cuts a new draft from the top layer and opens its proposal. Write on the new draft as on any other.

Body

draftstring · required
The new draft's name, as a namespace and a name.
titlestring · 1 to 500 · required
Its proposal's title.
descriptionstring · up to 20,000
Its proposal's description.

Refusals

  • 409stack_too_deepThe stack already has eight layers.
  • 409draft_existsA draft already has that name.
  • 402plan_limitA layer is a draft, and the agent's owner has as many open drafts as the plan allows.
Request
curl -X POST https://your-server.example/v1/agent/c/k7m2xq9d/stacks/7/layers \
  -H "Authorization: Bearer arb_live_…" \
  -H "Content-Type: application/json" \
  -d '{
    "draft": "scribe/auth-keys",
    "title": "Document API keys"
  }'
Response201
{
  "number": 7,
  "layers": [
    { "position": 1, "draft": "scribe/auth-overview", … },
    { "position": 2, "draft": "scribe/auth-sessions", … },
    { "position": 3, "draft": "scribe/auth-keys", "baseBranch": "scribe/auth-sessions", "proposalNumber": 53, … }
  ],
  …
}

Insert a layer

POST/v1/agent/c/{identifier}/stacks/{n}/layers/insert

Slots a new layer in at a position. Everything there and above moves up one, the layer that was there now rests on the new one, and the layers above are rebuilt.

Body

positioninteger · 1 to 8 · required
Where it goes.
draft, title, descriptionstring
As for adding a layer on top.
Request
curl -X POST https://your-server.example/v1/agent/c/k7m2xq9d/stacks/7/layers/insert \
  -H "Authorization: Bearer arb_live_…" \
  -H "Content-Type: application/json" \
  -d '{
    "draft": "scribe/auth-cookies",
    "title": "Document session cookies",
    "position": 2
  }'
Response200
{
  "restacked": [2, 3],
  "skipped": [1],
  "conflictedAt": null,
  "blocked": [],
  "conflicts": []
}

Reorder the layers

PATCH/v1/agent/c/{identifier}/stacks/{n}/layers/order

Puts the layers in a new order and rebuilds them on one another in that order.

Body

orderinteger[] · 1 to 8 · required
The current positions, listed bottom first in the order wanted.
Request
curl -X PATCH https://your-server.example/v1/agent/c/k7m2xq9d/stacks/7/layers/order \
  -H "Authorization: Bearer arb_live_…" \
  -H "Content-Type: application/json" \
  -d '{ "order": [2, 1, 3] }'
Response200
{
  "restacked": [2, 3],
  "skipped": [1],
  "conflictedAt": null,
  "blocked": [],
  "conflicts": []
}

Fold a layer into the one below

POST/v1/agent/c/{identifier}/stacks/{n}/layers/{pos}/fold

Joins a layer with the one below it, so the two changes become one, and everything above rests on the result. For when two parts turn out to be one idea.

Request
curl -X POST https://your-server.example/v1/agent/c/k7m2xq9d/stacks/7/layers/3/fold \
  -H "Authorization: Bearer arb_live_…"
Response200
{
  "restacked": [2, 3],
  "skipped": [1],
  "conflictedAt": null,
  "blocked": [],
  "conflicts": []
}

Drop a layer

DELETE/v1/agent/c/{identifier}/stacks/{n}/layers/{pos}

Takes a layer out of the stack. The layer above it now rests on the layer below, and the layers above are rebuilt from there.

Request
curl -X DELETE https://your-server.example/v1/agent/c/k7m2xq9d/stacks/7/layers/2 \
  -H "Authorization: Bearer arb_live_…"
Response200
{
  "restacked": [2, 3],
  "skipped": [1],
  "conflictedAt": null,
  "blocked": [],
  "conflicts": []
}

Read what one layer changes

GET/v1/agent/c/{identifier}/stacks/{n}/layers/{pos}/diff

One layer's change against the layer it rests on, so a reviewer sees only that layer's part.

Request
curl https://your-server.example/v1/agent/c/k7m2xq9d/stacks/7/layers/2/diff \
  -H "Authorization: Bearer arb_live_…"
Response200
{
  "base": "scribe/auth-overview",
  "head": "scribe/auth-sessions",
  "documents": [ { "kind": "added", "path": "auth/sessions.md", "additions": 64, … } ],
  "totals": { "documents": 5, "additions": 212, "deletions": 3 },
  "nextCursor": null
}

Keeping it current

Restacking rebuilds each layer on the one beneath it. Each layer is saved on its own, a layer that is already current is skipped, and it stops at the first conflict. Layers above a conflict are blocked and left as they were.

Restack

POST/v1/agent/c/{identifier}/stacks/{n}/restack

Rebuilds the layers on one another. The body may be left out, which restacks from the bottom.

Body

fromPositioninteger · 1 to 8
The lowest layer to rebuild. 1 when absent.

What comes back

restacked, skippedinteger[]
Layers rebuilt, and layers that were already current.
conflictedAt, conflictsinteger · null, array
The layer where it stopped, and what collided there.
blockedinteger[]
Layers above it, not yet looked at.

Refusals

  • 409stack_driftedThe drafts no longer rest on one another as the stack says. Repair the drift first.
Request
curl -X POST https://your-server.example/v1/agent/c/k7m2xq9d/stacks/7/restack \
  -H "Authorization: Bearer arb_live_…"
Response200
{
  "restacked": [2],
  "skipped": [1],
  "conflictedAt": 3,
  "blocked": [4],
  "conflicts": [
    {
      "id": "…",
      "documentId": "…",
      "path": "auth/keys.md",
      "kind": "body",
      "frontmatterKey": null,
      "base": "…",
      "theirs": "…",
      "mine": "…",
      "resolved": false
    }
  ]
}

Layers 1 and 2 are current. Layer 3 conflicts. Layer 4 waits on it.

Catch the whole stack up

POST/v1/agent/c/{identifier}/stacks/{n}/sync

Catches the bottom layer up with the trunk, then restacks everything above it: the one call for “the trunk has moved on”.

Request
curl -X POST https://your-server.example/v1/agent/c/k7m2xq9d/stacks/7/sync \
  -H "Authorization: Bearer arb_live_…"
Response200
{
  "restacked": [2, 3],
  "skipped": [1],
  "conflictedAt": null,
  "blocked": [],
  "conflicts": []
}

Publishing

A layer is never published through its own proposal. It goes through the stack, from the bottom, so the layers above are rebuilt on what landed. Each layer is held to the Concept's review rules separately, and stacking relaxes none of them.

Publish the bottom layer

POST/v1/agent/c/{identifier}/stacks/{n}/layers/{pos}/merge

Publishes one layer to the trunk and rebuilds the rest on it. Needs an editor's standing.

Refusals

  • 409not_mergeableThe layer does not meet the review rules. The problem says which.
  • 409merge_conflictThe trunk moved and the layer now conflicts. The problem carries the conflicts.
  • 409stack_driftedRepair the drift first.
Request
curl -X POST https://your-server.example/v1/agent/c/k7m2xq9d/stacks/7/layers/1/merge \
  -H "Authorization: Bearer arb_live_…"
Response200
{
  "merged": true,
  "trunkSeq": 319,
  "documentsMerged": 3,
  "cascade": {
    "restacked": [2, 3],
    "skipped": [],
    "conflictedAt": null,
    "blocked": [],
    "conflicts": []
  }
}

cascade is what happened to the layers above as they were rebuilt on what landed.

Publish several layers together

POST/v1/agent/c/{identifier}/stacks/{n}/merge

Publishes the bottom layers together as one entry in the trunk's history, so the lot can be reverted in one step. If any of them conflicts, none is published.

Body

layersinteger · 1 to 8
How many, from the bottom. All of them when absent.
messagestring · up to 1,000
The history entry's message.

Refusals

  • 409not_mergeableA layer does not meet the review rules.
  • 409merge_conflictA layer conflicts, so nothing was published. The problem names it in failedAtLayer.
Request
curl -X POST https://your-server.example/v1/agent/c/k7m2xq9d/stacks/7/merge \
  -H "Authorization: Bearer arb_live_…" \
  -H "Content-Type: application/json" \
  -d '{ "layers": 2, "message": "Document sessions and their overview" }'
Response200
{
  "merged": true,
  "layersMerged": 2,
  "trunkSeq": 320,
  "documentsMerged": 8,
  "failedAtLayer": null
}

Dissolve the stack

POST/v1/agent/c/{identifier}/stacks/{n}/unstack

Ends the stack and keeps the work. Each layer's proposal carries on as an ordinary proposal, rebased on the trunk.

Request
curl -X POST https://your-server.example/v1/agent/c/k7m2xq9d/stacks/7/unstack \
  -H "Authorization: Bearer arb_live_…"
Response200
{ "layers": 3 }

Drift

A stack says which draft each layer rests on. If a draft is moved some other way, the two disagree, and that is drift. Publishing or restacking a drifted stack is refused, because it would merge against a base the work was never written on. Reading still works.

Check for drift

GET/v1/agent/c/{identifier}/stacks/{n}/drift

Whether the stack and its drafts agree and, if not, where they part.

Request
curl https://your-server.example/v1/agent/c/k7m2xq9d/stacks/7/drift \
  -H "Authorization: Bearer arb_live_…"
Response200
{
  "diverged": true,
  "layer": 2,
  "expectedBase": "scribe/auth-overview",
  "actualBase": "main",
  "options": ["adopt", "restore", "dissolve"]
}

Repair drift

POST/v1/agent/c/{identifier}/stacks/{n}/drift/resolve

There are three ways out, and the server never picks one, because which is right depends on what was meant.

Body

actionadopt · restore · dissolve · required
adopt takes the drafts as they really are and reorders the stack to match. restore puts the stack's own order back and restacks. dissolve ends the stack and keeps each proposal.
A refused publish or restack names this route in its nextAction, and lists the three choices with where the drafts part.
Request
curl -X POST https://your-server.example/v1/agent/c/k7m2xq9d/stacks/7/drift/resolve \
  -H "Authorization: Bearer arb_live_…" \
  -H "Content-Type: application/json" \
  -d '{ "action": "restore" }'
Response200
{
  "action": "restore",
  "restacked": {
    "restacked": [2, 3],
    "skipped": [1],
    "conflictedAt": null,
    "blocked": [],
    "conflicts": []
  }
}