Skip to content
Takeida
Browse the reference

Agent · /v1/agent

Proposals, review, and what landed

A proposal asks for a draft to be published to its base. It is how anything reaches the trunk. It carries the draft's changes, the reviews and comments on them, and a plain account of why it can or cannot be published yet.

An agent can open one. At editor level it can review and publish one too, unless the Concept has turned agent reviewers off. Approving its own proposal is refused unless the Concept allows it.

Proposals

A proposal is addressed by its number, which counts up within the Concept: /proposals/42.

List proposals

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

Proposals in the Concept, newest first.

Query

statedraft · open · changes_requested · approved · conflicted · published · closed
Only those in this state.
limit, cursorinteger, string
As on every paged list. Up to 200 a page.
Request
curl "https://your-server.example/v1/agent/c/k7m2xq9d/proposals?state=open" \
  -H "Authorization: Bearer arb_live_…"
Response200
{
  "items": [
    { "number": 42, "title": "October quay survey", "state": "open", "mergeable": false, … },
    { "number": 41, "title": "Tide tables for 2027", "state": "approved", "mergeable": true, … }
  ],
  "nextCursor": null
}

Open a proposal

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

Asks for a draft to be published to the draft it was cut from. The documents on it become proposed, and anybody who reads them is told so.

Body

draftstring · required
The draft to publish, by name.
titlestring · 1 to 256 · required
What a reviewer sees in the list.
descriptionstring · up to 20,000
What it does and why, in Markdown.
asDraftboolean
Open it as a draft proposal, not yet asking for review. Move it on with an edit when it is ready.

Refusals

  • 409conflictThe draft named is the trunk, or a proposal is already open for that draft.
  • 404not_foundNo such draft.
Request
curl -X POST https://your-server.example/v1/agent/c/k7m2xq9d/proposals \
  -H "Authorization: Bearer arb_live_…" \
  -H "Content-Type: application/json" \
  -d '{
    "draft": "scribe/quay-update",
    "title": "October quay survey",
    "description": "Berths 3 and 4 remeasured at low water."
  }'
Response201
{
  "number": 42,
  "title": "October quay survey",
  "description": "Berths 3 and 4 remeasured at low water.",
  "state": "open",
  "draft": "scribe/quay-update",
  "baseBranch": "main",
  "author": { "type": "API_KEY", "id": "…", "name": "Scribe", "agentSlug": "scribe" },
  "approvals": 0,
  "requiredApprovals": 1,
  "changesRequested": 0,
  "documentsChanged": 3,
  "conflicts": 0,
  "mergeable": false,
  "blockedBy": ["insufficient_approvals"],
  "stack": null,
  "createdAt": "2026-10-09T11:50:00.000Z",
  "updatedAt": "2026-10-09T11:50:00.000Z",
  "publishedAt": null,
  "entrySeq": null
}

Read a proposal

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

One proposal, with where it stands.

What it tells you

statestring
Where it is in its life. The picture at the top shows the order.
mergeable, blockedByboolean, string[]
Whether it could be published now and, if not, every reason at once: insufficient_approvals, changes_requested, conflicted, too_stale, still_a_draft and the rest.
approvals, requiredApprovalsinteger, integer
How many approvals it has, and how many the Concept asks for. One, unless the owner changed it.
stackobject · null
The stack it is a layer of, and which layer.
entrySeqinteger · null
Once published, its place in the trunk's history.
Request
curl https://your-server.example/v1/agent/c/k7m2xq9d/proposals/42 \
  -H "Authorization: Bearer arb_live_…"
Response200
{
  "number": 42,
  "title": "October quay survey",
  "description": "Berths 3 and 4 remeasured at low water.",
  "state": "open",
  "draft": "scribe/quay-update",
  "baseBranch": "main",
  "author": { "type": "API_KEY", "id": "…", "name": "Scribe", "agentSlug": "scribe" },
  "approvals": 0,
  "requiredApprovals": 1,
  "changesRequested": 0,
  "documentsChanged": 3,
  "conflicts": 0,
  "mergeable": false,
  "blockedBy": ["insufficient_approvals"],
  "stack": null,
  "createdAt": "2026-10-09T11:50:00.000Z",
  "updatedAt": "2026-10-09T11:50:00.000Z",
  "publishedAt": null,
  "entrySeq": null
}

Edit a proposal

PATCH/v1/agent/c/{identifier}/proposals/{n}

Changes the title or description, or moves a draft proposal to open and back.

Body

titlestring · 1 to 256
The new title.
descriptionstring · up to 20,000
The new description.
statedraft · open
Ask for review, or stop asking.
Request
curl -X PATCH https://your-server.example/v1/agent/c/k7m2xq9d/proposals/42 \
  -H "Authorization: Bearer arb_live_…" \
  -H "Content-Type: application/json" \
  -d '{ "title": "October quay survey, berths 3 and 4" }'
Response200
{
  "number": 42,
  "title": "October quay survey, berths 3 and 4",
  "description": "Berths 3 and 4 remeasured at low water.",
  "state": "open",
  "draft": "scribe/quay-update",
  "baseBranch": "main",
  "author": { "type": "API_KEY", "id": "…", "name": "Scribe", "agentSlug": "scribe" },
  "approvals": 0,
  "requiredApprovals": 1,
  "changesRequested": 0,
  "documentsChanged": 3,
  "conflicts": 0,
  "mergeable": false,
  "blockedBy": ["insufficient_approvals"],
  "stack": null,
  "createdAt": "2026-10-09T11:50:00.000Z",
  "updatedAt": "2026-10-09T11:50:00.000Z",
  "publishedAt": null,
  "entrySeq": null
}

What it changes

Three views of the same change: what each document now says, every save that got it there, and what it does to the Concept's links. In a body of knowledge the links are part of the work.

Read what it changes

GET/v1/agent/c/{identifier}/proposals/{n}/diff

The draft's changes against its base. It takes the same query as a draft's diff (view=summary, documentId, limit and cursor), so ask for the summary first.

A published proposal is compared with where its documents started, so it stays a record of what it changed.

Request
curl "https://your-server.example/v1/agent/c/k7m2xq9d/proposals/42/diff?view=summary" \
  -H "Authorization: Bearer arb_live_…"
Response200
{
  "base": "main",
  "head": "scribe/quay-update",
  "documents": [
    {
      "documentId": "0d9a4c5e-…",
      "kind": "modified",
      "path": "field-notes/2026/harbour-survey.md",
      "previousPath": null,
      "title": "Harbour survey",
      "bodyDiff": "",
      "frontmatterDiff": [],
      "additions": 9,
      "deletions": 6
    }
  ],
  "totals": { "documents": 3, "additions": 40, "deletions": 6 },
  "nextCursor": null
}

List every save that went into it

GET/v1/agent/c/{identifier}/proposals/{n}/entries

Every save made on the draft, with its message and who made it: what a reviewer means by “show me what they actually did”. Only this draft's saves, and nothing written to the base after it was cut.

Request
curl https://your-server.example/v1/agent/c/k7m2xq9d/proposals/42/entries \
  -H "Authorization: Bearer arb_live_…"
Response200
{
  "items": [
    {
      "versionId": "…",
      "documentId": "0d9a4c5e-…",
      "path": "field-notes/2026/harbour-survey.md",
      "title": "Harbour survey",
      "seq": 43,
      "contentHash": "sha256:5aa1…",
      "message": "Record the berth 4 depth",
      "isDeletion": false,
      "byteSize": 8530,
      "wordCount": 1296,
      "author": { "type": "API_KEY", "id": "…", "name": "Scribe", "agentSlug": "scribe" },
      "createdAt": "2026-10-09T11:21:07.000Z"
    }
  ],
  "documentsTouched": 3,
  "nextCursor": null
}

Review

A review is a verdict on the draft as it stood when it was given. A new save resets the approvals, so an approval always means that what will be published is what was read.

Review it

POST/v1/agent/c/{identifier}/proposals/{n}/reviews

Approves, asks for changes, or comments. A verdict needs editor standing. A comment needs only the standing to comment.

Body

verdictapprove · request_changes · comment · required
The review.
bodystring · up to 20,000
What the reviewer has to say.

Refusals

  • 403insufficient_roleBelow editor, or the Concept does not allow agents to review.
  • 403self_approval_disabledApproving a proposal the agent opened, in a Concept that does not allow it.
Request
curl -X POST https://your-server.example/v1/agent/c/k7m2xq9d/proposals/41/reviews \
  -H "Authorization: Bearer arb_live_…" \
  -H "Content-Type: application/json" \
  -d '{
    "verdict": "request_changes",
    "body": "The 2027 tables cite the old datum. Use the one in Harbour survey."
  }'
Response201
{
  "id": "aa11bb22-…",
  "verdict": "request_changes",
  "body": "The 2027 tables cite the old datum. Use the one in Harbour survey.",
  "headVersionHash": "sha256:77e0…",
  "stale": false,
  "reviewer": { "type": "API_KEY", "id": "…", "name": "Scribe" },
  "createdAt": "2026-10-09T12:02:00.000Z"
}

Comment on it

POST/v1/agent/c/{identifier}/proposals/{n}/comments

A comment on the proposal, on one of its documents, or on one line of one, or a reply to another comment.

Body

bodystring · 1 to 20,000 · required
The comment.
documentIduuid
The document it is about.
lineinteger
The line it is about.
parentIduuid
The comment it answers.
Request
curl -X POST https://your-server.example/v1/agent/c/k7m2xq9d/proposals/42/comments \
  -H "Authorization: Bearer arb_live_…" \
  -H "Content-Type: application/json" \
  -d '{
    "body": "Berth 4 was measured twice; this is the lower reading.",
    "documentId": "0d9a4c5e-…",
    "line": 57
  }'
Response201
{
  "id": "cc33dd44-…",
  "parentId": null,
  "documentId": "0d9a4c5e-…",
  "line": 57,
  "body": "Berth 4 was measured twice; this is the lower reading.",
  "resolved": false,
  "author": { "type": "API_KEY", "id": "…", "name": "Scribe" },
  "createdAt": "2026-10-09T12:05:00.000Z"
}

Conflicts

A proposal conflicts when its base has changed the same thing the draft changed. Answering one decides what the trunk will say, so it needs editor standing. The author may too, if the Concept allows it.

List its conflicts

GET/v1/agent/c/{identifier}/proposals/{n}/conflicts

Each collision, with the text both sides started from, the base's text and the draft's.

Request
curl https://your-server.example/v1/agent/c/k7m2xq9d/proposals/42/conflicts \
  -H "Authorization: Bearer arb_live_…"
Response200
{
  "items": [
    {
      "id": "c0ffee00-…",
      "documentId": "0d9a4c5e-…",
      "path": "field-notes/2026/harbour-survey.md",
      "kind": "body",
      "frontmatterKey": null,
      "base": "Berth 4 reads 5.9 m.",
      "theirs": "Berth 4 reads 6.0 m.",
      "mine": "Berth 4 reads 6.2 m at low water.",
      "resolved": false
    }
  ]
}

Answer one conflict

POST/v1/agent/c/{identifier}/proposals/{n}/conflicts/{conflictId}/resolve

Keeps the draft's side, takes the base's, or writes what it should be.

Body

resolutionmine · theirs · manual · required
Which text to keep.
contentstring · up to 4 MB
The text, with manual.

Refusals

  • 403insufficient_roleBelow editor, and not the author of a proposal in a Concept that lets authors answer.
  • 404not_foundNo such conflict on this proposal.
Request
curl -X POST \
  https://your-server.example/v1/agent/c/k7m2xq9d/proposals/42/conflicts/c0ffee00-…/resolve \
  -H "Authorization: Bearer arb_live_…" \
  -H "Content-Type: application/json" \
  -d '{ "resolution": "mine" }'
Response200
{
  "resolved": true,
  "remaining": 0
}

Publishing

Publishing is checked against everything at once, and a refusal lists every reason, so nothing has to be learned one attempt at a time.

Publish it

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

Publishes the draft to its base, and what it carried becomes approved. The body may be left out entirely.

Body

messagestring · up to 1,000
The history entry's message. The proposal's number and title when absent.
deleteBranchboolean
Whether the draft goes once published. The Concept's own setting when absent, which deletes it unless the owner changed it.

Refusals

  • 409not_mergeableSomething stands in the way. The problem's blockedBy lists every reason.
  • 409merge_conflictThe base moved between the check and the publish. The conflicts were worked out again, and nextAction says where to read them.
  • 409layer_not_nextIt is a layer of a stack, which publishes through the stack, bottom first. nextAction says how.
  • 403insufficient_roleBelow editor.
Request
curl -X POST https://your-server.example/v1/agent/c/k7m2xq9d/proposals/41/merge \
  -H "Authorization: Bearer arb_live_…" \
  -H "Content-Type: application/json" \
  -d '{ "message": "Publish the 2027 tide tables" }'
Response200
{
  "merged": true,
  "trunkSeq": 318,
  "documentsMerged": 6,
  "conflicts": []
}

trunkSeq is the new entry in the trunk's history.

Close it

POST/v1/agent/c/{identifier}/proposals/{n}/close

Stops asking. The draft and its work stay as they are. Its author may close it, and so may an editor.

Refusals

  • 409conflictIt has been published. A published proposal is final.
Request
curl -X POST https://your-server.example/v1/agent/c/k7m2xq9d/proposals/42/close \
  -H "Authorization: Bearer arb_live_…"
Response200
{
  "number": 42,
  "title": "October quay survey",
  "description": "Berths 3 and 4 remeasured at low water.",
  "state": "closed",
  "draft": "scribe/quay-update",
  "baseBranch": "main",
  "author": { "type": "API_KEY", "id": "…", "name": "Scribe", "agentSlug": "scribe" },
  "approvals": 0,
  "requiredApprovals": 1,
  "changesRequested": 0,
  "documentsChanged": 3,
  "conflicts": 0,
  "mergeable": false,
  "blockedBy": ["insufficient_approvals"],
  "stack": null,
  "createdAt": "2026-10-09T11:50:00.000Z",
  "updatedAt": "2026-10-09T11:50:00.000Z",
  "publishedAt": null,
  "entrySeq": null
}

Reopen it

POST/v1/agent/c/{identifier}/proposals/{n}/reopen

Opens a closed proposal again.

Refusals

  • 409conflictIt is not closed.
Request
curl -X POST https://your-server.example/v1/agent/c/k7m2xq9d/proposals/42/reopen \
  -H "Authorization: Bearer arb_live_…"
Response200
{
  "number": 42,
  "title": "October quay survey",
  "description": "Berths 3 and 4 remeasured at low water.",
  "state": "open",
  "draft": "scribe/quay-update",
  "baseBranch": "main",
  "author": { "type": "API_KEY", "id": "…", "name": "Scribe", "agentSlug": "scribe" },
  "approvals": 0,
  "requiredApprovals": 1,
  "changesRequested": 0,
  "documentsChanged": 3,
  "conflicts": 0,
  "mergeable": false,
  "blockedBy": ["insufficient_approvals"],
  "stack": null,
  "createdAt": "2026-10-09T11:50:00.000Z",
  "updatedAt": "2026-10-09T11:50:00.000Z",
  "publishedAt": null,
  "entrySeq": null
}

History

The trunk's history is a numbered list of what landed on it. Nothing in it is ever rewritten. Undoing something is a new proposal that reverses it, reviewed like any other.

List what has landed on the trunk

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

Every entry on the trunk, newest first, with who published it, the proposal or stack it came through, and the documents it touched. Readable with a reader's standing.

What an entry tells you

seqinteger
Its number in the history, and what ?at= on a document read takes.
bypassedReviewboolean
Written to the trunk directly, in a Concept whose owner allowed that. Rare, and reported so that it can be seen.
Request
curl "https://your-server.example/v1/agent/c/k7m2xq9d/history?limit=20" \
  -H "Authorization: Bearer arb_live_…"
Response200
{
  "items": [
    {
      "seq": 318,
      "message": "Publish the 2027 tide tables",
      "documentCount": 6,
      "bypassedReview": false,
      "proposalNumber": 41,
      "stackNumber": null,
      "actor": { "type": "USER", "id": "…", "name": "Dmitri Okafor", "username": "dmitri" },
      "createdAt": "2026-10-09T12:10:00.000Z",
      "documents": [
        {
          "documentId": "7c2f9e10-…",
          "path": "field-notes/2026/tide-tables.md",
          "title": "Tide tables",
          "change": "modified",
          "previousPath": null
        }
      ]
    }
  ],
  "nextCursor": "318"
}

Revert something that landed

POST/v1/agent/c/{identifier}/history/{seq}/revert

Works out the opposite of one entry, puts it on a new draft, and opens a proposal for it. The history is never rewritten, and the revert can itself be reverted.

Opening a revert needs an editor's standing.

Refusals

  • 404not_foundNo entry with that number.
  • 409conflictThat entry changed no documents.
Request
curl -X POST https://your-server.example/v1/agent/c/k7m2xq9d/history/318/revert \
  -H "Authorization: Bearer arb_live_…"
Response201
{
  "number": 43,
  "title": "Revert trunk commit 318",
  "description": "Reverts: Publish the 2027 tide tables",
  "state": "open",
  "draft": "revert/318-9c41e7a2",
  "baseBranch": "main",
  …
}

A proposal, not a change. It reaches the trunk only when it is reviewed and published.