一键导入
cro-analyze
Full experiment analysis, report, insight capture, ship/kill PR. Triggered by bud_server webhook when a Roadmap entry's Status changes to 7-analyzing.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Full experiment analysis, report, insight capture, ship/kill PR. Triggered by bud_server webhook when a Roadmap entry's Status changes to 7-analyzing.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Twice-daily scan of idle pages (6 AM & 6 PM UTC): dispatch builds, notify when pages need prioritization, trigger research for empty backlogs. Runs as the first pass of the cro-monitor cron.
Build and ship an A/B test experiment from a prioritized hypothesis at 50/50 split. Triggered by bud_server webhook when a Roadmap entry's Status changes to 3-building.
Twice-daily experiment lifecycle (6 AM & 6 PM UTC): merge detection, validation, running checks, conclusion detection, ship/kill PR merge tracking. Runs as the second pass of the cro-monitor cron, after backlog_monitor.
Propagate Owner changes from the Page Registry to the Roadmap & Backlog. Triggered by Notion automation when the Owner field changes on a Page Registry entry.
Daily sync of the Notion Page Registry: pulls last-7-day traffic from BigQuery, adds new pages, updates Daily Traffic and CVR, syncs cross-database fields (insights, hypotheses, hit rate), and computes each page's Research Status. Runs as the cro-page-registry-sync Oz cron at 06:00 UTC.
Research website pages and generate A/B test hypotheses. Runs when triggered or on-demand for a single page. Discovers traffic sources, analyzes on-page behavior and visual design, then writes findings and hypotheses back to Notion.
| name | cro-analyze |
| description | Full experiment analysis, report, insight capture, ship/kill PR. Triggered by bud_server webhook when a Roadmap entry's Status changes to 7-analyzing. |
Read .warp/skills/cro/references/config.md for Notion IDs, data access, and status labels.
Read .warp/skills/cro/references/config-slack.md for Slack posting config (token, channels, Thread TS protocol).
Skill-specific config:
.warp/skills/cro/experiment_monitor/scripts/experiment.py.warp/skills/cro/experiment_monitor/scripts/monitoring_queries.sql.warp/skills/cro/references/priors.yamlbud_server passes these fields from the Notion webhook:
NOTION_PAGE_ID: <hypothesis-page-id>
EXPERIMENT_ID: example-hero-copy
PAGE_PATH: /example-page
Fetch the full Roadmap entry from Notion. Extract: Experiment Desc, Page, Method, Experiment ID, Build PR, Dash, Start Date, Slack Thread TS, Hypothesis, Change Type, Change Description.
Preflight required credentials before doing any analysis work. $NOTION_INTEGRATION_TOKEN must be present for Notion reads/writes, and either $GOOGLE_OAUTH_TOKEN or $METABASE_API_KEY must be present for experiment data. $EXPERIMENT_BUD_SLACK_BOT_TOKEN must be present before Step 6. If any required credential is missing, stop immediately and report that the triggering run is missing required Oz team secrets; do not attempt to work around missing credentials by spawning child agents, using alternate Slack tokens, or switching data sources.
SEO-only scope guard. Experiment Bud is CRO-only. Read references/config.md → Experiment Scope. If this entry is clearly SEO-only, do not create an analysis report, ship/kill PR, or Slack result. Log that the live SEO-only experiment needs human cleanup and exit. Do not silently mutate production artifacts for SEO-only tests.
Also fetch the Page Registry entry for the page to get Primary Metric, Secondary Metric(s), and Owner. Resolve {owner_mention} from Owner per references/config.md → Page Owners; if Owner is empty, omit the {owner_mention} line from the Slack post in Step 6.
Query experiment data using M1 and M3 from monitoring_queries.sql.
When adapting M1/M3 for the page's Primary Metric, preserve the conversion de-duplication pattern from monitoring_queries.sql: aggregate analytics.website_conversion to one row per anonymous_id + pageview_date with LOGICAL_OR metric fields before joining to experiment assignments. Do not count raw joined conversion rows directly, because duplicate conversion rows can materially overstate conversions and produce incorrect ship/kill decisions.
Run the appropriate analysis command based on the Method field from the Notion entry:
Frequentist:
python3 .warp/skills/cro/experiment_monitor/scripts/experiment.py significance \
--control-n {{CONTROL_N}} \
--control-conv {{CONTROL_CONVERSIONS}} \
--variant-n {{VARIANT_N}} \
--variant-conv {{VARIANT_CONVERSIONS}}
Bayesian:
python3 .warp/skills/cro/experiment_monitor/scripts/experiment.py bayesian \
--control-n {{CONTROL_N}} \
--control-conv {{CONTROL_CONVERSIONS}} \
--variant-n {{VARIANT_N}} \
--variant-conv {{VARIANT_CONVERSIONS}} \
--day {{CURRENT_DAY}} \
--max-days {{MAX_DAYS}}
The script returns a recommendation (frequentist) or decision (Bayesian) field with the ship/kill outcome. Use that directly — the thresholds and min sample guardrails are implemented in the script.
Also check the M3 paid vs organic breakout. Flag if they move in opposite directions.
Create a subpage under Reports (see config.md for Reports page ID).
Title: YYYY-MM-DD {{PAGE_PATH}} {{EXPERIMENT_ID}} Experiment Analysis
Report structure:
Save the report URL.
4a. Update Roadmap entry:
Result → win, loss, or inconclusiveLift → relative lift valueEnd Date → todayAnalysis Link → report URLDo not update Status in this skill. Leave the Roadmap entry at 7-analyzing after analysis and PR creation. experiment_monitor Phase 4 is the only step allowed to move an analyzed experiment to 9-shipped, 8-no-ship, or 8-inconclusive, and only after the ship/kill PR has merged, the production deployment containing it is live, and scoped production Sanity cleanup/promotion has completed. This prevents pages from becoming eligible for the next experiment while code-defined experiment cleanup is still unmerged.
4b. Create Analysis Log entry:
completed{{PAGE_PATH}}4c. Create Knowledge Base insight:
{{EXPERIMENT_ID}} — {result} ({relative_lift}% lift)experimentexperiment-result{{PAGE_PATH}}All code and markdown changes go in a single PR against your-org/your-marketing-site base branch main. Sanity is the runtime source of truth, but do not apply destructive production Sanity mutations before the ship/kill PR has merged and deployed; production may still be running the code-defined experiment until that deployment is live. Use the [ship-kill]/{{EXPERIMENT_ID}} branch convention. Do not run broad production pushes.
If ship (variant wins):
your-marketing-site/src/lib/ab/experiments/<experiment-id>.experiment.ts, then run pnpm run generate:experiments to regenerate experiments/index.ts. The middleware will stop intercepting traffic on next deploy.src/content/pages/<slug>-v<n>.md's frontmatter blocks over src/content/pages/<slug>.md (keep the control's title, slug, and seoNoindex — do NOT carry the variant's seoNoindex: true over to control). Then delete src/content/pages/<slug>-v<n>.md.experiment_monitor Phase 4. Do not patch production Sanity yet. After the ship/kill PR merges and the production deployment containing it is live, experiment_monitor will patch the production control page to the promoted content, then delete or mark completed the variant document and active experiment document.[Ship] {{EXPERIMENT_ID}} — variant wins.If no-ship (control wins or inconclusive):
your-marketing-site/src/lib/ab/experiments/<experiment-id>.experiment.ts, then run pnpm run generate:experiments to regenerate experiments/index.ts.rm src/content/pages/<slug>-v<n>.md.experiment_monitor Phase 4. Do not delete production Sanity artifacts yet. After the ship/kill PR merges and the production deployment containing it is live, experiment_monitor will delete or mark completed the active experiment document and delete the variant page document. Control content is untouched.[No-Ship] {{EXPERIMENT_ID}} — reverting to control.PR body: full analysis results, recommendation, link to Notion entry and report, list of files changed, plus a Post-merge production Sanity plan containing the exact control slug, variant slug, experiment ID, and expected cleanup/promotion actions for experiment_monitor.
Store the PR URL in the Roadmap entry's Ship/Kill PR field.
Follow the Slack Thread TS protocol from config-slack.md. Post the result to the experiment's thread.
Token: use ONLY $EXPERIMENT_BUD_SLACK_BOT_TOKEN. Use the canonical snippet from config-slack.md:
import json, os, sys, urllib.request
token = os.environ.get('EXPERIMENT_BUD_SLACK_BOT_TOKEN', '').strip()
if not token:
print("FATAL: EXPERIMENT_BUD_SLACK_BOT_TOKEN is unset. Refusing to post.", file=sys.stderr)
sys.exit(1)
payload = {'channel': 'SLACK_NOTIFICATIONS_CHANNEL_ID', 'text': message_text}
if thread_ts:
payload['thread_ts'] = thread_ts
req = urllib.request.Request(
'https://slack.com/api/chat.postMessage',
data=json.dumps(payload).encode('utf-8'),
headers={'Authorization': f'Bearer {token}', 'Content-Type': 'application/json; charset=utf-8'},
)
with urllib.request.urlopen(req) as resp:
result = json.loads(resp.read().decode('utf-8'))
if not result.get('ok'):
print(f"Slack post failed: {result.get('error')}", file=sys.stderr)
sys.exit(1)
Message templates:
Omit the final {owner_mention} line entirely if Owner is empty.
Frequentist format:
{emoji} Experiment Complete — {experiment_desc}
{page_path} · {duration} days · {total_visitors} visitors
• Control: {control_cvr}% · Variant: {variant_cvr}%
• {relative_lift}% lift · p={p_value}
{one_line_learning}
🔗 <{pr_url}|Ship/Kill PR> · <{report_url}|Report>
{owner_mention}
Bayesian format:
{emoji} Experiment Complete — {experiment_desc}
{page_path} · {duration} days · {total_visitors} visitors
• Control: {control_cvr}% · Variant: {variant_cvr}%
• P(variant > control): {prob}% · Expected uplift: {uplift}%
{one_line_learning}
🔗 <{pr_url}|Ship/Kill PR> · <{report_url}|Report>
{owner_mention}
Use 🟢 for ship, 🔴 for no-ship, 🟡 for inconclusive.
main on your-org/your-marketing-site. Ship/kill changes go through PRs.cro-analyze records the result, report, and ship/kill PR but must leave Status = 7-analyzing. Final status is owned by experiment_monitor after PR merge, production deploy, and scoped Sanity cleanup.experiments/ and the markdown variant file is necessary but not sufficient — the production Sanity experiment doc and affected page docs must also reflect the new state, or users will see stale variants.