Reference time daily pipeline
DB¶
- Notion DB id:
3510950b-d7a9-8150-bee9-f611b878afe5(keytime_dailyinNOTION_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:
- If the event has a
colorId, look it up in_COLOR_TO_CATEGORY(inverse of the brain's_CATEGORY_COLORmap). 9 → Work, 10 → Personal, 1 → Sleep, 5 → Errands, 11 → Workout, 6 → Entertainment, 7 → Travel. - If no colorId (event was created in Google Calendar UI without setting color), fall back to summary-text
_PATTERNSin priority order:Forge:prefix → Work,Sleepstart → Sleep, gym/yoga/run → Workout, lunch/dinner/krystal/family → Personal, etc. - No match →
Untagged(still counted inUntagged 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¶
[Claude Code, bot-refiner-v2, 2026-04-29]