agentleFS
loglylogly/mureo/skills/sync-state/SKILL.md

sync-state

Skill64 starsChanged 7 months agoApache-2.0View on GitHub

Sync STATE.json with current campaign data from all platforms. Use when the user asks to refresh state, sync campaigns, update STATE.json from live data, or pull latest campaign snapshots. Also use when the user asks in Japanese (STATE.jsonを更新 / 最新データに同期して / キャンペーン情報を取り込み直して).

1 other project uses a version of this.

Adopted by

Most recently taken up by

The file

We split this skill into the rules it gives an agent

4 rules. About 0 are common, 1 is distinctive, and 3 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈1

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 3

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    Check data sources: If Search Console is configured, verify site access is still valid.

    line 41
  2. Very specific:

    Detect new platforms: If new platform credentials exist but have no entry in platforms, prompt the user to run /onboard to add them.

    line 43
  3. Very specific:

    Verify STRATEGY.md Data Sources: If STRATEGY.md is missing a ## Data Sources section (older setup), prompt the user to add it listing all …

    line 45
  4. Very specific:

    If STATE.json doesn't exist yet, suggest running /onboard first.

    line 59

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Sync State

PREREQUISITE: Read ../_mureo-shared/SKILL.md for auth, security rules, output format, and Tool Selection (Read/Write on Code, mureo_strategy_* / mureo_state_* MCP on Desktop / Cowork), and ../_mureo-state-schema/SKILL.md for the STATE.json schema and the status vocabulary contract.

Tool names below refer to the built-in platforms; a namespaced variant (see _mureo-shared → Namespaced built-in variants) is used with its prefix substituted.

Synchronize STATE.json with the current state of all marketing platforms.

Mixed operation

Manual operation in the platform UI and mureo-driven operation coexist — most accounts run that way for a while after onboarding, and it applies to every platform. Treat any change you find that mureo did not make as a first-class fact, not an anomaly: the action_log records what mureo did, never the full history of the account, so never infer current state from it. When a diff surfaces a change made outside mureo, say so in the report rather than silently absorbing it into the new state.

Prerequisites

  • STRATEGY.md and STATE.json should exist in the current directory (run the onboard skill first if not)

Steps

Note: the Diagnostic preamble (learning insights + advisor consult) from ../_mureo-shared/SKILL.md is intentionally not required here — sync-state is mechanical data synchronization with no judgement calls.

  1. Establish today: call mureo_state_get first, on every host (including Claude Code, where you would otherwise Read the file) and take server_now from its response — ISO 8601 with UTC offset, e.g. 2026-07-28T10:12:33+09:00. Its date is the only source of the current date for this sync (no shelling out — this skill must run in Bash-less headless hosts). The dates inside the document — last_synced_at, reports.*.period, action_log timestamps — are history: use them to describe what changed, never to decide what "now" is or whether a sync is still needed. Never write server_now into STATE.json; it is a response field, and a persisted copy becomes tomorrow's stale "today".
  2. Read current STATE.json (if exists) to track changes — the same mureo_state_get response from step 0 on MCP hosts.
  3. Discover platforms: Identify all platforms registered in STATE.json platforms — built-in AND plugin/bridge platforms. Per ../_mureo-shared/SKILL.md → Plugin platforms, also enumerate any installed entry-point plugin that exposes mcp__mureo__<plugin>_* tools; its STATE.json platform key is plugin:<dist>:<provider> (the same convention mureo uses when promoting plugin mutations into action_log; the older plugin:<dist> is still read, and an entry already stored under it must be kept, not rewritten). Also enumerate any hosted official-MCP connector present in the session (e.g. TikTok's tt-ads-* tools) — its key is a first-class ad-platform key such as tiktok_ads; see ../_mureo-shared/SKILL.md → Hosted-connector platforms.
  4. Fetch platform data: For each registered platform:
    • Google Ads: prefer mureo native — call google_ads_campaigns_list, then google_ads_performance_report for the current period (last 30 days). Both work in BYOD and Live API modes. Keep the per-campaign numbers from the performance report — they become each campaign's metrics in step 7. If mureo's Google Ads tools are unavailable (e.g. MUREO_DISABLE_GOOGLE_ADS=1 after mureo providers add google-ads-official), fall back to the official google-ads-official MCP's equivalent campaign-list and performance-report tools for the same period.
    • Meta Ads: prefer mureo native — call meta_ads_campaigns_list, then meta_ads_insights_report for the current period — capture result_indicator per campaign so STATE.json reflects whether each campaign's "results" are clicks or real leads, and keep the per-campaign insight numbers for the metrics write in step 7. If mureo's Meta Ads tools are unavailable, fall back to the official meta-ads-official hosted MCP for the campaign list and insights; the result_indicator field is mureo-specific and will not be present — record the raw optimization goal / actions list per campaign in STATE.json instead and note that CV-definition disambiguation requires mureo's native MCP. In BYOD mode this response is wrapped as {"source": "byod_import", "as_of": <import time>, "data": [...]} — take the rows from data and treat them as of as_of, not as live.
    • Plugin / bridge platforms (plugin:<dist>:<provider>): where the plugin exposes a daily-report / insights / performance tool (infer from the live tool list — best-effort, not deterministic), call it for the current period and keep the per-campaign numbers for the metrics write in step 7. Honest scope per ../_mureo-shared/SKILL.md: capture only the basic metrics the plugin's own tools return; skip mureo-only value-adds (result_indicator CV-mismatch, anomaly detection, RSA-asset audit, rule-based scoring) — they do not exist for plugins, so omit result_indicator for a plugin platform. If a plugin has no such reporting tool, leave its metrics/totals empty (it stays an advisory platform) and continue — never fail the whole sync because a plugin tool is missing.
    • Hosted-connector platforms (tiktok_ads etc.): call the hosted connector's own campaign-list / reporting tools (e.g. tt-ads-*) for the current period and keep the per-campaign numbers for the metrics write in step 7. Same honest scope as a plugin platform (basic metrics only; omit result_indicator and other mureo-only value-adds). If the connector has no reporting tool available, leave its metrics/totals empty and continue. See ../_mureo-shared/SKILL.md → Hosted-connector platforms.
    • Ad-level delivery status — active campaigns only: for each campaign whose status reads as active in its own platform's vocabulary — ACTIVE / ENABLED / enabled, matched case-insensitively (see ../_mureo-state-schema/SKILL.md → Status vocabulary contract) — list its ads and keep each ad's ad_id, name, status and effective_status. status is only what the ad is configured as; effective_status is whether it is actually delivering, and the two disagreeing is exactly how an ad stopped outside mureo (by hand in the platform UI, by its ad set / campaign, or by policy) shows up. Meta: meta_ads_ads_list (scope by ad_set_id, or list once per account and group by campaign_id). Google Ads: google_ads_ads_list for the campaign's ad groups, keeping the ad status plus the policy review/approval status. Amazon Ads (official-MCP bridge, plugin:mureo-amazon-ads-bridge:amazon_ads): campaign_management-query_ad — the body REQUIRES accessRequestedAccount ({advertiserAccountId} or {profileId}; a global account accepts only profileId) and adProductFilter.include with exactly one ad product (SPONSORED_PRODUCTS / SPONSORED_BRANDS / SPONSORED_DISPLAY / SPONSORED_TELEVISION / AMAZON_DSP), so a full sweep is one call per product; narrow with campaignIdFilter.include and stateFilter.include (ENABLED / PAUSED / ARCHIVED), and take the rows from the ads envelope. Amazon exposes one state per ad (state, the configured state) and no serving/review status: record it as the ad's status and leave effective_status unset — its effective status is unknown, never state copied across (see ../_mureo-amazon-ads/SKILL.md → Ad-level delivery state). Other plugin / hosted-connector platforms: use the equivalent ad-listing tool where one exists; where none does, skip that platform and report the skip — name the platform and say that no ad-listing tool was found — so a missed or mis-inferred tool is distinguishable from a platform that genuinely has nothing to report. Cost guard: do not make ad-level calls for PAUSED / REMOVED campaigns. In BYOD mode these reads are served from the imported CSVs and come back wrapped as {"source": "byod_import", "as_of": <import time>, "data": [...]} — take the rows from data, and treat the statuses as of as_of, not as live (a live response has no such wrapper).
    • mureo BYOD data is centralized in the workspace byod/ directory (or ~/.mureo/byod/ for legacy CLI users) and is only accessible through mureo MCP tools — do not look for raw CSVs in the project directory.
  5. Check data sources: If Search Console is configured, verify site access is still valid. If GA4 is available, verify connectivity.
  6. Detect new platforms: If new platform credentials exist but have no entry in platforms, prompt the user to run /onboard to add them.
  7. Verify STRATEGY.md Data Sources: If STRATEGY.md is missing a ## Data Sources section (older setup), prompt the user to add it listing all configured platforms.
  8. Update STATE.json with all campaign snapshots. On the Code Write path, use the canonical STATE.json field names — campaign_name (NOT the tool-output name), campaign_id (NOT id), and each platform's account_id; a snapshot/platform missing a required field is dropped by the reporting dashboard. See ../_mureo-state-schema/SKILL.md → STATE.json Schema. Copy each campaign's type from the campaign list verbatim into campaign_type — Google Ads channel_type (e.g. SEARCH, PERFORMANCE_MAX), Meta objective (e.g. OUTCOME_LEADS); omit it where the list carries no such field. For each campaign, also write the metrics you fetched in step 3 onto the snapshot: spend, impressions, clicks, conversions, cpa, ctr, the Meta result_indicator (when present), period (e.g. LAST_30_DAYS), and fetched_at (ISO 8601). On Code use Write; on Desktop / Cowork call mureo_state_upsert_campaign with the metrics object. Record the per-platform rollup on each platforms[<platform>] entry too — totals (summed spend / clicks / conversions / etc.), metrics_period (the period the totals cover, LAST_30_DAYS here), and the same totals under periods["LAST_30_DAYS"] (the per-window map the reporting dashboard's period toggle reads) — so the dashboard can render KPIs from STATE.json without re-querying. On Code write the rollup via Write; on Desktop / Cowork call mureo_state_platform_metrics_set (pass platform, account_id, totals, metrics_period="LAST_30_DAYS", and periods={"LAST_30_DAYS": {…}}) — mureo_state_upsert_campaign writes per-campaign metrics only, never the platform rollup. periods merges per window key, so writing LAST_30_DAYS never clobbers a YESTERDAY bucket daily-check wrote. On the mureo_state_platform_metrics_set path you may omit fetched_at from the rollups — the server stamps the write time onto every rollup that call supplies without one, and never re-stamps a window it only preserves; on the Write path set it yourself, or the dashboard has no age to show. Give the LAST_30_DAYS rollup a period_end — the last calendar date those figures cover, YYYY-MM-DD, in the ad account's own timezone (the server stamps fetched_at but does not know the account's timezone and will not guess this date; without it the card is judged on when it was last written, not on what it covers). All metric fields are optional: omit any a platform doesn't provide rather than writing nulls. Persist the ad-level statuses from step 3 too, as the campaign's ads array (ad_id, name, status, effective_status) — omitting effective_status for a platform that reports no serving status (Amazon Ads; see step 3): on Desktop / Cowork pass ads to mureo_state_upsert_campaign (the server stamps each ad's as_of, so do not compute it); on Code write the same array on the campaign snapshot with an as_of of server_now. Omit ads entirely for campaigns whose ads you did not fetch — an empty array means “fetched, this campaign has no ads”. Plugin / bridge platforms use the SAME shape: persist their campaigns + best-effort metrics (canonical vocabulary, minus result_indicator) under platform key plugin:<dist>:<provider> via mureo_state_upsert_campaign (pass platform="plugin:<dist>:<provider>" — or the key that platform is already stored under, which may be the older plugin:<dist>; never write a second key for a platform that already has one), plus the per-platform totals / metrics_period / periods["LAST_30_DAYS"] via mureo_state_platform_metrics_set — so a bridge's KPIs land in the same platforms shape the dashboard reads. A plugin with no reporting tool keeps an entry with empty metrics/totals (advisory, no synced metrics).
  9. Show diff: Compare old vs new state and highlight changes:
    • New campaigns added
    • Campaigns removed/paused
    • Budget changes
    • Status changes
    • Bidding strategy changes, on the platforms that have one (see ../_mureo-state-schema/SKILL.md → Status vocabulary contract)
    • Ad-level status changes — ads added or removed, plus any change to a stored status field, diffed against the ads the previous run stored: compare each ad's status, and its effective_status when the platform reports one, against the previous run's stored value for that same field, and report every difference. An ad stopped delivering when such a value moved away from the platform's active value — matched case-insensitively, so ACTIVE, ENABLED and enabled all count as active — which makes the limb fire on a platform that reports only one status field, in its own vocabulary, instead of falling through (see ../_mureo-state-schema/SKILL.md → Status vocabulary contract). Changes mureo did not make are the point of this line: name them explicitly (see Mixed operation) instead of letting the new snapshot quietly replace the old.
  10. Update last_synced_at timestamp — use server_now from step 0 (the mureo_state_* write tools stamp it for you; on the Code Write path write that value yourself).

If STATE.json doesn't exist yet, suggest running /onboard first.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.