Helm Decisions.
Your data, turned into next moves.
ChannelHelm already knows what your catalogue covers (Atlas), what everything cost (Ledger), how it performed (Signal), and which variants won (experiments). Helm Decisions joins all of it, once a day per brand, and writes a short queue of recommendations at /decisions. Every recommendation is plain arithmetic over your own numbers — there is no LLM anywhere in the decision path, so every claim on a card can be checked by hand.
The eight rules
| Kind | Fires when | Accept does |
|---|---|---|
| revisit_topic | A topic carried ≥2 videos but hasn't been covered in 90+ days — proven material going stale. | Creates a ranked idea on the Plan board. |
| followup_topic | A high-weight topic was covered exactly once — strong material with no follow-up. | Creates a ranked idea on the Plan board. |
| double_down_asset_type | One asset type reaches at least 2× the median of your other types (≥3 assets each). | Acknowledges — you prioritize it in upcoming packages. |
| budget_pace | From day 7, month-to-date spend projects past the monthly budget. | Acknowledges — raise the budget or trim fan-out. |
| prompt_winner_ready | A prompt-version A/B decided. Winners are never auto-pinned. | Acknowledges — you pin the prompt version deliberately. |
| stale_brand | No new packages ingested in 14+ days. | Acknowledges — bulk ingest takes a backlog paste. |
| experiment_opportunity | ≥3 published videos and zero experiments ever. | Acknowledges — start a title/thumbnail rotation. |
| roi_outlier | An asset type costs ≥3× the median per 1,000 reach this month. | Acknowledges — cheaper model, fewer variants, or skip it. |
Why dismissals stick
Every recommendation carries a dedupe key and the engine may create each key at most once, ever. Subject-stable keys (revisit_topic:local-first software) mean a dismissed topic never comes back. Period-scoped keys (budget_pace:2026-06) re-evaluate next month — the situation is genuinely new, so the question is asked again. The engine cannot nag: re-running it a hundred times produces nothing you haven't already seen.
Where the numbers come from
collect_signal pulling YouTube/Zernio analytics). Cost-per-1k-reach joins the two — and unmeasured content shows as "no data", never as "free". The same join powers the "Return on content" panel on /performance.