Proposals
Every change an AI agent wants to make, with the proof FurniOps ran on it. What a proposal holds, how it is proved and rated low or high risk, its statuses, accepting and rejecting it, and the webhooks that announce it.
A proposal (prp_…) is a change an AI agent wants to make, with the evidence for
it. Review them under Catalogue › Proposals, or through the API.
{
"object": "proposal",
"id": "prp_034XqBaL2mRLTZPXyRbaUj",
"catalogue": "cat_034XqBaL2mRLTZPXyRbaUa",
"agent": "categories",
"source": "src_034XqBaL2mRLTZPXyRbaUh",
"status": "proposed",
"risk": "low",
"summary": "File 2 category paths covering 37 products",
"payload": {
"kind": "category_rules",
"rules": [
{
"path": ["Upholstery", "Sectionals"],
"category": "ctg_034XqBaL2mRLTZPXyRbaUk",
"reason": "The path names sectional sofas; the sample titles are L-shaped sofas."
},
{
"path": ["Upholstery", "Loveseats"],
"category": "ctg_034XqBaL2mRLTZPXyRbaUm",
"reason": "Two-seat sofas, by the path and the titles."
}
]
},
"evidence": {
"kind": "category_rules",
"products": 1204,
"filed_before": 1150,
"filed_after": 1187,
"snapshot": "2026-10-06T06:00:02Z"
},
"model": "gemini-3.8-flash",
"cost_micros": 1840,
"failure": null,
"superseded_by": null,
"decided_by": null,
"created_at": "2026-10-06T06:04:19Z",
"decided_at": null,
"applied_at": null
}
| Property | Meaning |
|---|---|
agent | The agent that proposed it. |
source | The source it is about; null when it is about none (a new source from a probe). |
status | Where it stands (below). |
risk | low or high (below). |
summary | What it proposes, in a line. |
payload | The change, by kind: category_rules, mapping, source or triage. |
evidence | The proof's result, by the same kind. |
model, cost_micros | The model that proposed it, and what asking it cost in micro-USD. |
failure | Why it failed its proof, or could not be applied. |
superseded_by | The newer proposal about the same thing that replaced it. |
decided_by, decided_at, applied_at | Who decided it (a person, or the agent under auto_low_risk) and when. |
New kinds come with new agents: show a kind you do not know by its summary.
The proof
Before anyone sees a proposal, FurniOps proves it against the source as it is now, in code. A change that makes things worse fails there and is never offered.
| Kind | Proved on | It fails when |
|---|---|---|
category_rules | The source's current products. | A rule names a category the taxonomy lacks, names a path twice, or sits on a path that already has a rule; or it files no product that was not filed before. |
mapping | Rows of the source's latest file, mapped with and without the columns. | The file's headers changed since; a column is not one the mapping left unplaced (a person's "left out" included); the columns are not a valid mapping together; or they add field problems, empty a column imported now, or fill nothing. |
source | The probe's report. | There is a draft only when FurniOps can run the site's source now: a public feed of a platform it reads, and no wall. |
triage | The run as recorded. | A cited issue is not the run's own, or the run is no longer the source's latest. |
The evidence shows the counts the proof made: products filed before and after, field problems
before and after and the fields gained, the probe's platform and effort, or the issues explained.
Risk
The proof also rates the change. High-risk proposals always wait for a person, whatever the agent's autonomy.
| Kind | Low risk | High risk |
|---|---|---|
category_rules | Every product it files was unfiled. | It moves products out of a category a person's rule gave them. |
mapping | It adds columns to an already confirmed mapping, and none of them keys or groups products. | It would confirm a mapping for the first time (which imports the source), or it maps a column that keys products (which regroups everything the source imports). |
source | Never. | Always: a new source, and its licence basis is your call. |
triage | Always. | Never. A note is read, then dismissed; it is never applied. |
Statuses
status | Dashboard tab | Meaning |
|---|---|---|
proposed | Waiting | Waiting for a person. |
applied | Applied | Made: accepted by a person, or applied at once as low risk under auto_low_risk. |
rejected | Rejected | A person said no (or dismissed a triage note). |
failed | Failed | Its proof found it makes things worse, or applying it failed; see failure. |
shadow | Shadow | Recorded while the agent runs in shadow. Nobody is asked. |
superseded | Superseded | A newer proposal about the same thing replaced it. |
GET /v1/proposals lists those waiting for a person by
default, newest first; filter by status, agent and source. Reading needs agent:read, which
an API key can hold.
Decide
- Accept and apply (
POST /v1/proposals/{id}/accept): FurniOps proves the change again, then applies it through the same service a person uses (category rules, mappings, sources), as you. A proposal that no longer holds answers409. - Reject (
POST /v1/proposals/{id}/reject), with an optional reason for the agent's record. A triage note is dismissed this way.
Deciding needs agent:write, and accepting also needs the change's own permission
(sources:write): owners and admins, signed in. Neither API keys nor OAuth apps can hold
agent:write, so proposals are decided in the dashboard.
A rejection holds. An agent never proposes the same change again once a person rejected it. The same change is recognised however the agent words it: by the paths and categories, the columns, fields and settings, the source's fields, or the cited issues, never by its reasons.
Webhooks
Two events announce proposals to your webhook endpoints:
| Event | Sent when |
|---|---|
proposal.created | An agent proposed a change that passed its proof and waits for a person. |
proposal.applied | A proposal was applied: accepted by a person, or at once as low risk under auto_low_risk. |
Each carries the full proposal. They belong to your organisation, not to a catalogue's records: only webhooks deliver them (not the change feed or the stream), and shadow proposals raise none.
AI agents
FurniOps' AI agents file categories, repair mappings, draft new sources and explain failed runs. They never change your catalogue themselves. What each agent does, autonomy from off to applying low-risk changes, daily budgets, and the shadow record.
Sync a catalogue
Keep a complete, correct copy of your FurniOps catalogue in your own database, with a backfill, the change feed, and webhooks for speed.