Option A+ — workflow with family/system contextRecommended

Same 3-column workflow as A, plus a family banner and step strip on top so you can see where this cron sits inside its pipeline. Example: pbr-pipeline-daily, step 3 of the PBR Recruiting Pipeline.

pbr-pipeline-daily
9am CT daily · last run 09:00 (success, 1h 12m)
🌳 System: PBR Recruiting Pipeline step 3 of 6
Discovers new baseball prospects from Perfect Game events, scrapes their profile data, dedups against HubSpot, imports new contacts into the recruiting funnel, and recomputes athlete metric improvements. Six crons + scripts working together. This one is the daily orchestrator.
1
pg-event-monitor
every 4h
2
pg-daily-contacts
daily 6am
3
pbr-pipeline-daily
daily 9am
4
pg-hubspot-sync
daily 11am
5
compute-improvement-rates
weekly Mon
6
monthly-pbr-import
manual
⬅ Triggered by
Schedule ⏰ 9:00 AM CT daily
Upstream cron 🔄 pg-event-monitor
queues new athlete IDs to scrape
Upstream cron 🔄 pg-daily-contacts
writes profile data the pipeline reads
This cron
pbr-pipeline-daily
Daily orchestrator: dedups newly scraped athletes against HubSpot, builds the prioritized scrape queue, runs the scraper, imports new contacts to HubSpot, and marks state-sheet rows as complete.
bash tools/recruiting/scripts/pbr-pipeline-daily.sh
Effects ➡
Reads 🗄️ PG state sheets (44)
🗄️ HubSpot dedup index
🗄️ recruiting Supabase
Writes 🔵 HubSpot contacts (new + updated)
📊 PG state sheets (Last Scraped col)
💬 Slack #cron-log
Triggers 🔄 pg-hubspot-sync (downstream)
Used by 📱 SalesMSG nurturing flow
📋 monthly-pbr-import (residual)

What you get from the family layer: a one-glance answer to "what does this thing belong to?" The banner names the system in plain English. The step strip shows the whole pipeline with this cron highlighted. The prev/next links let you walk the chain like a checkout flow.

How it adapts: sequential pipelines (PBR, daily-pipeline, program-end-dates) render as a step strip. Networked clusters (Program Writer, Chip Agent) would render as a small node-and-arrow map instead of a strip. Standalone crons with no family hide the banner entirely.

What you'd need to build it: two new optional fields on registry.yamlsystem: pbr-recruiting (group key) and system_step: 3 (sequence). Plus one new file tools/cron-map/systems.yaml mapping each system key → name + plain-English purpose. The strip and banner auto-render from those.

Option A — HubSpot-style horizontal workflow

Three columns flowing left to right: Triggered By, This Cron, Effects.

program-end-dates-overnight
4am CT daily · last run 04:00 (success, 18.4s)
⬅ Triggered by
Schedule ⏰ 4:00 AM CT daily
Sibling cron 🔄 programs-sync-midday
runs same script at 1pm
This cron
program-end-dates-overnight
Refreshes each athlete's throwing & strength program end dates by reading the latest workout in each stream from PW Supabase.
python3 tools/contacts/sync_program_end_dates.py
Effects ➡
Reads 🗄️ Supabase RPC
program_end_dates_per_athlete()
Writes 🔵 HubSpot contact props
throwing_program_end_date
strength_program_end_date
Used by 🤖 Chip Agent renewal alerts
📺 Data Hub Today tab

What's good: Reads exactly like a HubSpot workflow. Eye flows left to right. Easy to scan.

What's not: Three columns get cramped on phone. Long property names wrap awkwardly. Needs a collapse-to-stacked treatment for narrow screens.

Option B — Vertical stack

Top to bottom. Each section a labeled block, chevrons between. Mobile-friendly by default.

program-end-dates-overnight
4am CT daily · last run 04:00 (success, 18.4s)
Triggered by
⏰ Schedule: 4:00 AM CT daily
🔄 Sibling cron: programs-sync-midday (runs same script at 1pm)
This cron
program-end-dates-overnight Refreshes each athlete's throwing + strength program end dates from latest PW workout.
python3 tools/contacts/sync_program_end_dates.py
Reads from
🗄️ Supabase RPC: program_end_dates_per_athlete()
📊 Source table: pw_workouts.calendar_date (grouped by stream)
Writes to
🔵 HubSpot contact prop: throwing_program_end_date
🔵 HubSpot contact prop: strength_program_end_date
Used downstream by
🤖 Chip Agent (renewal alert eligibility)
📺 Data Hub Today tab (program-end countdowns)
📋 programs-sync-midday cron (cross-checks against this output)

What's good: Reads cleanly at any width. Each section has room to breathe. Empty sections degrade gracefully ("none known"). Easy to add new section types later.

What's not: Less workflow-y feeling than Option A. Five sections is a lot of vertical real estate before you see the whole picture.

Option C — Hub-and-spoke (Miro-style)

Cron sits in the center, sources fan in from the left, effects fan out to the right.

program-end-dates-overnight
4am CT daily · last run 04:00 (success, 18.4s)
⏰ Schedule 4:00 AM CT daily
🗄️ Reads Supabase RPC
program_end_dates_per_athlete()
🔄 Sibling cron programs-sync-midday
program-end-dates-overnight 4am CT · ~20s
🔵 HubSpot prop throwing_program_end_date
🔵 HubSpot prop strength_program_end_date
🤖 Used by Chip Agent renewal alerts
📺 Used by Data Hub Today tab

What's good: Most "Miro-like." The cron's place in the network is instantly visual. Looks great when the panel is wide.

What's not: Doesn't reflow on narrow screens — desktop only. SVG curve positioning has to be computed per cron based on how many upstream/downstream items it has, which is the most engineering work of the four. Aesthetic ceiling is high but so is the cost.

Option D — Dense info card (typography only)

No diagram. Just structured, scannable text. Like a great GitHub issue body or readme block.

program-end-dates-overnight
4am CT daily · last run 04:00 (success, 18.4s)

program-end-dates-overnight

Refreshes each athlete's throwing and strength program end dates by reading the latest workout in each stream from PW Supabase, then writes the dates to HubSpot contacts. Property-write only. Fast.


Schedule
0 4 * * * — 4:00 AM CT daily
Command
python3 tools/contacts/sync_program_end_dates.py
Triggered by
  • ⏰ Cron schedule (4am CT)
  • 🔄 programs-sync-midday — runs the same script via the 1pm pipeline
Reads
  • 🗄️ Supabase RPC program_end_dates_per_athlete()
  • 📊 Source: pw_workouts.calendar_date grouped by stream
Writes
  • 🔵 HubSpot contact prop: throwing_program_end_date
  • 🔵 HubSpot contact prop: strength_program_end_date
Used downstream
  • 🤖 Chip Agent — renewal alert eligibility
  • 📺 Data Hub — Today tab program-end countdown
  • 📋 programs-sync-midday cron cross-checks against this output

What's good: Cheapest to build, easiest to keep accurate, scales to 100+ crons without breaking. Reads great on any device. Empty fields just collapse.

What's not: No actual visual. Doesn't fully satisfy the "I want to SEE how this fits in" instinct that prompted the question.