Getting it into your agent
One page per mod, every tool's command on it. A separate URL per tool would split the same page into five that compete with each other.
npx agentmods add instructions/logly/mureo/agents-mdgit clone --depth 1 https://github.com/logly/mureoWhat 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 | $0.10087 | $0.10087 |
| Opus 5 | $0.05044 | $0.05044 |
| Sonnet 5 | $0.02017 | $0.02017 |
| Haiku 4.5 | $0.01009 | $0.01009 |
Grade A, and why
mureo AGENTS.md 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 2d ago.
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 — 505 lines — stays where its author put it; the contents beside it link to each section on GitHub.
AGENTS.md
Guidelines for AI agents contributing to the mureo codebase.
Project Overview
mureo — your local-first AI ad ops crew. Find waste, audit changes, run ad accounts safely.
Works with Claude Code, Cursor, Codex & Gemini. mureo sits on top of the official ad-platform MCPs and gives your AI a strategy to follow, an outcome to be measured against, and an audit trail you can show to anyone — credentials never leave your machine.
mureo combines strategy context, workflow commands, and domain knowledge to help AI agents achieve marketing goals across platforms. Provides MCP tools for direct platform operations and workflow commands for strategy-driven ad operations via Claude Code slash commands. Designed for AI agents — no database, no LLM SDK, no web framework.
Build & Test
pip install -e ".[dev]"
pytest tests/ -v
pytest tests/ --cov=mureo --cov-report=term-missing
# Browser assets (only when mureo/_data/web/ changes). Node's built-in
# runner — no package.json, no dependencies, no build step.
node --test tests/js/*.test.js
Architecture
mureo/
├── google_ads/ # Google Ads API client (Mixin composition)
│ ├── client.py # GoogleAdsApiClient (main entry)
│ ├── mappers.py # Response mapping to structured dicts
│ ├── _enum_names.py # map_enum_name + SDK-derived int->name maps (raw protobuf has no .name, #588)
│ ├── _placement_mappers.py # Negative-placement + group_placement_view row mappers (#544/#547)
│ ├── _ads.py # AdsMixin (RSA create/update/status/list)
│ ├── _ads_display.py # DisplayAdsMixin (RDA create + RDAUploadError)
│ ├── _asset_groups.py # AssetGroupsMixin (Performance Max asset groups: one read for
│ │ # text + images, and the text swap via one atomic
│ │ # GoogleAdsService.mutate, #590/#626). Owns both field-type
│ │ # tables — text width limits and image dimension rules
│ ├── _asset_groups_images.py # AssetGroupImagesMixin (the P-MAX image swap, #626:
│ │ # existing asset id or local upload, one atomic mutate)
│ ├── _keywords.py # KeywordsMixin (add/remove/suggest/diagnose)
│ ├── _placements.py # PlacementsMixin (negative placements: sites/apps/app categories, #544)
│ ├── _analysis.py # AnalysisMixin aggregator, composing the split modules below
│ ├── _analysis_auction.py / _analysis_btob.py / _analysis_budget.py # + _analysis_constants.py
│ ├── _analysis_keywords.py / _analysis_performance.py / _analysis_rsa.py / _analysis_search_terms.py
│ ├── _diagnostics.py # DiagnosticsMixin (campaign diagnosis)
│ ├── _extensions.py # ExtensionsMixin aggregator, composing the split modules below
│ ├── _extensions_callouts.py / _extensions_conversions.py / _extensions_sitelinks.py / _extensions_targeting.py
│ ├── _monitoring.py # MonitoringMixin (anomaly detection/reporting)
│ ├── _creative.py # CreativeMixin (LP analysis/message match)
│ ├── _media.py # MediaMixin (image asset upload)
│ ├── _rsa_validator.py # RSA ad text validator
│ ├── _rda_validator.py # RDA input validator (display ads)
│ ├── _rsa_insights.py # RSA asset performance insights
│ ├── _intent_classifier.py # Search term intent classification
│ ├── _message_match.py # Message match evaluator
│ ├── _gaql_validator.py # GAQL input validators (ASCII-only ID/date whitelists — see below)
│ └── accounts.py # Accessible-customer / account listing
├── meta_ads/ # Meta Ads API client (Mixin composition)
│ ├── client.py # MetaAdsApiClient (main entry)
│ ├── mappers.py # Response mapping
│ ├── _campaigns.py # CampaignsMixin
│ ├── _ad_sets.py # AdSetsMixin
│ ├── _ads.py # AdsMixin
│ ├── _creatives.py # CreativesMixin (image/carousel/collection/dynamic)
│ ├── _videos.py # VideosMixin (AdVideo upload/status/thumbnails)
│ ├── _audiences.py # AudiencesMixin
│ ├── _pixels.py # PixelsMixin
│ ├── _placement_exclusions.py # PlacementExclusionsMixin (ad-set publisher exclusions, #544)
│ ├── _insights.py # InsightsMixin
│ ├── _analysis.py # AnalysisMixin
│ ├── _catalog.py # CatalogMixin (product catalogs/feeds)
│ ├── _conversions.py # ConversionsMixin (Conversions API / CAPI)
│ ├── _hash_utils.py # SHA-256 PII hashing for CAPI
│ ├── _leads.py # LeadsMixin (lead forms/leads)
│ ├── _page_posts.py # PagePostsMixin (page posts/boost, page photos for an Instant Form cover)
│ ├── _instagram.py # InstagramMixin (accounts/media/boost)
│ ├── _split_test.py # SplitTestMixin (A/B split tests)
│ ├── _ad_rules.py # AdRulesMixin (automated rules)
│ ├── _conversion_count.py # Conversion-count parsing helper
│ ├── _period.py # Date-period resolution helper
│ └── accounts.py # Ad-account listing
├── search_console/ # Google Search Console API client (reuses Google OAuth2 credentials)
│ └── client.py # SearchConsoleApiClient
├── mcp/ # MCP server (Google/Meta/Search Console + Rollback/Analysis + Analytics registry, Creative Studio, Learning, mureo Context)
│ ├── server.py # MCP Server entry point (stdio-based)
│ ├── _helpers.py # Shared handler utilities
│ ├── tools_google_ads.py # Google Ads tool definitions (aggregator)
│ ├── _tools_google_ads_*.py # Tool definition sub-modules
│ ├── _handlers_google_ads.py # Google Ads base handlers
│ ├── _handlers_google_ads_extensions.py # Extensions handlers
│ ├── _handlers_google_ads_analysis.py # Analysis handlers
│ ├── tools_meta_ads.py # Meta Ads tool definitions (aggregator)
│ ├── _tools_meta_ads_*.py # Tool definition sub-modules
│ ├── _handlers_meta_ads.py # Meta Ads base handlers
│ ├── _handlers_meta_ads_extended.py # Extended handlers
│ ├── _handlers_meta_ads_other.py # Other handlers
│ ├── tools_search_console.py # Search Console tool definitions
│ ├── _handlers_search_console.py # Search Console handlers
│ ├── tools_rollback.py # rollback_plan_get / rollback_apply
│ ├── _handlers_rollback.py # Rollback handlers (lazy-resolve dispatcher)
│ ├── tools_batch.py # mureo_batch_begin / _end / _status (#549)
│ ├── _handlers_batch.py # Batch lifecycle handlers
│ ├── tools_change_import.py # mureo_external_changes_import (#545)
│ ├── _handlers_change_import.py # Change-import handler
│ ├── tools_analysis.py # analysis_anomalies_check / analysis_delivery_collapse_* / analysis_exclusion_impact_preview
│ ├── _handlers_analysis.py # Anomaly detector composition handler
│ ├── _handlers_delivery_collapse.py # Delivery-collapse check / diagnose handlers (#546)
│ ├── _handlers_exclusion_impact.py # analysis_exclusion_impact_preview handler (#547)
│ ├── exclusion_preflight.py # Pre-dispatch exclusion sizing + refusal + notice (#547)
│ ├── exclusion_sources.py # Built-in per-platform delivery sources for the above (#547)
│ ├── tools_analytics_registry.py # mureo_analytics_modules_list / mureo_analytics_run (#440)
│ ├── tools_creative_studio.py # creative_studio_* (visual generation + compose)
│ ├── tools_learning.py # mureo_learning_insights_get / mureo_consult_advisor
│ ├── tools_learning_preflight.py # mureo_learning_reset_preflight (#548)
│ ├── tools_mureo_context.py # STRATEGY.md / STATE.json + mureo_outcome_evaluate tools
│ ├── _handlers_mureo_context.py # Context (STRATEGY/STATE) handlers
│ ├── _client_factory.py # Per-platform BYOD-vs-live client factory
│ └── tool_provider.py # Third-party plugin → MCP tool exposure layer (#89)
├── cli/ # Typer CLI (setup + auth + configure + BYOD + providers + rollback + repair; ad ops are via MCP)
│ ├── main.py # CLI entry point (`mureo` command)
│ ├── setup_cmd.py # `mureo setup claude-code` / `cursor` / `codex` / `gemini`
│ ├── setup_codex.py # Codex install-kit: MCP, credential guard, operational + foundation skills
│ ├── setup_gemini.py # Gemini extension manifest at ~/.gemini/extensions/mureo/
│ ├── native_skills.py # Deploy/remove plugin native slash skills via `mureo.native_skills` group (#439)
│ ├── configure_cmd.py # `mureo configure` — open the local web configuration UI
│ ├── byod_cmd.py # `mureo byod import` / `status` / `remove` / `clear`
│ ├── providers_cmd.py # `mureo providers list` / `install` / `uninstall` (official MCP catalog)
│ ├── service_cmd.py # `mureo service` — install/restart the auto-start configure daemon (#241)
│ ├── upgrade_cmd.py # `mureo upgrade` — pipx venv-aware bulk upgrade of mureo + plugins
│ ├── auth_cmd.py # `mureo auth setup` / `status` / `check-*` / `upgrade-google`
│ ├── rollback_cmd.py # `mureo rollback list` / `show` (inspection only; apply routes through MCP)
│ ├── repair_cmd.py # `mureo repair platform-key` — drop a platforms entry the DOCUMENT
│ │ # shows to be wrong (duplicate of a resolvable key, or empty stub);
│ │ # dry run by default, backs up first (#610/#616).
│ │ # `--all` sweeps every client, summary first, one prompt (#614).
│ │ # `--key <k> --drop-duplicate` records the operator's OWN decision
│ │ # about a duplicate whose two keys both resolve (#636); not with --all
│ ├── _repair_preview.py # What that command prints — the half that has to be TRUE: why an
│ │ # entry can go, what is NOT changed (scoped to the plan), every
│ │ # same-account sibling, and conversion_action_types (#616/#617/#618).
│ │ # Also the not_collected note an entry carries (#643) and both
│ │ # entries of a duplicate mureo hands back to decide (#645)
│ ├── _repair_clients.py # Which STATE.json files `--all` sweeps — reuses the Reports tab's
│ │ # optional list_clients / state_store_for_client seam, never a second one
│ ├── _state_file.py # The shared `--state-file` option + workspace default (rollback + repair)
│ ├── _tty.py # TTY-safe helpers for non-interactive setup + terminal_safe() scrubbing
│ └── web_auth.py # Browser-based OAuth wizard spawned by `mureo configure` (per-platform creds)
├── context/ # File-based strategy context (no DB)
│ ├── strategy.py # STRATEGY.md parser/writer
│ ├── state.py # STATE.json parser/writer
│ ├── models.py # StrategyEntry, StateDocument, CampaignSnapshot, ActionLogEntry (rollback_of, batch_id), BatchRecord
│ ├── batch.py # Batch id minting + the action_log stamping rule (#549)
│ ├── daily.py # The day-grain history write MINUS the file (#690/#710):
│ │ # `with_platform_daily(doc, ...)` (guard + per-date merge +
│ │ # trim) and `capped_platform_daily(daily)` (the 35-day
│ │ # retention rule on its own), for a writer that lands
│ │ # `daily` inside its OWN atomic document write.
│ │ # `set_platform_daily` is the path-based wrapper, so both
│ │ # routes keep one set of semantics. Optional `as_of_date`
│ │ # = today in the ACCOUNT's timezone: an account closes its
│ │ # day locally, so the host clock refused a complete
│ │ # yesterday-JST on a UTC host every night
│ ├── observations.py # What closes an action_log observation, and which are
│ │ # past due (#651). ONE rule for `mureo_state_get(
│ │ # action_log="pending")` and the Reports triage count;
│ │ # two entry shapes (rendered dict / ActionLogEntry)
│ ├── monthly_budget.py # The `## Custom: Monthly Budget` reader (#652) — the operator's
│ │ # INTENDED monthly spend, twin of `guardrails_from_strategy_text`.
│ │ # Separate type from `Guardrails` on purpose: a target is not a
│ │ # ceiling. "Not set" is a first-class answer (never 0), a total
│ │ # derived from `max_total_daily_budget` says so, and the figure
│ │ # stays in STRATEGY.md — never copied into STATE.json
│ ├── platform_monthly_budget.py # Rung 2 of that precedence (#656): the sum of the
│ │ # per-campaign monthly budgets, for platforms that DECLARED they
│ │ # have the concept (`register_monthly_budget_support`; core
│ │ # declares none). A third `source`, so a configured sum is never
│ │ # shown as an agreed target. No total is stored — it is computed
│ │ # on read — and an incomplete or uncollected campaign set is
│ │ # withheld rather than summed short, reported as
│ │ # `IncompletePlatform(platform, reason)` so an operator is told
│ │ # WHICH gap it is (a wrong declaration, a sync behind, a failed
│ │ # collection) instead of reading a debug log. The two splits are
│ │ # separate fields — `per_platform` is only ever what the operator
│ │ # wrote — and the type refuses a split that does not match `source`
│ ├── platform_guards.py # Write-time platform-key guards (#534/#609) — the one "is this key
│ │ # real?" answer every other surface asks, including the read-side
│ │ # label path (`installed_platform_names`, shared since #631)
│ ├── platform_repair.py # The repair half (#610): plan + drop an entry under an unresolvable
│ │ # key. Unresolvable is the FILTER, not the criterion — the document
│ │ # must show the entry wrong (#616), and conversion_action_types is
│ │ # never dropped (#617). `drop_duplicates` is the one widening: a key
│ │ # the OPERATOR named, dropped only against a same-account sibling
│ │ # (#636). Drops, never merges; backs up; no action_log
│ └── errors.py # Context-specific errors
├── analysis/ # Analysis utilities
│ ├── lp_analyzer.py # Landing page analyzer
│ ├── anomaly_detector.py # Zero-spend / CPA-spike / CTR-drop detection (pure, sample-size-gated)
│ ├── delivery_collapse.py # Delivery-collapse detection (#546) — weekday-aware baseline taken
│ │ # from the platform's own daily delivery, never from action_log
│ ├── delivery_collapse_config.py # ## Guardrails -> CollapseThresholds (the only I/O half)
│ ├── collapse_diagnosis.py # Change x metric timeline + elimination ladder; reports the
│ │ # open questions, never a cause it did not evidence
│ ├── exclusion_impact/ # Delivery-impact preview for bulk exclusions (#547; pure)
│ │ ├── models.py # DeliveryRecord / ExclusionTarget / ExclusionImpact + coverage verdicts
│ │ ├── matching.py # Per-entity-kind match rules (host, app id, negative keyword match type)
│ │ ├── estimator.py # The share itself — incremental and cumulative
│ │ ├── rules.py # ## Guardrails exclusion keys, the one refusal decision, inert-rule reporting
│ │ └── surfaces.py # Which tools are exclusion surfaces (mureo's + plugin-registered)
│ └── tracking/ # Tracking-parameter consistency: platform-neutral detector + per-platform URL accessors (#550)
├── rollback/ # Rollback feature (allow-list gated, append-only audit trail)
│ ├── models.py # RollbackStatus / RollbackPlan + batch verdicts (BatchCoverage, BatchRollbackPlan)
│ ├── planner.py # plan_rollback(ActionLogEntry) -> RollbackPlan | None
│ ├── batch.py # plan_batch_rollback(doc, batch_id) -> every member, gaps included (#549)
│ └── executor.py # execute_rollback(...) -> appends ActionLogEntry(rollback_of=index)
├── adapters/ # Provider adapters wrapping each ad-platform client as a registry Protocol
├── analytics/ # Analytics-module registry for external MCP / plugin platforms (#120)
├── change_import/ # Import changes made OUTSIDE mureo into action_log (#545)
│ ├── models.py # ExternalChange / ChangeFeedResult / ChangeImportOutcome
│ ├── protocol.py # ChangeFeedProvider Protocol (`mureo.change_feeds` entry-point group)
│ ├── registry.py # Discovery + per-plugin fault isolation + lookup
│ ├── dedupe.py # Already-imported vs mureo's own change (why one is approximate)
│ ├── importer.py # Watermark, action_log write, per-platform outcome
│ └── builtin/ # Native feeds — google_ads only today; see docs/change-import.md
├── core/ # Extension Protocols + file-backed impls + RuntimeContext; provider & skill discovery
├── providers/ # Official MCP provider catalog + one-command install helpers (#86)
├── policy/ # Built-in policy gates (strategy_gate) — ship with OSS, run by default
│ ├── learning_rules.py # Per-platform learning-period facts + their first-party sources (#548)
│ ├── platform_model.py # Per-platform delivery-model prose + first-party sources (#648) —
│ │ # the ONLY always-on plugin channel: rendered into the MCP
│ │ # server's `instructions`, scoped to the platforms served
│ └── learning_reset.py # Reset-class + learning-state pre-flight the gate refuses on
├── learning/ # Read-side /learn companion: insight federation across configured sources
├── creative_studio/ # Creator-grade ad-creative (image) generation via pluggable providers
├── byod/ # Bring Your Own Data — CSV-backed offline analysis (see BYOD Mode below)
├── web/ # Local `mureo configure` UI — stdlib http.server on 127.0.0.1 (no web framework)
├── demo/ # `mureo demo init` synthetic-bundle bootstrap (round-trips through BYOD)
├── auth.py # Credentials management (~/.mureo/credentials.json + env vars + Meta token auto-refresh)
├── auth_setup.py # Interactive setup wizard (browser OAuth flow)
├── credential_guard.py # Blocks AI agents from reading ~/.mureo/credentials.json
├── logging_setup.py # Configure-server logging (#581): rotating ~/.mureo/logs/configure.log,
│ # MUREO_LOG_LEVEL, and the HTTP access-log query scrubber. Installed by
│ # the configure entry point only — never at import time, never on root.
└── throttle.py # Rate limiting (token bucket + rolling hourly cap)
skills/ # Native slash skills — one `<name>/SKILL.md` per skill (migrated from
│ # .claude/commands in #439; invocable as `/<name>`). Plugins contribute
│ # more via the `mureo.native_skills` entry-point group, deployed/removed
│ # by `mureo/cli/native_skills.py`.
├── onboard/, daily-check/, rescue/, budget-rebalance/, … # ~20 operational (workflow) skills
│ └── SKILL.md
└── _mureo-*/ # 7 foundation skills: _mureo-shared / _mureo-strategy / _mureo-google-ads /
└── SKILL.md # _mureo-meta-ads / _mureo-amazon-ads / _mureo-learning / _mureo-pro-diagnosis
docs/integrations.md # Platform discovery + external MCP integration guide
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.
- 2d ago First seen · 505 lines · 10,087 tokens per session scan A 567c3f27f738
mureo AGENTS.md is an instructions file published in the GitHub repository logly/mureo (42 stars, last pushed 2d ago), licensed Apache-2.0. It adds 10,087 tokens to every session, about $0.0504 per session on Opus 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-08-30.
Other instructions, from other repositories
adloop CLAUDE.md
Instructions for kLOsk/adloop, covering adloop, quick reference, architecture, orchestration rules and documentation site.
marketing-studio CLAUDE.md
Instructions for ucsandman/marketing-studio: Remotion (studio/) renders all final video for ALL products/brands; assets are copied out to the product's repo at the end. brands/ .json holds per-product tokens (zod-validated via studio/src/lib/brand.ts; mark components in studio/src/brands/marks.ts); templates resolve…
marketing-skills AGENTS.md
Instructions for hyperfx-ai/marketing-skills, covering agents.md, what this repo is, available skills, foundation and paid ads.
ads-mcp GEMINI.md
Instructions for amekala/ads-mcp, covering adspirer — ad campaign management, quick start, when to use these tools, required workflow and step 1: check connected platforms.
ads-mcp CLAUDE.md
Instructions for amekala/ads-mcp, covering adspirer — performance marketing plugin, getting started, available commands and safety.
backlink-pilot CLAUDE.md
Instructions for s87343472/backlink-pilot, covering backlink pilot v2.1 — claude code instructions, first-time user flow, step 1: check prerequisites, step 2: create config.yaml and step 3: start chrome.