Backlog Monitor
Configuration
Read .warp/skills/cro/references/config.md for Notion IDs and data access.
Read .warp/skills/cro/references/config-slack.md for Slack posting config (token, channels, Thread TS protocol).
Operating Rules
- One experiment per page. Never dispatch a build on a page that has an active experiment (Status in
3-building,4-ready for review,5-live:validating,6-live:running,7-analyzing). Also treat a page as blocked if it has a recently analyzed final-status row (8-no-ship,8-inconclusive, or9-shipped) with a non-emptyShip/Kill PRthat has not merged yet; that is a lifecycle inconsistency, not an idle page. - CRO-only scope. Never dispatch SEO-only tests. Read
references/config.md→ Experiment Scope. If a1-proposed,2-prioritized, or3-buildingRoadmap entry is clearly SEO-only, set Status →0-archived, log the reason in the agent session, and do not post to Slack. - Only process experiment-eligible pages. Skip Page Registry entries whose
Research Statusislow-traffic,cro-excluded, orneeds-primary-metric; do not dispatch builds, request prioritization, trigger research, or post Slack messages for them. - Agents never prioritize. Never change status to
2-prioritized. - No duplicate idle reminders. Do not post a new page-level idle notification if an existing top-level idle notification for the same page is already present in #your-notifications-channel. The existing message is the reminder; repeated cron runs must stay silent.
- Parallel dispatches are fine. Multiple pages can have builds dispatched in the same run — each triggers its own agent.
- Follow the Slack Thread TS protocol from
config-slack.mdfor all posts. - Slack token: use ONLY
$EXPERIMENT_BUD_SLACK_BOT_TOKEN. See the Token section inconfig-slack.mdfor the full rule.
Procedure
Step 1: Read pipeline state
Query the Roadmap & Backlog for all non-archived entries:
curl -s -X POST "https://api.notion.com/v1/databases/NOTION_ROADMAP_DB_ID/query" \
-H "Authorization: Bearer $NOTION_INTEGRATION_TOKEN" \
-H "Notion-Version: 2022-06-28" \
-H "Content-Type: application/json" \
-d '{"filter": {"property": "Status", "select": {"does_not_equal": "0-archived"}}}'
Before grouping, classify Roadmap entries with the SEO-only scope rules in references/config.md. Archive clearly SEO-only entries in 1-proposed, 2-prioritized, or 3-building by setting Status → 0-archived; exclude them from active/prioritized/proposed counts. Do not post a Slack notification for this cleanup.
Group by Page path. For each page, note:
- Active experiments: any entry with Status in
3-building,4-ready for review,5-live:validating,6-live:running,7-analyzing - Pending cleanup experiments: any entry with Status in
8-no-ship,8-inconclusive, or9-shippedand a non-emptyShip/Kill PR. Check the PR state withgh pr view. If the PR is not merged, count the page as active/blocked, logLifecycle inconsistency: final status but Ship/Kill PR unmerged for {page_path}: {pr_url}, and do not dispatch another build or post an idle-page notification for that page. - Prioritized hypotheses: Status =
2-prioritized, sorted by RICE Score descending - Proposed hypotheses: Status =
1-proposed
Also query the Page Registry for all pages where:
CRO Excluded = falseResearch Statusis NOTlow-trafficResearch Statusis NOTcro-excludedResearch Statusis NOTneeds-primary-metric
For each eligible page, also read:
Owner— determines who to @-mention in page-specific Slack posts (seereferences/config.md→ Page Owners)Daily Traffic— used only as a defensive cross-check; if it is present and< 50, skip the page silently even ifResearch Statusis staleResearch Status— log skip reasons in agent output if an ineligible page appears in the result set unexpectedly
Pages with ineligible research statuses are waiting on traffic or human input — don't auto-dispatch builds, request prioritization, trigger research, or post Slack messages for them. page_registry_sync will auto-advance them once they become eligible. If Daily Traffic is present and < 50, skip the page silently even if Research Status is stale.
Step 2: Process each idle page
For each experiment-eligible page with no active experiment:
2a. Has 2-prioritized hypotheses → dispatch build
Pick the highest RICE score entry. Update its status to 3-building:
curl -s -X PATCH "https://api.notion.com/v1/pages/{{HYPOTHESIS_PAGE_ID}}" \
-H "Authorization: Bearer $NOTION_INTEGRATION_TOKEN" \
-H "Notion-Version: 2022-06-28" \
-H "Content-Type: application/json" \
-d '{"properties": {"Status": {"select": {"name": "3-building"}}}}'
This triggers the build agent via Notion automation → bud_server.
The build agent handles the Slack notification for this experiment.
2b. No 2-prioritized but has 1-proposed → request prioritization
Before posting, dedupe against existing page-level idle reminders:
- Call Slack
conversations.historyfor #your-notifications-channel (SLACK_NOTIFICATIONS_CHANNEL_ID) and scan recent top-level messages from theexperiment-budapp, paginating at least 30 days back or 1,000 messages, whichever comes first. - Treat messages from either
app_id = SLACK_APP_ID,bot_id = SLACK_BOT_ID, oruser = SLACK_BOT_USER_IDas Experiment Bud messages. Do not rely onusername. - For each candidate idle reminder, parse the page path with this exact regex so both rendered emoji and Slack emoji aliases are handled:
^(?:⏳|:hourglass_flowing_sand:)\s+(.*?)\s+is idle(?:\s+with|:)Compare that parsed path to the currentpage_pathusing exact string equality after trimming whitespace. Do not use substring matching because the homepage path/would match every page path. - If any candidate has the same parsed page path and the idle-reminder phrase
is idleplusproposed hypothesplusnone prioritized, skip posting for that page. LogSkipping duplicate idle reminder for {page_path}: existing Slack message {ts}in the agent output. - Only post if no existing idle reminder for that page is found.
Post to #your-notifications-channel (as a new message, not threaded — this is a page-level notification). Use the canonical snippet from config-slack.md with channel='SLACK_NOTIFICATIONS_CHANNEL_ID' and no thread_ts. Resolve {owner_mention} from the page's Owner (per config-slack.md → Page Owners); if Owner is empty, omit the mention entirely.
Do not post this notification for pages whose Research Status is low-traffic, cro-excluded, or needs-primary-metric, or whose Daily Traffic is present and < 50. These pages are not currently experiment-eligible, so asking humans to prioritize hypotheses creates noise.
⏳ {page_path} is idle: {n} proposed {hypothesis/hypotheses}, none prioritized.
{owner_mention} — choose the next experiment in <{roadmap_url}|Roadmap>: prioritize an existing idea or add a new one with status 2-prioritized.
Use hypothesis when n=1; otherwise use hypotheses.
2c. No hypotheses at all (no 1-proposed, no 2-prioritized) → trigger research
Update the Page Registry entry's Research Status to generate-more-hypotheses:
curl -s -X PATCH "https://api.notion.com/v1/pages/{{PAGE_REGISTRY_ENTRY_ID}}" \
-H "Authorization: Bearer $NOTION_INTEGRATION_TOKEN" \
-H "Notion-Version: 2022-06-28" \
-H "Content-Type: application/json" \
-d '{"properties": {"Research Status": {"select": {"name": "generate-more-hypotheses"}}}}'
This triggers the research agent via Notion automation → bud_server.
Step 3: Done
This skill's only Slack output is the ⏳ idle page notification from Step 2b.