Skip to content

Reference time daily pipeline

DB

  • Notion DB id: 3510950b-d7a9-8150-bee9-f611b878afe5 (key time_daily in NOTION_DBS)
  • Parent: LifeOS page 37e5e724-ba79-4182-a270-9949b714fab8 (same parent as Wellness Daily and Daily Log)
  • Properties: Name (title, ISO date), Day (date), Total h, Work h, Personal h, Sleep h, Workout h, Errands h, Entertainment h, Travel h, Untagged h, Events count, Top categories (rich_text), Notes (rich_text), Computed at (rich_text)

Pipeline

Component File
Aggregator forge/scripts/forge_time_daily_aggregator.py
Service unit /etc/systemd/system/forge-time-daily.service
Timer unit /etc/systemd/system/forge-time-daily.timer
Schedule OnCalendar=*-*-* 12:00:00, 17:00:00, 23:30:00 America/Chicago

Classification

Two-tier, colorId first:

  1. If the event has a colorId, look it up in _COLOR_TO_CATEGORY (inverse of the brain's _CATEGORY_COLOR map). 9 → Work, 10 → Personal, 1 → Sleep, 5 → Errands, 11 → Workout, 6 → Entertainment, 7 → Travel.
  2. If no colorId (event was created in Google Calendar UI without setting color), fall back to summary-text _PATTERNS in priority order: Forge: prefix → Work, Sleep start → Sleep, gym/yoga/run → Workout, lunch/dinner/krystal/family → Personal, etc.
  3. No match → Untagged (still counted in Untagged h).

This works correctly as of 2026-04-30 because forge talks direct to Google Calendar v3 via forge_google_calendar.py (no n8n hop, so colorId is preserved in both the create and list responses). See Google Calendar direct client.

Idempotency

The aggregator queries the DB for an existing row with Day == today. If found, it page_update instead of page_create. So the 3-times-a-day cron is safe; later fires overwrite earlier ones with fresh totals.

Backfill

Not done at install. To backfill past days, loop aggregate_day(target) + upsert_time_daily() over a date range.

Manual run

/home/justinwieb/forge/scripts/forge_time_daily_aggregator.py

[Claude Code, bot-refiner-v2, 2026-04-29]