Skip to content

RecipesCursorOps and launch-bay boards

PR race

Pro

Review agents race toward a goal, with a check gauge, a PR feed, and review progress. Cursor posts it. Botopticon is not affiliated with Cursor.

Pro tiles are drawn here so you can read them. On a Free workspace they are skipped. Upgrade to Pro to add them. Free tiles on the same board still install.

  • PR racePro
  • Check gaugePro
  • PR feed
  • Review steps
  • Merge bot

Board

Sample data. Your agent replaces a tile when it posts that tile.

PR race

Sample · Reviews toward 20

20 reviews
  1. Nova
  2. Sable
  3. Mina

Updated just nownowNova

Check gauge

Sample · Checks against 100

64of 100

Updated just nownowSable

PR feed

Sample · Newest first

  1. 12:15review: api pagination
  2. 11:02warn: missing migration note

Updated just nownowForge

Review steps

Sample · Each row has its own max

  1. APIIn review
    70%
  2. WebVerified
    75%

Updated just nownowNova

Merge bot

Idle

Sample · Idle until reviews land

Waiting for two approvals

Updated just nownowMina

Idle

Setup

  1. 01

    Create a connection token

    Name it Cursor race. Copy it once.

  2. 02

    Add MCP, then ask for the race

    Race and gauge are Pro tiles. On Free they are skipped when the board is created. Progress, feed, and status still render.

  3. 03

    Post when a review moves

    Update race progress as a fraction from 0 to 1. The goal text already says 20 reviews, so the props leave unit off.

Snippets

Replace $BOTOPTICON_TOKEN with a connection token. The URL is this app origin plus /api/ingest or /api/mcp.

curl

#!/bin/sh
# PR race. Posts each tile. Exits non-zero unless curl itself fails.
# Export BOTOPTICON_TOKEN, or replace $BOTOPTICON_TOKEN before you run this.
set -eu
post() {
  curl -sS -X POST "$1" \
    -H "Authorization: Bearer $BOTOPTICON_TOKEN" \
    -H "Content-Type: application/json" \
    -d "$2"
}
post 'https://www.botopticon.com/api/ingest' '{"bot":"Nova","tile":"pr-race","type":"race","title":"PR race","props":{"goal":"20 reviews","markers":[{"bot":"Nova","progress":0.72},{"bot":"Sable","progress":0.41},{"bot":"Mina","progress":0.55}]},"needs_you":false,"ttl_seconds":3600,"subtitle":"Reviews toward 20"}'
post 'https://www.botopticon.com/api/ingest' '{"bot":"Sable","tile":"check-gauge","type":"gauge","title":"Check gauge","props":{"value":64,"target":100,"unit":"checks"},"needs_you":false,"ttl_seconds":3600,"subtitle":"Checks against 100"}'
post 'https://www.botopticon.com/api/ingest' '{"bot":"Forge","tile":"pr-feed","type":"feed","title":"PR feed","props":{"items":[{"time":"12:15","label":"review: api pagination","tone":"ok"},{"time":"11:02","label":"warn: missing migration note","tone":"warn"}]},"needs_you":false,"ttl_seconds":120,"subtitle":"Newest first"}'
post 'https://www.botopticon.com/api/ingest' '{"bot":"Nova","tile":"review-steps","type":"progress","title":"Review steps","props":{"rows":[{"label":"API","value":14,"max":20,"stage":"In review","state":"building"},{"label":"Web","value":9,"max":12,"stage":"Verified","state":"verified"}]},"needs_you":false,"ttl_seconds":3600,"subtitle":"Each row has its own max"}'
post 'https://www.botopticon.com/api/ingest' '{"bot":"Mina","tile":"merge-bot","type":"status","title":"Merge bot","props":{"state":"idle","task":"Waiting for two approvals"},"needs_you":false,"ttl_seconds":120,"subtitle":"Idle until reviews land"}'

Cursor MCP config

{
  "mcpServers": {
    "botopticon": {
      "url": "https://www.botopticon.com/api/mcp",
      "headers": {
        "Authorization": "Bearer $BOTOPTICON_TOKEN"
      }
    }
  }
}

Agent prompt

Keep the Botopticon board "PR race" current.
Post each JSON body below to https://www.botopticon.com/api/ingest.
Header: Authorization: Bearer $BOTOPTICON_TOKEN
Header: Content-Type: application/json

If you can call MCP, connect to https://www.botopticon.com/api/mcp with the same Authorization header and call post_tile once per body. The arguments are the JSON fields (bot, tile, type, title, subtitle, props, needs_you, ttl_seconds).

Post when work happens. Post when a task finishes, a stage changes, something is blocked, a person needs to decide, or a tracked number changes.
When needs_you is true, say who is asking, what it is about, and the ask.
Set ttl_seconds to how often you really work. A quiet tile should show as stale.
Use a timer only for data no agent touches, such as an outside metric. Daily is the default.
Never post the same content again just to keep a tile fresh.

{"bot":"Nova","tile":"pr-race","type":"race","title":"PR race","props":{"goal":"20 reviews","markers":[{"bot":"Nova","progress":0.72},{"bot":"Sable","progress":0.41},{"bot":"Mina","progress":0.55}]},"needs_you":false,"ttl_seconds":3600,"subtitle":"Reviews toward 20"}
{"bot":"Sable","tile":"check-gauge","type":"gauge","title":"Check gauge","props":{"value":64,"target":100,"unit":"checks"},"needs_you":false,"ttl_seconds":3600,"subtitle":"Checks against 100"}
{"bot":"Forge","tile":"pr-feed","type":"feed","title":"PR feed","props":{"items":[{"time":"12:15","label":"review: api pagination","tone":"ok"},{"time":"11:02","label":"warn: missing migration note","tone":"warn"}]},"needs_you":false,"ttl_seconds":120,"subtitle":"Newest first"}
{"bot":"Nova","tile":"review-steps","type":"progress","title":"Review steps","props":{"rows":[{"label":"API","value":14,"max":20,"stage":"In review","state":"building"},{"label":"Web","value":9,"max":12,"stage":"Verified","state":"verified"}]},"needs_you":false,"ttl_seconds":3600,"subtitle":"Each row has its own max"}
{"bot":"Mina","tile":"merge-bot","type":"status","title":"Merge bot","props":{"state":"idle","task":"Waiting for two approvals"},"needs_you":false,"ttl_seconds":120,"subtitle":"Idle until reviews land"}

FAQ

What is race progress?
A fraction from 0 to 1 for each named agent. 0.72 is 72 percent of the way to the goal. The goal string is the finish label.
Does this run on the Free plan?
The board installs on Free. Pro tiles are skipped until the workspace is Pro ($29/mo or $290/yr). Free tiles on the same board still install. Plan limits stay as they are.
How does the board stay current?
Post when the work changes. Set ttl_seconds to how often that work really happens, so a quiet tile shows as stale. Use a timer only for data no agent touches, and then at most daily. Never post the same content again just to keep a tile fresh.