-
Notifications
You must be signed in to change notification settings - Fork 0
Monthly Reports
On the 1st of each month at 7:00 AM, Signal generates a monthly intelligence summary — a longitudinal analysis that reads daily briefs and weekly summaries from the prior calendar month. This is where story arcs, watch list accountability, and coverage patterns become visible across weeks.
Partial months are supported: if daily coverage does not span the full calendar month (e.g. pipeline started mid-month), the report is labeled Partial Coverage in the header and filename.
| Trigger | Time | What it does |
|---|---|---|
| Automated (launchd) | 1st of each month, 7:00 AM local time | Synthesizes previous calendar month, publishes |
| Manual (CLI) | python3 main.py --monthly --month YYYY-MM |
Same pipeline, immediate execution |
On Jul 1, the scheduled job runs --month 2026-06 (June). The month argument defaults to the current month when omitted, but the launchd script always passes the previous month.
Important: The launchd job must be installed first. See Scheduling#one-time-setup.
cp scripts/com.flexrpl.signal.monthly.plist ~/Library/LaunchAgents/
launchctl load ~/Library/LaunchAgents/com.flexrpl.signal.monthly.plist
# Verify it loaded:
launchctl list | grep flexrpl
# → - 0 com.flexrpl.signal.monthlyThe monthly report has seven fixed sections:
| Section | What it covers |
|---|---|
| Month in Review | The dominant political dynamic of the month — trajectory visible only in hindsight |
| Story Arc Tracker | How the top 3–5 stories entered coverage, peaked, evolved, resolved, or vanished across weeks |
| Watch List Scorecard | Which early-month watch items materialized, which did not — accountability on prior intelligence |
| Coverage Pattern Analysis | Recurring blindspots that persisted all month on left vs. right |
| Emerging Actors | People and institutions that gained or lost significance across the month |
| Watch List: Next Month | Concrete forward-looking items with named entities and deadlines |
| Analyst Note | One paragraph: honest monthly trajectory assessment |
The monthly pipeline is Pass 7 — it skips article fetching entirely and works from data already stored in signal.db.
signal.db → get_runs_for_month() → get_weekly_source_data()
get_weekly_briefs_for_month()
↓
Format weekly + daily summaries
Build watch list evolution timeline
↓
MONTHLY_BRIEF prompt (one LLM call)
↓
save_monthly_brief() → monthly_briefs table
↓
generate_monthly_report() → HTML fileIf the earliest daily run in the month is after the 1st, or the latest run is before the last day of the month, partial=True is set automatically. The LLM prompt includes a note to avoid implying completeness.
- Daily runs: one complete run per calendar date in the target month (latest run wins per day)
- Weekly briefs: any weekly brief whose date range overlaps the calendar month
Monthly reports are written to reports/ with a distinct filename format:
reports/monthly_202605_partial_20260610_1753.html # partial month
reports/monthly_202606_20260701_0700.html # full month
─────── ───────
YYYYMM optional _partial suffixMonthly reports use a purple color scheme (#a371f7) instead of daily blue or weekly gold:
- Purple header gradient and MONTHLY SUMMARY badge
- Partial Coverage badge (red) when the month is incomplete
- Day chips showing each daily run included
- Analyst Note uses a purple tint
After each monthly run, _update_index() in main.py regenerates both pages:
Landing page (index.html): A fourth card — "Monthly Summary" — appears alongside daily, weekly, and archive cards. Partial months show (partial) in the card meta.
Archive (archive.html): A "Monthly Summaries" section appears at the top, above weekly groupings.
The monthly script writes to logs/monthly.log:
# Watch a monthly run live
tail -f logs/monthly.log
# Check last run result
grep -A5 "Signal MONTHLY run" logs/monthly.log | tail -20"No complete daily runs found for [Month]"
At least one successful daily run must exist in the target month. Run the daily pipeline first, then retry:
python3 main.py --monthly --month 2026-05Running a partial month manually
This is expected when the pipeline has not been running for the full calendar month:
python3 main.py --monthly --month 2026-05 # May 11–31 partial OKMonthly job not in launchctl list
launchctl load ~/Library/LaunchAgents/com.flexrpl.signal.monthly.plist
launchctl list | grep flexrplMonthly social card
Not yet implemented — planned after the first full scheduled monthly run (Jul 1+).
Signal · Repository · fleXRPL · Daily political intelligence — powered by local AI