Working with proposals

How the proposal mechanism looks from the agent side of the wire. The rule underneath everything: an Ajan token's mutation is recorded, never executed — nothing you do is visible in the store until the owner applies it.

202 means recorded

A mutation through any surface — POST /v1/commands, a propose-policy route, an MCP tool — answers HTTP 202 with the normal outcome shape plus proposed: true and auditId: null:

{ "ok": true, "proposed": true, "proposalId": "prp_…", "itemId": "pri_…", "position": 3, "preview": { "wouldChange": [...], "warnings": [] } }

auditId: null is the tell — "no audit row ⇔ nothing applied" is a platform invariant, so you can distinguish proposed from applied without guessing. Over MCP, results of recorded calls start with PROPOSED (not applied). The recorded preview is the same dry-run the owner will see; read its wouldChange and warnings to know what you actually proposed.

You have one open proposal per token; the first recorded mutation creates it, later ones append items in order (max proposalMaxItems items). Items keep their order at apply — sequence your calls the way they must run (create the product before pricing it).

Notes

Every recorded call accepts a note (≤500 chars) — the rationale the owner sees next to that item in Öneriler. Use it: "Fiyat listesindeki yeni KDV oranına göre güncelleme" reviews faster than a bare diff.

Submitting

When the change set is complete, proposal.submit with a title and a summary. The proposal moves to submitted, the owner is mailed a review link, and it expires unreviewed after proposalSubmittedDays days. An empty proposal cannot be submitted. From the CLI: propose.

While a proposal is open you can keep appending; after submit, a further mutation opens a fresh proposal.

Drift: stale items

At apply time each item is re-previewed against the current world and its recorded preview hash must match. If the store moved underneath you — the owner edited the same price, an order shipped, the live design advanced — that item goes stale, the proposal pauses, and the owner decides: skip the item, or accept the new preview and continue. You do not resolve drift; the owner does. What you can do is keep proposals small and submit promptly — drift is a function of time.

Failures behave the same way: apply stops at the first failing item and never rolls back applied ones (each applied item is an ordinary audited command).

Watching status

Withdrawing and expiry

proposal.withdraw drops your own proposal in open, submitted or paused — use it when you discover a mistake rather than submitting a correction on top. Open proposals idle out after proposalOpenIdleDays days; submitted ones expire after proposalSubmittedDays days; a revoked token's open proposal is withdrawn automatically. Expired or withdrawn proposals apply nothing.

Generated from the live platform registries at build time — reference pages cannot go stale. Markdown variant: /agents-proposals.md