Getting it into your agent
It runs from inside its repository, so the clone comes first — what it calls does not travel with the file alone.
git clone --depth 1 https://github.com/logly/mureonpx agentmods add skills/logly/mureo/_mureo-state-schemaWrote this? Show the measurements
A badge with what this costs and how it scanned, read live from this page, so it follows the numbers instead of freezing them. Markdown for a README, HTML for a documentation site or a project page.
[](https://agentmods.dev/skills/logly/mureo/_mureo-state-schema)<a href="https://agentmods.dev/skills/logly/mureo/_mureo-state-schema"><img src="https://agentmods.dev/badge/skills/logly/mureo/_mureo-state-schema/github.svg" alt="Measured on agentmods" height="20"></a>Or the 80×15 button, for a site that already has a row of RSS and ATOM ones. Only the verdict fits; the numbers stay here.
<a href="https://agentmods.dev/skills/logly/mureo/_mureo-state-schema"><img src="https://agentmods.dev/badge/skills/logly/mureo/_mureo-state-schema.svg" alt="Reviewed on agentmods" width="80" height="20"></a>What it costs to keep this loaded
Counted locally with the o200k_base tokenizer, which is exact for GPT models; Claude uses its own tokenizer and its counts differ. Treat this as one consistent yardstick across the catalogue rather than a bill. Prices are per million input tokens.
| Model | Per session | Once invoked |
|---|---|---|
| Fable 5.1 | $0.00022 | $0.03018 |
| Opus 5.5 | $0.00009 | $0.01207 |
| Sonnet 5.5 | $0.00004 | $0.00604 |
| Haiku 4.5 | $0.00002 | $0.00302 |
Grade A, and why
_mureo-state-schema scanned grade A with 0 findings against 26 rules in 11 categories — prompt injection, anti-refusal, data exfiltration, privilege escalation, supply chain, agent snooping, system-prompt leakage, SSRF and excessive agency — measured today.
A static scan of the body, not an audit. Every finding is printed with the line that produced it so you can judge whether it matters here. A mod is markdown that instructs an agent; that is exactly why what it instructs is worth reading.
Nothing flagged
None of the 26 patterns this scan looks for appear in this file: no shell pipes, no recursive deletes, no credential paths, no hidden text, no instruction-override or anti-refusal phrasing, no agent-config snooping. That is not a guarantee, it is the absence of the things that are checkable.
How it starts
The opening of the file, as written. The whole thing — 190 lines — stays where its author put it; the contents beside it link to each section on GitHub.
mureo STATE.json Schema
PREREQUISITE: Read
../_mureo-shared/SKILL.mdfor auth, global flags, and security rules.
This file is the STATE.json schema and the status vocabulary contract every skill follows when it writes STATE.json with Write on Code (the bulk-snapshot flows sync-state / daily-check); on Desktop / Cowork the mureo_state_* MCP tools apply it for you. The Success Response it refers to as "above" is ../_mureo-shared/SKILL.md → Output Format.
STATE.json Schema (when writing on Code via Write)
Tool output ≠ STATE.json. The Success Response above is what a vendor MCP tool returns — a campaign there is
{"campaign_id", "name", "status", …}. STATE.json'sCampaignSnapshotis a different shape: it requirescampaign_name, notname. When you hand-write STATE.json withWriteon Code, map the tool-outputname→campaign_name(andid→campaign_id), and always set the platform'saccount_id. On Desktop / Cowork themureo_state_*MCP tools serialize this canonical shape for you, so the mapping only matters on the CodeWritepath.
A campaign or platform missing a required field below, or a decisions record
mureo cannot read, is not rejected: it is kept as written and re-emitted
unchanged on every later write (a decision record mureo can read keeps its
extra keys too). But it reads with the missing values empty (a
campaign without campaign_name shows unnamed), and an unreadable decision
record is kept opaque — ignored by every reader — so get these exact names
right:
- Campaign snapshot (root
campaigns[]andplatforms[<p>].campaigns[]) — required:campaign_id(str),campaign_name(str),status(str). Optional:bidding_strategy_type,daily_budget,campaign_goal,notes,device_targeting, andmetrics(the per-campaign performance object:spend/impressions/clicks/conversions/cpa/ctr/ …). - Platform entry (
platforms[<platform>]) — required:account_id(str; use""only if genuinely unknown — an empty id is treated as unknown everywhere, so it never joins with another entry and never matches a per-account override). A placeholder —unknown,none,null,n/a,undefined,tbd, in any case — is read as unknown too, but only so a document that already carries one does not join two entries;""is still the one spelling to write. The MCP write tools read""the same way, but onlymureo_state_platform_not_collected_setaccepts it: a platform whose figures you DID collect knows which account they came from, so every other one still requires a real id. Pluscampaigns[]and the rollups the dashboard actually renders:totals,metrics_period,periods[<window>]. A rollup carries the canonical metrics (spend,impressions,clicks,conversions,cpa,ctr, the Metaresult_indicator) plus two statements ABOUT them, which are different facts and never stand in for each other:fetched_at(when the rollup was WRITTEN — ISO-8601, stamped for you by themureo_state_*write tools when you omit it) andperiod_end(the last calendar date the figures COVER —YYYY-MM-DD, in the ad account's own timezone).period_endis optional and yours to supply: the server cannot derive it without the account's timezone, and a coverage date off by one day is worse than none. A window written without it is judged stale on its write time alone, which is how a card goes on showing two-day-old numbers under a fresh-looking update time. Each window states its own — never copy one window's date onto another.metrics_periodand everyperiodskey must be one of mureo's three windows —YESTERDAY/LAST_7_DAYS/LAST_30_DAYS. The set is closed: any other token is refused rather than stored (and never rounded onto a neighbouring window), because a window nothing reads makes a write that reports success over a dashboard that never moves. One ad account has exactly one platform key. Before writing an entry, check whether thataccount_idis already stored under a different key and write to that key instead — the reporting view aggregates across platforms, so two keys for one account inflate spend / conversions / CPA together. (The read side detects that case and withholds the client total rather than showing the inflated one, and separately reports a key it cannot resolve to any platform — but detection is not repair, so do not treat it as a licence to write the duplicate.) Themureo_state_*write tools now reject a write that would create the second key (naming both keys and the account); on the CodeWritepath the same rule is yours to honour, and a wholesaleWritethat lands a duplicate is logged as a warning rather than blocked. Pass the key exactly — a key with surrounding whitespace (" google_ads") is a different key, and is rejected on create rather than silently stripped. Never invent or abbreviate a platform key: creating an entry under a key that is neither a first-class ad-platform key, nor a platform an installed plugin registered (its entry-point name —logly_ads_context, notlogly_ads), nor aplugin:<dist>:<provider>key is rejected, with the accepted keys listed in the error. Use the canonicalplugin:<dist>:<provider>form when the bridge that owns a snapshot is not installed on this machine. If a document already carries the duplicate pair, writes to the existing keys still succeed — mureo never merges or deletes an entry, because the two typically hold different partial figures; reconciling them is the operator's call. Changing an existing key'saccount_idto one another key already holds is rejected for the same reason (it creates the duplicate just as surely); pointing a key at an account nobody else holds is fine. - Top-level — required:
last_synced_at(ISO-8601 string, stamped to now by every campaign/metrics/report write). It drives the dashboard's "Synced N ago" freshness; a missing or stale value makes the data read as not-recently-synced.mureo_state_upsert_campaign/_platform_metrics_set/_report_setset it for you (_action_log_appenddoes not); on the CodeWritepath you must set it yourself. history/beside STATE.json (#758) — thedailydays trimmed past the 35-day retention cap and every version of every report kind are archived there by themureo_state_*write tools (history/daily/<YYYY-MM>.json,history/reports/<kind>.jsonl) while STATE.json keeps only the current window and the latest report, so never hand-write, prune or carry over those files on the CodeWritepath. Read them withmureo_history_query(sources: ["daily"]/["reports"]), never by opening the files yourself.- Top-level
batches(declared bulk change sets, #549) — carry it over verbatim on the CodeWritepath, together with eachaction_logentry'sbatch_id. Dropping either detaches a change set from its members, which is precisely the "reconstruct what I did from memory" state batches exist to remove. A record with noended_atis an OPEN batch; do not invent, close or renumber one by hand — usemureo_batch_begin/mureo_batch_end. action_logprovenance (origin/external_id/occurred_at, #545) — carry these over verbatim on the CodeWritepath.originabsent means mureo made the change;origin: "external"means mureo only observed it. Droppingoriginsilently promotes an observed change into one mureo claims it made (and could offer to roll back); droppingexternal_idmakes the next import record the same change again. Never addoriginto an entry that did not have it, and never write these three by hand for a platformmureo_external_changes_importcovers.
What this file has done since we first saw it
Hashed on every crawl. A supply-chain change to an agent config is a question of when, not whether, so the history is kept rather than the latest state alone.
- today Changed 6d5181715e51
- yesterday First seen · 190 lines · 22 tokens per session scan A ecace21eecab
_mureo-state-schema is a skill published in the GitHub repository logly/mureo (51 stars, last pushed today), licensed Apache-2.0. It adds 22 tokens to every session and 3,018 once invoked, about $0.0001 per session on Opus 5.5. A static security scan graded it A with 0 findings. No closer match exists in the catalogue, so it is treated as the original; first seen 2026-10-24.
Other skills, from other repositories
adcp-advertising
Automate advertising campaigns with AI. Create ads, buy media, manage ad budgets, discover ad inventory, run display ads, video ads, CTV campaigns, and optimize ad performance. Perfect for marketing automation, programmatic advertising, media buying, ad management, campaign optimization, creative management, and…
adspirer-ads-agent
Adspirer — AI-powered advertising and performance marketing agent. Manage Google Ads, Meta Ads (Facebook & Instagram), LinkedIn Ads, and TikTok Ads via natural language. 100+ tools for paid media campaign creation, live performance analysis, PPC keyword research with real CPC data, budget optimization, ad creative…
google-ads-manager
Google Ads campaign management - campaign setup, keyword research, bid optimization, and performance reporting.
ads-copywriter
Multi-platform ad copy generation for Google Ads, Meta/Facebook, TikTok, LinkedIn with A/B testing variants.
adspirer-ads-agent
Adspirer — AI-powered advertising and performance marketing agent. Manage Google Ads, Meta Ads (Facebook & Instagram), LinkedIn Ads, and TikTok Ads via natural language. 400+ tools for paid media campaign creation, live performance analysis, PPC keyword research with real CPC data, budget optimization, ad creative…
adcp-advertising
Automate advertising campaigns with AI. Create ads, buy media, manage ad budgets, discover ad inventory, run display ads, video ads, CTV campaigns, and optimize ad performance. Perfect for marketing automation, programmatic advertising, media buying, ad management, campaign optimization, creative management, and…