mureo_decision_record
Record a proposed decision with its rationale and metrics before surfacing it, so the reasoning survives the session and later links to the change made.
Instructions
Record a decision so the reasoning survives the session. Use it only when you want to PROPOSE first: record status='proposed' BEFORE you surface the proposal, with the figures you judged it on in metrics, your reasoning in rationale and the effect you expect in expected. When the operator approves, make the change and pass the proposal's decision_id on the change-making call: it becomes adopted and is linked to the change. When the operator turns it down or postpones it, record status='rejected' / 'deferred' with supersedes set to the proposal's decision_id — the section is APPEND-ONLY, so a status change is a new record, never an edit. A change made without a proposal needs no record here: pass reason and expected on the change-making call and mureo records the decision itself. Never write an 'adopted' record for a change afterwards — that leaves two decisions for one change. display.proposals is the SCREEN — one moment, replaced whole on every dashboard write; this is the RECORD. decision_id and recorded_at are minted by the server; do not compute either. Every bound below refuses the write rather than truncating it.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| path | No | Optional path to STATE.json. Defaults to STATE.json in the MCP server's current working directory. Paths outside it are refused. | |
| title | Yes | What is being decided, in one line (e.g. 'Pause the generic ad group in Search_Lead-Gen'). | |
| status | Yes | Where the decision stands. 'proposed' before the operator has answered; 'rejected' / 'deferred' afterwards, with `supersedes` set. An approval is recorded by passing the proposal's `decision_id` on the change-making call, not here. 'deferred' is not 'rejected' — 'not now' and 'no' call for different behaviour next week. | |
| metrics | No | The figures the decision was judged on, as they stood THEN (e.g. {"cpa_7d": 5200, "conversions_7d": 45}). At most 20 keys, each value a string, number, boolean or null — a nested object is refused, and so is a string longer than 200 characters (a figure that needs a sentence belongs in `rationale`). Without them a rationale read next month against today's numbers is unfalsifiable. | |
| batch_id | No | The declared change set this decision concerns. A CLOSED batch is fine — the verdict on a bulk pass is normally recorded after it finished. | |
| expected | No | What the decision should move, judged when the change it leads to is evaluated (e.g. [{"metric": "cpa", "direction": "down", "target": 4500}]). The verdict is read off one primary metric: a single effect is primary by itself; with several, mark exactly one "primary": true or the record is refused (expected_primary_required). Required for 'proposed' / 'adopted' when ops history is enabled. | |
| platform | No | Platform the decision is about (google_ads / meta_ads / ...), when it is about one. | |
| entity_id | No | The entity's id. Must be given together with `entity_type`. | |
| rationale | Yes | Why — the evidence you acted on and the effect you expect. This is the payload: nothing downstream can reconstruct it, and you are the last point at which it exists. | |
| supersedes | No | The `decision_id` of the record this one updates. Required in practice for any status other than the first 'proposed', and validated: it must name a decision already on record. | |
| campaign_id | No | Campaign the decision is about, if any. | |
| entity_type | No | Sub-campaign entity kind (ad_group / ad_set / placement / ...). Must be given together with `entity_id`. | |
| related_actions | No | Positional indices into the full action_log of the entries this decision produced. Validated against the log — an index past its end is refused. |