plugins/octave/skills/ads-resonance/SKILL.md
Analyze ad performance and feed the learnings back into your Octave library — the resonance loop. Pulls performance data from Google Ads MCP, BigQuery Data Transfer, direct API, or manual paste; maps winners back to the source cards behind each ad variant; generates library update recommendations and a sales intelligence brief; writes falsifiable prediction cards and accumulates a calibration track record over time. Use when user says "analyze ad performance", "resonance loop", "score predictions", "evaluate my ads", or asks to turn ad performance into GTM intelligence. Do NOT use to build a new ad campaign — use /octave:ads instead.
npx skillsauth add octavehq/lfgtm ads-resonanceInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Turn ad performance data into GTM intelligence: pull performance from whichever source is available, map winners and losers back to the source cards that produced them, recommend library updates, brief the sales team on what language the market responds to, and write falsifiable prediction cards so the loop builds a verifiable track record over time.
Companion skill: /octave:ads builds the campaigns this loop analyzes. Campaigns generated there persist source cards to ~/.octave/source_cards/ (the data contract is defined in /octave:ads Step 2G and source-cards.template.json), which unlocks this loop's strongest analysis path. The loop also works on campaigns created outside /octave:ads via reverse-inference.
MCP Server: Library updates (Step 3) require the Octave MCP server. Look for available MCP tools that match the Octave tool names (e.g., update_entity, update_motion_playbook). The MCP server prefix varies by workspace. If multiple Octave-like MCP servers are available and you're unsure which to use, ask the user which workspace to target.
Performance data can come from four places, in order of preference:
Read performance-data-sources.md for setup instructions, all SQL and API queries, table layouts, and the troubleshooting table. That doc is the source of truth for everything in this step — the SKILL describes the procedure; the reference owns the queries.
Critical principle: never tell the user "I can pull your data" without running a smoke test first. A path that looks available (the MCP tool exists, the dataset exists, the dev token is set) can still fail at query time. Probe first, then commit.
Walk through the four paths in order. For each one, first detect, then smoke-test. The first path that passes its smoke test wins — use it. If all four fail, fall through to manual.
| Path | What to look for |
|------|------------------|
| 1 — MCP | MCP tools matching google_ads, googleads, adwords, google_campaigns, meta_ads, facebook_ads, linkedin_ads |
| 2 — BigQuery | A BigQuery MCP tool (bigquery, bq, mcp__bigquery*), OR the bq CLI on PATH and authenticated, OR a known dataset like google_ads containing ads_Campaign_* / ads_CampaignBasicStats_* tables |
| 3 — Direct API | The user mentions they have an approved developer token + a refresh token, but no MCP. Or earlier in the conversation they shared API credentials |
| 4 — Manual | Always available |
If a Google Ads MCP tool is detected, before promising data:
→ {google_ads_mcp}__list_accessible_customers()
If that succeeds, pick one accessible customer ID and run the simplest possible query:
→ {google_ads_mcp}__search(
customer_id: "{id}",
query: "SELECT customer.id, customer.descriptive_name FROM customer"
)
Interpret the result:
CUSTOMER_NOT_FOUND + "missing authentication credential" → wrong login-customer-id. Tell the user the exact fix (set GOOGLE_ADS_LOGIN_CUSTOMER_ID to the MCC, not a sub-account) and fall through to Path 2.DEVELOPER_TOKEN_NOT_APPROVED "only approved for use with test accounts" → the developer token is in Test tier and cannot query production accounts. Tell the user they need to apply for Basic Access in API Center (~3 days) and fall through to Path 2.invalid_scope or 403 → the credentials are missing the adwords scope. Reference the Python refresh-token snippet in the data sources doc and fall through to Path 2.404 on a versioned path → API version sunset. Check the current version (see the data sources doc) and fall through to Path 2.For all four failure modes, the message to the user should be one sentence: what failed, what the fix is, and "I'll try BigQuery next."
If a BigQuery MCP tool is available, list datasets and look for google_ads (or any dataset containing tables prefixed ads_Campaign_). If bq CLI is available, run:
bq ls --project_id=<project>
bq ls <project>:google_ads
If you find tables matching ads_CampaignBasicStats_<MCC>, run the two-stage smoke test defined in performance-data-sources.md § "Smoke test". The first stage proves data exists and is fresh. The second stage proves the data is meaningful — that it'll actually drive useful resonance analysis, not just produce empty tables.
_DATA_DATE over the last 30 days.CRITICAL — dim-table snapshot trap. ads_AdGroup_<MCC> and ads_Campaign_<MCC> are daily-snapshotted dimension tables. Joining them without a latest-snapshot dedup CTE cartesian-explodes your totals. Every query that reads dim metadata must use the ag_latest / c_latest CTE pattern from the data sources doc — see § "Gotcha #4: Daily-snapshotted dim tables" for the full writeup. Never JOIN the dim tables directly.
Interpret the result:
most_recent within the last 2 days → freshness OK, continue to Stage 2.clicks > 5 → Path 2 is good. Use the BigQuery queries from the data sources doc for all subsequent fetches. Note in your report what the data window covers and how many ad groups have meaningful volume.most_recent is more than 2 days old → the transfer exists but has stalled or hasn't backfilled yet. Tell the user and offer to either trigger a backfill (bq mk --transfer_run ...) or fall through to Path 3 / Path 4.roles/bigquery.dataViewer on the dataset. Tell the user the exact fix and fall through.If the user has shared API credentials earlier in the conversation (developer token + refresh token + client id/secret), or has an Application Default Credentials file for the Ads API, you can hit the API directly with curl or Python. Same smoke test as Path 1: mint an access token from the refresh token, hit listAccessibleCustomers, then run a customer query against an accessible ID.
Same failure modes as Path 1 (login-customer-id, dev token tier, scope, API version) — see the data sources doc for the curl invocations.
If all programmatic paths fail (or the user explicitly requests manual), ask:
AskUserQuestion({
questions: [{
question: "How would you like to provide ad performance data?",
header: "Performance Data",
options: [
{
label: "Paste a CSV or table",
description: "Paste performance data from your ad platform (needs: variant/headline, impressions, clicks, conversions)"
},
{
label: "Paste a screenshot",
description: "Share a screenshot of your ad platform dashboard — I'll extract the metrics"
},
{
label: "Summarize verbally",
description: "Tell me which variants won and lost, with approximate numbers"
},
{
label: "Skip — I'll come back later",
description: "Run the resonance loop when you have performance data"
}
],
multiSelect: false
}]
})
Whichever path wins, fetch these per-variant metrics so the resonance map (Step 2) has what it needs:
Match fetched data back to the variants the campaign was generated with (see /octave:ads Step 3) by headline text (most reliable across paths), then by ad set name, then by campaign ID if the user stored it during export.
This is the core of the resonance loop. Before generating the map, decide which analytical mode the data supports — the wrong mode produces confident-sounding noise. Then decide whether the campaign was generated by /octave:ads (source cards exist) or is legacy/external (source cards must be reverse-inferred).
Different volumes stabilize different metrics. Volume — not spend — is what determines statistical confidence. $100/day on $50 CPC enterprise keywords is 2 clicks; $100/day on $0.50 CPC long-tail keywords is 200 clicks. Same dollar amount, totally different reliability. Use the volume thresholds below as the primitives. Spend amounts are listed only as rough orientation.
Read this table and pick the most conservative mode that fits the unit being compared.
| Mode | Volume threshold (the actual gate) | Rough spend orientation | What's stable | What's still noise | |---|---|---|---|---| | Smoke-test | <500 impressions OR <20 clicks total in the window across all units | < $100/day | Almost nothing | Conversions, CTR, CPC at any level | | Ad-group | ≥2 ad groups each with 500+ impressions and 20+ clicks in the window | $100–$500/day | Ad-group-level CTR and CPC | Conversion rate at any level, ad-level metrics, CPA | | Ad | Per-ad: 1,000+ impressions and 30+ clicks for the ad in question | $500–$2,000/day | Ad-level CTR (only for ads meeting the threshold) | Conversion rate, CPA, ad-level CPC for low-volume ads | | Full resonance | All ad-mode thresholds met + 30+ total conversions in the window | > $2,000/day | All of the above + ad-level conversion rate | Headline-level attribution (Google does not expose this) |
The gates are AND, not OR. An ad with 5,000 impressions and 4 clicks doesn't qualify for ad mode (clicks too low). An ad group with 50,000 impressions but only 10 conversions doesn't qualify for full resonance (conversions too low).
Default thresholds can be overridden at runtime if the user explicitly says they know their data. Accept arguments like:
--min-impressions 200 (lowers the per-unit impression floor)--min-clicks 10--min-conversions 10--mode ad-group / --mode ad / --mode full-resonance (force a specific mode regardless of volume)When the user passes an override, state in the report what was overridden and to what value, so the user can interpret the confidence accordingly. Do not silently use looser thresholds than the data supports.
Hard rules — apply regardless of mode:
--min-conversions. State the conversion data, but frame any conclusion as "early signal, needs more volume to validate." A single conversion is correlation, not causation.Pick the mode now and state it explicitly at the top of the resonance map output so the user knows the confidence floor before reading the findings.
Two paths into this step:
Path A — Campaign was generated by /octave:ads (source cards exist):
Campaigns generated by /octave:ads automatically persist source cards to ~/.octave/source_cards/<workspace_slug>/<campaign_slug>.json, with final headlines populated after creative generation. The file contains the campaign metadata, the full source cards, and a headlines_by_variant mapping from each variant to the actual headlines that were generated. The schema is defined in source-cards.template.json.
To use Path A in the resonance loop:
~/.octave/source_cards/ for subdirectories. Each subdirectory is a workspace slug.headlines_by_variant field.If no source card files exist (the campaigns running in BigQuery weren't generated by /octave:ads — e.g., they were created in the Google Ads UI directly), fall through to Path B (reverse-inference).
Path B — Legacy or externally created campaign (no source cards):
For everything currently running in production that wasn't generated by /octave:ads, the resonance loop has to reverse-infer the variant type and source card from the headlines themselves. This is a much weaker form of analysis — you're looking at the output and guessing what the brief was. Be honest about this in the report: a winning headline tells you what worked, but without the original brief you can only speculate about which underlying angle made it work.
The reverse-inference process for legacy campaigns:
/octave:ads so the next loop iteration can use Path A. The strongest version of the resonance loop requires that the campaign and the analysis share a vocabulary.For each variant with performance data (Path A) or each ad group (Path B at small spend), produce the map. The template adapts to the mode picked in 2.1 — at small spend, there are no per-variant winners to list; the unit of comparison is ad groups.
Standard template (ad mode or full resonance mode):
## Resonance Map
**Data window**: {start} – {end} ({N} days) | **Spend**: ${X} | **Total impressions**: {N} | **Total conversions**: {N}
**Mode**: {smoke-test | ad-group | ad | full resonance}
**Path**: {A — source cards exist | B — reverse-inferred from headlines}
### Winners (top performing variants)
| Variant | Type | Ad Set | CTR | Conv Rate | Source Card | Derivation Chain | Confidence |
|---------|------|--------|-----|-----------|-------------|-----------------|------------|
| "Still Prepping Audits By Hand?" | Pain-focused | VP Eng × FinServ | 3.2% | 1.8% | Pain Language Audit | Finding F-123 (call w/ Acme, 2 weeks ago) → emotional core: "fear of failed audits" → headline | HIGH |
**What this tells us**: The pain of manual audit prep resonates more strongly than the cost-of-inaction framing for VP Engineering personas. The winning language traces to a specific finding from a real sales call — this isn't just ad performance, it's market validation of a pain point.
### Underperformers (below-average variants)
| Variant | Type | Ad Set | CTR | Conv Rate | Source Card | Hypothesis for Underperformance | Confidence |
|---------|------|--------|-----|-----------|-------------|-------------------------------|------------|
| "Every Hire Starts From Zero" | Status quo | VP Eng × FinServ | 0.4% | 0.1% | Compounding Cost Model | The compounding narrative may be too abstract for search intent — buyers searching for solutions want immediate pain acknowledgment, not long-term projections | MEDIUM |
Small-spend template (ad-group mode):
When the data only supports ad-group comparisons, lead with the CPC gap finding instead of variant-level analysis:
## Resonance Map
**Data window**: {start} – {end} ({N} days) | **Spend**: ${X} | **Total conversions**: {N}
**Mode**: ad-group (spend too low for ad-level conclusions)
**Path**: {A | B}
### Ad Group Comparison
| Ad Group | Campaign | Impr | Clicks | CTR | Conv | Cost | CPC | Confidence |
|---|---|---|---|---|---|---|---|---|
| VP Eng × Enterprise FinServ | Compliance Automation Q1 | 1,000 | 60 | 6.00% | 1 | $180 | $3.00 | HIGH |
| Director Compliance × Mid-Market | Compliance Automation Q1 | 400 | 15 | 3.75% | 0 | $225 | $15.00 | HIGH |
**Key finding**: The Director Compliance ad group costs ~5x more per click than the VP Eng ad group and converts at 0% vs ~1.5% over the window. This is a Quality Score / keyword-creative match gap, not a creative gap alone — even rewriting the ads will not close a CPC delta this large without keyword changes.
**Actionable**: Pause or rework the Director Compliance ad group. Move budget to VP Eng. Expected effect: ~5x more clicks per dollar at the same total spend.
### Per-ad observations (FYI only — too noisy to act on)
[List ads with their headlines and metrics, but explicitly do NOT rank them or label winners/losers. The ad-group finding is the actionable one.]
Confidence tiers for the resonance map:
Based on the resonance map, generate specific, actionable recommendations for the Octave library:
## Library Update Recommendations
### Persona Updates
| Persona | Field | Current | Recommended Update | Evidence |
|---------|-------|---------|-------------------|----------|
| VP Engineering | Primary pain point | "Tool sprawl across compliance stack" | "Manual audit preparation that doesn't scale" | Pain-focused variant at 3.2% CTR vs status-quo at 0.4% — manual process pain resonates 8x stronger than tool sprawl framing |
### Playbook Updates
| Playbook | Update | Evidence |
|----------|--------|----------|
| Enterprise FinServ | Add discovery opener: "How are you handling audit prep today?" | Derived from winning headline "Still Prepping Audits By Hand?" — 3.2% CTR proves this question self-selects the right buyer |
### Value Prop Updates
| Value Prop | Update | Evidence |
|------------|--------|----------|
| Compliance Automation | Reframe from "reduce risk" to "eliminate manual audit prep" | Pain-focused (manual process) outperformed authority (risk reduction) by 4x in CTR |
For each recommendation, ask the user whether to apply it:
AskUserQuestion({
questions: [{
question: "Apply these library updates?",
header: "Library Updates",
options: [
{ label: "Apply all", description: "Update personas and Motion Playbook narratives based on ad performance evidence" },
{ label: "Let me pick", description: "Review each recommendation individually" },
{ label: "Save as findings only", description: "Don't update the library yet — save these as findings for later review" },
{ label: "Skip", description: "Review only, no changes" }
],
multiSelect: false
}]
})
If they choose to apply updates, use the appropriate MCP tools. For Motion Playbook narrative edits (Strategic narrative, Benefits and impacts, Pains and consequences sections inside a Motion ICP cell), use update_motion_playbook:
→ {octave_mcp}__update_entity(oId: "{persona_oId}", instructions: "{update}")
→ {octave_mcp}__update_motion_playbook(motionPlaybookOId: "{motion_playbook_oId}", instructions: "{update}")
Generate a Sales Intelligence Brief — a summary designed for sales teams showing what language the market is responding to:
## Sales Intelligence Brief — From Ad Performance
### Winning Messages (use these in conversations)
| Message | Where It Won | Suggested Sales Use |
|---------|-------------|-------------------|
| "Still prepping audits by hand?" | Google Search, 3.2% CTR, VP Eng | Discovery opener — ask this in the first 2 minutes |
| "Audit prep: 3 weeks → 2 days" | Google Search, 2.8% CTR, VP Eng | Proof point framing — lead with this specific transformation |
### Messages That Didn't Land (avoid or reframe)
| Message | Where It Failed | Why | Alternative |
|---------|----------------|-----|------------|
| "Every hire starts from zero" | Google Search, 0.4% CTR | Too abstract for search intent | Reframe to concrete: "New hires spend 6 weeks learning your compliance process" |
### Persona Insight
{Persona}: The ad data confirms this buyer responds to **immediate, tangible process pain** over **strategic risk framing**. Lead with "how are you doing X today?" not "what happens if X breaks?"
Based on what worked, recommend the next campaign iteration:
## Next Campaign Recommendations
### Double Down
- **Pain-focused variants won across all ad sets** → Next campaign: allocate 60% of budget to pain-focused variants, test 3 pain sub-angles (manual process, time waste, audit failure risk)
- **VP Engineering was the top-converting persona** → Consider increasing bid/budget for this ad set
### Test Next
- **Question-based variant showed high CTR but low conversion** → The question stops the scroll but the landing page may not match. Test a dedicated landing page that mirrors the question framing.
- **No data on Meta/LinkedIn yet** → Repurpose the top 3 Google winners as Meta ads to test cross-platform resonance
### Retire
- **Status quo / cost of inaction variants underperformed everywhere** → Retire this variant type for this persona. The Compounding Cost Model may apply better to executive personas (CFO/CEO) who think in longer time horizons.
Offer to build the next iteration with /octave:ads so its source cards feed the next loop run (Path A).
This step turns the resonance loop from a one-shot analyzer into an iterative scientific instrument with a verifiable track record. Read prediction-cards.md for the full schema, prediction types, persistence model, self-tuning rules, and the empirical lessons from prior backtests. That doc is the source of truth for everything in this step.
The principle: at the end of every loop run, write down explicit, falsifiable predictions about what specific metrics will do over a specific window. The next time the loop runs, evaluate the previous predictions against actual data and report a track record. Over time, calibration accumulates and the loop tunes its own confidence based on its own history of being right and wrong.
At the start of every loop run, before producing any new resonance map:
Determine the MCC ID and today's date (the loop needs both to find the right file and evaluate predictions):
bq ls <project>:<dataset> and look for tables matching ads_Campaign_<digits>. The digits are the MCC ID. If multiple MCCs are present, ask the user which to analyze.date -u +%Y-%m-%d via the Bash tool, OR use the currentDate value from the system context if available.Then read previous predictions:
~/.octave/predictions/<MCC_ID>.json. If the file doesn't exist, this is the first run for this account — skip to 6.3 (no previous predictions to evaluate). On first run, copy prediction-cards.template.json to the destination path as the starter file.status: PENDING whose evaluation_window end date is on or before today.evaluation_sql field — the loop generates SQL queries at prediction-creation time and stores them in the card so re-evaluation is deterministic. Substitute the placeholders (<project>, <dataset>, <MCC>, <window_start>, <window_end>) with the actual values, then run via bq query.confirms / refutes / inconclusive conditions to the query result. Update the card with one of: CONFIRMED, REFUTED, INCONCLUSIVE_FAVORABLE, INCONCLUSIVE_UNFAVORABLE, or leave as PENDING with a partial_evaluation block if the window data isn't fully landed yet (the BQ data only goes through yesterday — anything past that is PENDING).evaluation_window end date is within the last refresh_lag_days (typically 7), set tentative: true on the card regardless of which resolution status you assigned. Both CONFIRMED and REFUTED can flip inside the refresh window — late-reported data can push rate metrics in either direction (CTR can drop if impressions grow faster than clicks; conversion rate can rise if late conversions come in; CPC can change as total cost adjusts). Only set tentative: false once the evaluation window has aged past window_end + refresh_lag_days. Tentative cards are re-evaluated on every subsequent run until they finalize. See prediction-cards.md § "Common pitfalls" #7 for the full rule and the empirical backtest evidence behind it.evaluated_at, evaluated_against, and evaluation_notes for each updated card.action_if_<status> instructions — most often this means promoting/demoting source cards in the library, NOT changing campaigns autonomously.Before showing the new resonance map, show the user a summary of what the last run's predictions said and how they resolved:
## Previous Predictions Evaluated
| ID | Type | Claim | Status | Notes |
|---|---|---|---|---|
| P-2026-04-03-004 | cpc-efficiency-gap | CPC gap holds at >= 3x | ✅ CONFIRMED | Held at ~5x via a new ad group that didn't exist at prediction time |
| P-2026-04-03-002 | regression-to-mean | Pilot ad group conv rate regresses to 0-3% | 🟡 INCONCLUSIVE_FAVORABLE | Volume gate failed (8 clicks); directional signal supports the prediction |
| P-2026-04-03-001 | regression-to-mean | Pilot ad group CTR regresses to 4-6% | 🟡 INCONCLUSIVE_UNFAVORABLE | Volume gate failed; CTR moved away from prediction |
| P-2026-04-03-003 | exposure-projection | Director Compliance reaches 30 clicks in 7 days | ⏳ PENDING | 4 of 7 days available; on track to refute |
**Track record so far**: 1 confirmed / 0 refuted / 2 inconclusive (1 favorable, 1 unfavorable) / 1 pending
**Strongest type**: cpc-efficiency-gap (1/1 confirmed)
This panel is the user-facing magic. It builds trust by being honest about what the loop got right and wrong last time.
After producing the new resonance map (Steps 2–5), generate 3–6 new prediction cards covering the strongest claims in the current run. Read prediction-cards.md for the full taxonomy of prediction types and the rules for each.
Hard rules for prediction generation:
field-stability prediction per run. It's a meta-prediction about whether the cast of ad groups will change, and it's the first signal the loop has about whether to weight structural vs unit-specific claims more heavily on the next run.regression-to-mean predictions for units below the volume gate. Compute (current run rate clicks/day) * 7 >= volume_gate. If false, generate an exposure-projection instead — those can be confirmed even at low volume.For each new card, fill in every field of the schema (see prediction-cards.md § "The prediction card schema"). Required fields: id, generated_at, generated_by, mode, is_structural, claim, type, evaluation_window, evidence_at_prediction, confirms (natural language), refutes (natural language), inconclusive (natural language), evaluation_sql (the parameterized SQL query that produces the data needed to apply the confirm/refute/inconclusive conditions — uses placeholders <project>, <dataset>, <MCC>, <window_start>, <window_end>), confidence, rationale, action_if_confirmed, action_if_refuted, action_if_inconclusive, status: PENDING.
The evaluation_sql field is what makes the loop deterministic across runs. Without it, the next session has to interpret the natural-language confirms field and reconstruct a query — different sessions may write different queries. Always emit the SQL at generation time so re-evaluation is mechanical, not interpretive. See prediction-cards.template.json for example schemas with evaluation_sql filled in.
After all evaluation and generation is complete, recompute the calibration block at the bottom of the JSON file:
total_predictions, evaluated, pending, confirmed, refuted, inconclusive_favorable, inconclusive_unfavorabledirectional_hit_rate: (confirmed + inconclusive_favorable) / (resolved predictions)by_type: per-prediction-type breakdown with hit rateslessons: append any new lessons learned from this run (especially if a previously confirmed type just got refuted, or vice versa)Write the file back to ~/.octave/predictions/<MCC_ID>.json. Include a brief mention in the loop's user-facing output: "Updated prediction track record at ~/.octave/predictions/<MCC_ID>.json — N new predictions generated, evaluate by [date]."
Tell the user when the next meaningful prediction resolution will occur:
## Upcoming Prediction Evaluation Dates
| Earliest evaluation | Predictions resolving |
|---|---|
| 2026-04-13 | P-2026-04-07-001 (CPC gap), P-2026-04-07-002 (CPC tier distribution), P-2026-04-07-003 (VP Eng ad group reaches 100 clicks) |
| 2026-04-13 | P-2026-04-07-004 (conversions reach 5), P-2026-04-07-005 (field stability) |
Re-run `/octave:ads-resonance` on or after 2026-04-13 to see how these resolved.
This gives the user a reason to come back. It's also a hint for setting up a recurring run (see "Cadence and scheduling" in prediction-cards.md).
After the chat-markdown resonance map, library updates, sales brief, next-campaign recommendations, and prediction cards have been generated, offer to also produce self-contained HTML reports for longitudinal consumption:
AskUserQuestion({
questions: [{
question: "Generate HTML reports alongside the chat output?",
header: "HTML reports",
options: [
{ label: "Both reports", description: "Resonance report (this run's findings) + Prediction dashboard (full calibration track record)" },
{ label: "Resonance report only", description: "Self-contained HTML of this run's findings, saved to ~/Desktop/" },
{ label: "Prediction dashboard only", description: "Self-contained HTML showing all active and resolved predictions with calibration stats, saved to ~/Desktop/" },
{ label: "Skip", description: "Chat output is enough" }
],
multiSelect: false
}]
})
~/Desktop/resonance-report-<workspace-slug>-<YYYY-MM-DD>.html.~/Desktop/prediction-dashboard-<workspace-slug>-<YYYY-MM-DD>.html. Reads from ~/.octave/predictions/<MCC_ID>.json.Both reports are self-contained single HTML files with inline CSS and inline SVG charts — no external JS, no external images, only Google Fonts via CDN. They work offline after first load, print cleanly, and can be shared as a single file attachment.
Tell the user the path(s) after generating and suggest opening with open <path> (macOS) or double-click.
If the loop cannot read or write the predictions file (permissions, disk full, etc.):
~/.octave/predictions/<MCC_ID>.json. Calibration tracking is disabled for this run."If the schema version of an existing file is NEWER than what the current loop knows about (current: v0.2):
/octave:ads - Build the ad campaigns this loop analyzes (persists the source cards that unlock Path A)/octave:library - Review and refine the personas, Motion Playbooks, and value props the loop recommends updating/octave:insights - Field intelligence from calls and emails (the conversational counterpart to ad resonance)development
Turn one or more Octave GTM Explorer / Beats reports into a branded, shareable digest with selectable insight scope, evidence depth, and output format. Use when the user asks for a report digest, weekly or monthly insight recap, executive intelligence brief, magazine-style insight story, report deck, or a recurring published summary of Octave insights.
content-media
Product and feature launch planning with full content kit generation across channels and audiences. Use when user says "launch plan", "product launch", "feature announcement", "GTM plan for launch", "launch content kit", or mentions launching something new.
development
A dense internal deal room a rep hands to a champion so they can run the buying-committee sell without you in the room. Quantified business case, stakeholder map with per-seat ammo, objection handling, and a path to yes, rendered as self-contained HTML. Use when user says "champion deal room", "arm my champion", "help my champion sell internally", "internal business case for [deal]", or wants a champion enablement doc. For a customer-facing top-of-funnel page use /octave:microsite; for the formal closing proposal use /octave:proposal.
data-ai
Analyze email threads, call transcripts, and conversations for resonance, adherence to messaging, and competitive differentiation. Use when user says "analyze this call", "how did the email land", "score this thread", "conversation analysis", or pastes conversation content to evaluate.