git:20261018.f9042b5 to git:20261019.f2424f9

16 added, 117 removed. Audit B to A.

---
name: market-mirror
- description: MarketMirror - test marketing and sales decisions on simulated buyers before spending. Builds diverse personas (country, age, upbringing, education, income, thinking style, communities) from any documents, then runs ad and creative tests in realistic Facebook/Instagram/Reddit/TikTok/LinkedIn/X feeds, split tests of messages, buyer surveys (free-text intent mapped to rating distributions, objections, word of mouth), multi-seed ranges, price testing (Van Westendorp), landing-page drop-off, spend/ROI/cost-per-lead projections calibrated to real ad data, past-ad analysis and backtests, an independent analyst panel, and a sales playbook per audience, all in a live dashboard with downloadable reports. Use when the user wants to test ads, messages, offers, prices, launches, positioning or sales pitches on an audience; predict how customers, students, parents, voters or the public will react; analyse past ad performance; estimate cost per lead or ROI; or mentions MarketMirror or MiroFish. Needs a shell and an Anthropic API key.
+ description: Analyze real ad data, research markets, survey simulated buyers, and test campaigns, pricing, sales pitches, and product journeys through MarketMirror MCP tools or the local CLI.
---
# MarketMirror
- MarketMirror simulates buyers. Concrete personas react to your material in realistic social feeds and answer a buyer survey, and you get a marketing and sales dashboard: who converts, what message wins, what stops people, what they would pay, and what spend would return. It runs locally on the user's own Anthropic key (engine: MiroFish, AGPL-3.0).
-
- All commands go through the helper next to this file:
-
- ```bash
- MM="<this skill's folder>/scripts/mm.sh" # e.g. ~/.claude/skills/market-mirror/scripts/mm.sh
- bash "$MM" help
- ```
-
- The engine lives in `~/.market-mirror/engine` unless `MARKET_MIRROR_HOME` says otherwise.
-
- ## 0. Ground rules
-
- - Simulated people are not real people. Always say so when reporting, show the sample size, and prefer directions ("parents in Manila look strongest") over precise claims. The dashboard shows 95% margins and flags small samples; repeat them.
- - Ground everything you can in real data (section 2). Ungrounded runs are brainstorming, not evidence.
- - Never print, echo or grep the API key. Ask the user to put it in `<engine>/.env`, or write it there with a file edit if they paste it.
- - Spend control: always stop after `prepare` and show the personas first. Say roughly how many Claude calls the next step makes before running rounds, surveys or feed tests.
-
- ## 1. Set up (first time, then just `doctor`)
-
- 1. `bash "$MM" setup` clones the engine, installs Python 3.12 deps with `uv`, creates `.env`. If `uv` is missing, relay the install options it prints.
- 2. `bash "$MM" doctor`. If the key is missing, ask the user to set `LLM_API_KEY` in `<engine>/.env` (a new key with a spending limit is best).
- 3. `bash "$MM" start` starts the backend on port 5001.
- 4. `bash "$MM" live` (in the background) serves the live dashboard at `http://127.0.0.1:5050/`. In the Claude desktop app open it in the browser pane; elsewhere give the user the link.
-
- **Fastest route for anyone (no files to write):** ask the user the nine quickstart questions in chat (brand; what they sell, for whom, at what price; who buys and where; platforms; what to test: ads, messages, price, launch, pitch; monthly budget; size small/medium/large; past ad export; extra documents), then `bash "$MM" cli quickstart --answers @answers.json` (or the `quickstart` MCP tool). It writes the scenario folder with template ads, messages, launch calendar, pitch and rebuttals, builds the simulated people and stops. Show the people and the `edit_first` list, improve the templates with real material (section 2) or `cli captions`, then run the printed `market-test` command with `"approve_spend": true`.
-
- ## 2. Gather real data first (use whatever tools this session has)
-
- | Source | How | Becomes |
- |---|---|---|
- | Ad accounts (Meta Ads, Google Ads connectors) | pull ads, ad sets, spend, impressions, clicks, landing page views, results, by country/age/placement | a CSV/JSON export, then `cli ads-import` |
- | Ads Manager export the user has | `cli ads-import export.csv --out <scenario>/past_ads.md` | seed file + `past_ads.json` benchmarks |
- | SEO/market tools (Semrush etc.), web search | competitors, keywords, prices, reviews, audience size | a Markdown seed file |
- | CRM, survey results, interviews, support tickets, reviews | export or paste | seed files; quote real objections |
- | Landing page | fetch it; time how long it loads on mobile; list form fields | the feed test `landing` block |
-
- Run the `research` MCP tool first (query = the product, category or a competitor; country = the App Store storefront that matters): it writes `research.md` (themes with linked quotes) and `voices.json`. Reddit usually blocks the tool; when the result says so, open the relevant subreddits with your own browser or search tools and add what you find as seed files. Put `"research": "<scenario>/research"` in `market_test.json` so the personas, feeds, report and test ideas draw on the real quotes. During a run, `push_context` sends one or two sentences of live reality (a thread you just read, a competitor move, news) into every persona card from the next round on.
-
- Put everything in a scenario folder: `bash "$MM" scenario <name> file1 file2 ...` (gitignored inside the engine).
-
- ## 3. Define the audience (persona spec)
-
- Write `<scenario>/personas.json`. Each segment gets real people with ages spread over the range, balanced genders, rotating cities, and balanced upbringing, education, income, thinking style, tech comfort and media diet; each person also gets one deliberate contradiction and realistic local names (never real people).
-
- ```json
- {"segments": [
- {"label": "Kenya young professionals", "count": 8, "country": "Kenya", "cities": ["Nairobi", "Mombasa"], "age_min": 22, "age_max": 35,
- "role": "young professional or freelancer", "entity_type": "Customer", "languages": ["English", "Swahili"], "platforms": ["Instagram", "TikTok"],
- "notes": "Pilot: highest cost per trial; questions about data use"}],
- "communities": [
- {"name": "Nairobi Runners & Gym Rats", "kind": "whatsapp_group", "segments": ["Kenya young professionals"], "norms": "data-cost conscious; compare by price"}],
- "keep_entities": ["Your brand name"]}
- ```
-
- Every person is then interviewed (12 life questions, 2 adaptive follow-ups, 3 questions about the product) and distilled into a BDE card (how they decide, what they pay for); add `"probes": false` to skip the second call, `"population": {country: {age/gender shares}}` to weight people to a real population mix. No spec? `--auto-personas 30` lets Claude plan segments and communities from the question. Up to 500 per segment and 2,000 in total are allowed; start with 20-40 and scale once the setup is right. `diversity` (top level or per segment) overrides the trait lists.
-
- ## 4. All in one (fastest)
-
- Write `<scenario>/market_test.json` (keys: name, title, brand, seeds, requirement, personas or auto_personas, creatives, seeds_n (repeat the feed test with N seeds; 3 for anything you will report), posts and events (brand posts and a launch calendar inside the rounds), rounds, survey {offer, goal, messages, split, pricing}, pitch {script, rebuttals, channel}, panel {analysts, brief}, report, approve_spend) and run `bash "$MM" cli market-test <scenario>/market_test.json`. The first run stops after creating the people and prints them: show them to the user. Then add the printed `simulation_id` and `"approve_spend": true` and run again. If the MCP tools are available (`market_test`, `job_status`, `results`), use those instead of the shell.
-
- The dashboard opens with a **go / iterate / no-go decision** combining every signal. Report it with its confidence and the "fix first" list.
-
- ## 5. Pick a recipe
-
- Run stage one for every recipe, then show the personas (`cli profiles --simulation <id> --brief`) before spending more:
-
- ```bash
- bash "$MM" cli run --seed <abs paths...> --requirement @<scenario>/requirement.txt \
- --personas <scenario>/personas.json --platform parallel --max-rounds 5 --stop-after prepare --out mirofish_runs/<name>
- ```
-
- `simulation_id` is in `<engine>/mirofish_runs/<name>/run_manifest.json`.
-
- **A. Ad and creative test (feed test).** Write `<scenario>/creatives.json`:
- ```json
- {"creatives": [{"id": "fb1", "platform": "facebook", "format": "image", "page": "Brand", "text": "...", "headline": "...",
- "cta": "Sign up", "media": "what the image shows", "image": "optional local image path",
- "segments": ["optional targeting"], "real_ad": "optional real ad name for backtests"}],
- "landing": {"load_seconds": 3.5, "language": "English", "shows": "...", "form_fields": ["name", "email", "phone"], "price": "free"},
- "benchmarks": {"facebook": {"cpm": 2.1, "ctr": 1.4, "budget": 500, "currency": "USD",
- "lead_value": 12, "close_rate": 0.1, "deal_value": 300, "gross_margin": 0.8}}}
- ```
- Then `bash "$MM" cli feedtest --simulation <id> --creatives @<scenario>/creatives.json --exposures 2 --seeds 3`. `--seeds N` repeats the test with N random seeds (N times the cost; the log prints Claude calls and tokens per seed) and reports each creative's mean and min-max range for expected CTR, thumb-stop and engagement, plus how often it ranked first. Use `--seeds 1` only for a quick check, and then report the result as a direction. Several creatives on one platform are split-tested automatically (each person sees one). Output: thumb-stop, CTR (realised and expected), engagement, hides, comments in the persona's voice, landing-page funnel with drop reasons, and spend projections: clicks, CPC, conversions, cost per lead, CAC, ROAS, ROI, break-even CPL, payback. Benchmarks from `ads-import` calibrate CTR to reality.
-
- **B. Message or offer test (buyer survey).** Needs the simulation running: `cli start --simulation <id> --max-rounds 3`, then
- `cli survey --simulation <id> --offer "..." --goal "sign up for X" --messages @<scenario>/messages.txt --split`.
- `--split` gives each person one message (a real A/B test); without it people pick their favourite.
- People answer interest, trust, purchase intent and recommendation in their own words first; the backend maps each answer to a 1-5 distribution by similarity to anchor statements with the local embedding model (semantic similarity rating, arXiv 2510.08338; free, no Claude calls). The dashboard's Ratings section shows the distributions and mean ± spread per audience, and "would convert" is the share who said yes (the SSR purchase mean drives go ≥ 3.75 / iterate ≥ 3.1). Quote intent as "3.4/5 ± 1.1", not the stated 0-10 numbers, which run high. If the log says SSR is unavailable, the stated numbers are used: say so when reporting.
-
- **C. Price test.** Add `--pricing USD` (any currency) to the survey: acceptable range, sweet spot, and "never pay" price by segment. Treat it as low confidence unless calibrated with real price data.
-
- **D. Past-ads analysis.** `cli ads-import <export.csv or .json> --out <scenario>/past_ads.md`. Read the seed it writes (best and worst ad sets, cost per conversion, landing-page loss), use it as a seed file, and pass `past_ads.json` as `--benchmarks` to the feed test.
-
- **E. Backtest (is the simulation any good here?).** Recreate 3+ past ads as creatives with `"real_ad": "<ad name in the export>"`, run the feed test, then `cli backtest --run-dir mirofish_runs/<name> --actuals <scenario>/past_ads.json`. Report the rank correlation, whether the winner matched, and the calibration factor. If it does not match, say the simulation is not predictive for this market yet.
-
- **F. Product or feature launch.** Seed: the launch announcement, pricing page and competitor notes. Write the brand's own captions (`cli captions --brief @brief.md --platform instagram --n 6`, or the user's real ones) as `posts.json` (day 0) and `events.json` (`[{"round": 1, "agent": "<brand name>", "platform": "both", "content": "teaser"}, {"round": 2, ...launch}, {"round": 4, ...offer}]`), run 6+ rounds with `--posts @posts.json --events @events.json` (or the `posts`/`events` keys in `market_test.json`). The dashboard's **Social feed** then shows every post by platform, round, audience and country, and a brand-posts strip with reach, reply sentiment, best and worst reply. Then the survey with the positioning lines as `--messages --split`.
-
- **G. Sales pitch rehearsal.** Seed: the pitch deck or call script and real objections from the CRM. Write `pitch.md` and `rebuttals.md` (`## price`, `## trust`, `## effort`, `## relevance`, `## privacy`, `## any`), then `cli pitch --simulation <id> --script @pitch.md --rebuttals @rebuttals.md --channel call` (or the `pitch` MCP tool; needs a live environment, so run rounds first). Every simulated buyer answers in their own voice, objects, asks a question back; objectors hear the matching rebuttal and say whether it moved them. Report the pitch score, the objections the rebuttals cannot handle ("fix first"), the hot leads with the best time to reach them, and the by-audience table. Lead scores also appear on the People cards and in `leads.csv`.
-
- **I. What to test next (from real data).** If the session has an ads connector (Meta, Google, TikTok), pull the ads with spend, impressions, clicks, conversions, country and age, and call the `ideas` MCP tool with those rows (or `cli ideas --rows @rows.json`), plus `--run-dir` of the last run and `--brand`. Without a connector use the user's export: `cli ideas --ads export.csv --run-dir mirofish_runs/<name>`. Each idea cites its evidence and carries the MarketMirror config to simulate it first; present them as a prioritised list and offer to run the top one.
-
- **M. One conclusion from several runs.** When the user wants to compare offers, prices or launch posts properly, or asks how sure we are: the `study` MCP tool (or `cli study --spec study.json`) runs every scenario with several seeds on the same people and returns a conclusion whose confidence comes from agreement across seeds. Quote the spread (mean ± interval) and the stability ("won in 3 of 3 seeds"), never a single cell. Then `predict` (MCP) turns the headline numbers into intervals that are scaled by the real results stored so far and labelled with their basis; run `backtest --brand X` or `calibrate` first whenever the user has real results, so the store learns.
-
- **K. Email campaigns.** Write `<scenario>/emails.json` (`{"emails": [{"id": "a", "from_name": "Brand", "subject": "...", "preheader": "...", "body": "...", "cta": "...", "send_time": "morning|midday|evening|night", "sequence": [{"delay_days": 2, "subject": "...", "body": "..."}]}], "list_size": 10000, "benchmarks": {"cost_per_send": 0.002, "lead_value": 12}}`) and run the `email_test` MCP tool or `cli emailtest --simulation <id> --emails @<scenario>/emails.json --list-size 10000`. Report open, click and unsubscribe rates per subject line and audience, the sequence funnel, the projection to leads, and every spam-word warning.
+ MarketMirror is your agent's marketing research and simulation lab. Analyze observed campaign performance, research customer feedback, survey and interview simulated buyers, compare campaigns and pricing, rehearse sales conversations, and test actual product URLs with synthetic visitors. Use the bundled MCP tools in any compatible agent, or `scripts/mm.sh cli ...` when MCP is unavailable. `doctor` checks the local engine; `setup` installs it if needed. `mm.sh home` shows the engine path. A checkout can be used directly with `MARKET_MIRROR_HOME` set to its absolute path.
- **L. Anything else, one spec.** The `run_test` MCP tool (or `cli test --simulation <id> --spec @test.json`) takes `{"type": ..., "variants": [...], "audience": {...}}` for ad, message, price, offer, positioning, naming, landing, launch, pitch, email, creator_post and channel_mix tests and returns one result shape: each variant's metric with a 95% margin, the winner, the lift, and whether it is clear or a tie. Use it when the user asks "can we test X" and X is not one of the recipes above.
+ ## Bring your agent's data
- **J. Is the panel trustworthy here?** Two checks, both cheap. `cli survey ... --retest 20` reports how many of twenty people give the same verdict a simulated week later (quote it as the reliability figure). When the user has 50-300 real answers (a real survey, Ads Manager results, email stats) export them as a CSV with segment, country, gender, age and y (yes/maybe/no or 0-1) and run the `calibrate` MCP tool (or `cli calibrate --run-dir ... --real answers.csv`): it returns trust / correct / walk-away per audience, the overlap between the real customers and the simulated panel, and a corrected rate with its standard error. Report the verdict before any number from that run, and use the corrected rate when the verdict is "correct".
+ When the calling agent has authorized advertising, analytics, CRM, or survey tools, use those tools to fetch relevant records. Pass exported CSV/JSON to `actuals_import` or `ads_import`; `ideas` also accepts ad rows directly from a connected ads tool. Retain the source, reporting period, market, metric definitions, and currency. Report missing access or fields and use supplied exports where available. MarketMirror does not automatically connect accounts or expand the agent's permissions. Its surveys interview simulated personas; imported human survey responses remain separate real evidence.
- **H. Second opinion.** `cli panel --simulation <id> --analysts 5 --brief "what we need to decide"`: independent analysts (performance marketer, brand strategist, sales lead, psychologist, sceptical data analyst, ...) each read the anonymized posts, comments, feed reactions and survey answers alone. Report the consensus and where they disagree.
+ For a real product URL, use `website_test` on prepared personas. The optional browser extra drives isolated Chromium sessions; agents can inspect the product, use the cart, reach signup or checkout, or leave. Supply named DOM checks and `goal_check` to verify outcomes independently. Account submission needs explicit opt-in and owned test identities; never submit payments or orders. Start with 1–3 visitors and review screenshots, traces, deliberate departures and execution failures separately. See `docs/WEBSITE_TESTING.md` in the engine checkout. Observed actions are synthetic visitor behavior, not measured human conversion.
- ## 6. Show the results
+ ## Workflow
- - Live: the browser pane at `http://127.0.0.1:5050/` updates as steps finish.
- - Final: `<engine>/mirofish_runs/<name>/dashboard.html` (one offline file). Publish it as an Artifact if available, otherwise send the file. The **Report** section (right under the decision) is written in plain language for non-technical readers and its header holds every download: this page, print/PDF, report (Markdown), action plan (JSON), survey answers and feed sessions (CSV), lead scores (CSV), pitch and social feed (JSON), test ideas, all numbers (JSON); the same files sit next to it (`market_report.md`, `leads.csv`, `pitch.json`, `ideas.md`...). The `results` MCP tool returns the report path, the action plan, pitch and ideas summaries.
- - In chat: lead with the decision (which audience, which message, what to fix first, expected cost per lead), then the evidence and its limits. Give ranges, not points: the feed-test range across seeds and the survey mean ± spread. If seeds disagree on the winning creative, call it a tie. Quote real comments from personas, labelled as simulated.
+ 1. `understand` product documents or an existing project. Read the resulting `product_profile.json`, including unknowns. `research` public feedback; retain cited URL, date, market and quality, and state blocked sources.
+ 2. `actuals_import` existing ads, email, website, CRM and survey CSV/JSON exports. Map columns explicitly and resolve validation errors. The old `ads_import` tool remains available for ad-specific seed files and benchmarks.
+ 3. `campaign_plan` takes a profile or project, goal, budget and optional channels. Review audiences, positioning, funnel metrics, allocations, proof gaps and the runnable `test_specs`. The plan is a draft; supplied claims need verification.
+ 4. `run_test` evaluates a relevant spec on prepared simulated buyers. For a controlled scenario comparison, use `study` with one simulation and the same seed list across variants. Poll `job_status`; finished cells resume on rerun. Search and organic content and referrals use a concept survey, lifecycle messages use the inbox engine, and sales outreach uses pitch rehearsal. Their simulated outcomes are not actual channel performance.
+ 5. `backtest` past ads and `holdout_backtest` independent real experiments. The latter compares the persona estimate against a no-persona training-mean baseline. An uncalibrated `predict` result is directional. A predictive claim needs held-out evidence that beats the baseline; otherwise label the conclusion exploratory.
+ 6. Open `results` and the saved dashboard, check the evidence and report paths, then recommend the next small real randomized test. Record audience, exposure, assignment, outcome, date, market and source. MarketMirror does not send campaigns or change ad accounts.
- ## 7. Costs and cleanup
+ ## Setup and access
- Feed tests call Claude only for exposures that catch someone's eye (most do not), plus one call per click for the landing page; `--seeds N` multiplies that by N. Rounds cost one call per active agent per round; surveys one per person; the panel one per analyst. `claude-haiku-4-5` is the cheap default; use a Sonnet model for final reports. `bash "$MM" stop` stops everything.
+ `bash scripts/mm.sh setup` installs the engine with `uv`; `bash scripts/mm.sh doctor` checks it. Choose an API-key or local-model provider, the documented eligible-user Sign in with ChatGPT option when configured, or a local `codex exec` / Claude CLI gateway. Run the backend with `bash scripts/mm.sh start`. The MCP server defaults to stdio: `bash scripts/mm.sh mcp`. To serve authenticated loopback MCP, provide a private bearer-token file: `bash scripts/mm.sh mcp --http --port 5061 --token-file /private/path/token`. Never commit or print tokens or API keys.
- ## Troubleshooting
+ Use `provider_setup` with `action:list` for official provider guides, `action:status` for masked configuration, and `action:check` for model discovery without an inference call. For hosted keys, direct the user to `mm.sh configure` in their own terminal (hidden input), or use a pre-existing environment variable through `key_env`. API keys must never be supplied in chat or tool arguments. Ollama and LM Studio support local use without a hosted API key; confirm the selected local model supports tools and structured output on a small fixture.
- `bash "$MM" doctor` first. Backend log: `<engine>/backend/logs/server.out`. A failed `run` still exports what it has. More detail: `<engine>/CLAUDE.md`.
+ Large simulations can consume substantial model calls. Review the intended audience and estimated work before running. Report measured calls, time and costs separately from estimates. Do not call simulated buyer comments real customer quotes. For focused workflows, use the bundled `research`, `planning`, `testing`, and `evidence-review` skills.