I run four GitHub Actions cron routines that all need to know the same thing: which game subjects have live search demand right now. The YouTube Short generation routine picks matchup titles from it. The Bluesky post queue uses it to weight the gaming slot. The article generation routine uses it to anchor VoC topics. A market monitoring sweep updates it.
For the first month of this setup, each routine had its own baked-in assumptions. The YT script used a hardcoded list of "safe" matchup pairs. The Bluesky routine had a separate file with a different classification of "hot" subjects. The article routine ignored market signal entirely. Every system was drifting independently, and updating any one of them required touching multiple files.
The fix was one shared markdown file — docs/market-trends.md — with three design rules that I got progressively more right over time.
Rule 1: counted numbers only, every claim traceable
The first version of this file was just notes. "Underdog narratives seem to do well." "Players talk about price gaps." Useful to write down, useless to automate against. A routine reading that file has no way to prefer one subject over another when the file's evidence is impressionistic.
The TERUS method — every number is a count from a specific source, every source is saved raw — forced the file into something a routine can act on. "3.1M views, 'Indie Dev Beat AAA Studios With 0 Marketing'" is something a routine can compare against "5K views, most recent build-in-public short." An impression is not.
This also matters for the author. When you have to write a specific count, you have to actually count. You can't hand-wave "players care about X" when the claim has to be backed by "I read 43 comments and 11 mentioned X." The discipline of traceable numbers improved the file's accuracy more than any review process would have.
Rule 2: fail-closed freshness gate
The second version of the file had a format problem: it could be months old and none of the consumers would know. The YT script would anchor on "hot subjects" that had been stale for two months, and the routine would behave as if the data were current.
The fix was a updated: date field at the top of the file and a freshness rule that consumers must check before using the file's content:
updated: 2026-08-10
Freshness rule (fail-closed): if updated: is more than 14 days
old, consumers MUST ignore this file and fall back to their own defaults —
stale trends are worse than no trends.
Fail-closed here means: if the file is stale, the routine ignores the market-trends data and uses conservative defaults (established evergreen matchups, not trend-chasing). It doesn't silently use the stale data, and it doesn't crash. The 14-day window matches the social-listening sweep cadence — I update the file weekly when things are moving, less often when they're stable.
The key design choice is making freshness the consumer's responsibility rather than the publisher's. The consumer checks the updated: date on every run. This means a routine added six months from now will inherit the freshness check automatically if it follows the documented pattern — I don't need to update a registry or notify consumers when the file goes stale.
Rule 3: separate what's measured from what's prescribed
The third version made the biggest difference: splitting the file into an observations section (what I measured) and a prescriptions section (what consumers should do with it).
The original file mixed these together: "Underdog narratives get high views, so use them." That forces consumers to interpret the claim, and different routines interpret it differently. The Bluesky routine might take "use underdog narratives" to mean write underdog captions. The YT routine might take it to mean use underdog-narrative titles. Neither is wrong, but they diverge over time.
The current structure separates the measurement table from the action directive:
- Observations section: the raw data table — video format, measured view counts, evidence notes. This is what I actually found. Consumers can read this to understand the evidence.
- Hot subjects list: the prescriptions — specific matchup subjects, anchor candidates, and what-to-avoid notes. This is what the routine should act on. The YT script reads this section and picks from the "anchor OK" rows; the Bluesky routine reads it to weight game subjects for the 70% gaming slot.
The separation means I can update the observations without changing any consuming routine's behavior. If I notice something new in the measurement data, I can add it to the observations section without touching the prescriptions — the prescriptions only change when I've decided what action to take based on the evidence.
What I'd do differently
Build the freshness check first. I spent a month using stale market data because it felt like a future concern. It wasn't — the first time I updated the file and forgot to check whether the routines were actually reading the new version, I lost a week of YT anchor selection to outdated data.
The other thing: write the consuming routine's expected behavior in the file itself. docs/market-trends.md now has a "Who reads this (mandatory)" section that names each consumer and what it should do with the file. When I added the article routine as a fourth consumer, I had a clear template for how to wire it in — and a record of what the existing consumers were doing, so I could check for overlap or contradiction.
A shared markdown file with a freshness gate and a traced-evidence discipline is a long way from a config service, but for a four-system automation project running on a $25/month budget, it's the right level of infrastructure.
Part of an ongoing 6-month experiment running three AI-curated directory sites. The technical claims here are real; this article was AI-assisted.
Top comments (0)