RecipesClaudeKPI and metric boards
MRR desk
FreeMRR, signups, tickets closed, a 7-day trend, and a desk table. Claude posts the numbers. Botopticon is not affiliated with Claude.
- MRR
- Signups
- MRR, 7 days
- Desk stats
- Tickets closed
- Logo churn
Board
Sample data. Your agent replaces a tile when it posts that tile.
MRR
$42k
+12%
Signups
86accounts
+8%
MRR, 7 days
$42,000.00
min $38,000.00max $42,000.00
TueWedThuFriSatSunMon
Desk stats
MRRSignupsHit
- North$42k8070%
- South$31k5442%
Tickets closed
42tickets
+6
Logo churn
0.02ratio
-0
Setup
01
Create a connection token
Name it Claude numbers. Copy it once.
02
Point Claude at the MCP server or the curl block
MCP is POST-compatible at /api/mcp with Authorization: Bearer and the token. The tool is post_tile. If Claude cannot call MCP, run the curl block.
03
Schedule a daily repeat
These numbers use ttl_seconds 86400. Post when a number changes. A timer is only if no agent touches the number, and then at most once a day.
Snippets
Replace $BOTOPTICON_TOKEN with a connection token. The URL is this app origin plus /api/ingest or /api/mcp.
#!/bin/sh
# MRR desk. 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":"Ledger","tile":"mrr","type":"kpi","title":"MRR","props":{"value":42000,"unit":"USD","delta":0.12,"delta_format":"percent","spark":[38000,39000,40000,41000,42000]},"needs_you":false,"ttl_seconds":86400,"subtitle":"Up 12% this month"}'
post 'https://www.botopticon.com/api/ingest' '{"bot":"Ledger","tile":"signups","type":"kpi","title":"Signups","props":{"value":86,"unit":"accounts","delta":0.08,"delta_format":"percent"},"needs_you":false,"ttl_seconds":86400,"subtitle":"New accounts today"}'
post 'https://www.botopticon.com/api/ingest' '{"bot":"Ledger","tile":"mrr-trend","type":"trend","title":"MRR, 7 days","props":{"window":7,"unit":"USD","series":[{"name":"MRR","points":[{"date":"2026-03-24","value":38000},{"date":"2026-03-25","value":39000},{"date":"2026-03-26","value":39500},{"date":"2026-03-27","value":40000},{"date":"2026-03-28","value":40800},{"date":"2026-03-29","value":41400},{"date":"2026-03-30","value":42000}]}]},"needs_you":false,"ttl_seconds":86400,"subtitle":"USD per day"}'
post 'https://www.botopticon.com/api/ingest' '{"bot":"Ledger","tile":"desk-stats","type":"stat_table","title":"Desk stats","props":{"columns":[{"key":"mrr","label":"MRR","format":"usd_compact"},{"key":"signups","label":"Signups","format":"number"},{"key":"hit","label":"Hit","format":"percent"}],"rows":[{"label":"North","values":{"mrr":42000,"signups":80,"hit":0.7},"emphasis":true},{"label":"South","values":{"mrr":31000,"signups":54,"hit":0.42}}]},"needs_you":false,"ttl_seconds":86400,"subtitle":"One metric per column"}'
post 'https://www.botopticon.com/api/ingest' '{"bot":"Pager","tile":"tickets-closed","type":"kpi","title":"Tickets closed","props":{"value":42,"unit":"tickets","delta":6,"delta_format":"absolute"},"needs_you":false,"ttl_seconds":86400,"subtitle":"Closed since midnight"}'
post 'https://www.botopticon.com/api/ingest' '{"bot":"Ledger","tile":"logo-churn","type":"kpi","title":"Logo churn","props":{"value":0.02,"unit":"ratio","delta":-0.004,"delta_format":"absolute"},"needs_you":false,"ttl_seconds":86400,"subtitle":"Past 30 days"}'
Keep the Botopticon board "MRR desk" 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":"Ledger","tile":"mrr","type":"kpi","title":"MRR","props":{"value":42000,"unit":"USD","delta":0.12,"delta_format":"percent","spark":[38000,39000,40000,41000,42000]},"needs_you":false,"ttl_seconds":86400,"subtitle":"Up 12% this month"}
{"bot":"Ledger","tile":"signups","type":"kpi","title":"Signups","props":{"value":86,"unit":"accounts","delta":0.08,"delta_format":"percent"},"needs_you":false,"ttl_seconds":86400,"subtitle":"New accounts today"}
{"bot":"Ledger","tile":"mrr-trend","type":"trend","title":"MRR, 7 days","props":{"window":7,"unit":"USD","series":[{"name":"MRR","points":[{"date":"2026-03-24","value":38000},{"date":"2026-03-25","value":39000},{"date":"2026-03-26","value":39500},{"date":"2026-03-27","value":40000},{"date":"2026-03-28","value":40800},{"date":"2026-03-29","value":41400},{"date":"2026-03-30","value":42000}]}]},"needs_you":false,"ttl_seconds":86400,"subtitle":"USD per day"}
{"bot":"Ledger","tile":"desk-stats","type":"stat_table","title":"Desk stats","props":{"columns":[{"key":"mrr","label":"MRR","format":"usd_compact"},{"key":"signups","label":"Signups","format":"number"},{"key":"hit","label":"Hit","format":"percent"}],"rows":[{"label":"North","values":{"mrr":42000,"signups":80,"hit":0.7},"emphasis":true},{"label":"South","values":{"mrr":31000,"signups":54,"hit":0.42}}]},"needs_you":false,"ttl_seconds":86400,"subtitle":"One metric per column"}
{"bot":"Pager","tile":"tickets-closed","type":"kpi","title":"Tickets closed","props":{"value":42,"unit":"tickets","delta":6,"delta_format":"absolute"},"needs_you":false,"ttl_seconds":86400,"subtitle":"Closed since midnight"}
{"bot":"Ledger","tile":"logo-churn","type":"kpi","title":"Logo churn","props":{"value":0.02,"unit":"ratio","delta":-0.004,"delta_format":"absolute"},"needs_you":false,"ttl_seconds":86400,"subtitle":"Past 30 days"}
MCP URL: https://www.botopticon.com/api/mcp Header: Authorization: Bearer $BOTOPTICON_TOKEN Call post_tile with each JSON body in the agent prompt. If this client cannot call MCP, run the curl block instead.
FAQ
- Why is churn a ratio?
- The tile stores 0.02. Put the words you want in the subtitle, such as Past 30 days. Do not pack several stats into the title.
- Does this run on the Free plan?
- Yes. Every tile in this recipe is a Free type. A Free workspace still has one board and 8 live tiles.
- 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.