Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Generate a daily morning briefing: email, calendar, Discord, and news — delivered via voice or Discord DM.
.claude/skills/sonichi-morning-briefing/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-04 | ✗→✓ | ▲ Improved | -2% | 0% |
| case-05 | ✗→✓ | ▲ Improved | -10% | 0% |
| case-07 | ✗→✓ | ▲ Improved | 6% | 0% |
| case-08 | ✗→✓ | ▲ Improved | 20% | 0% |
| case-10 | ✗→✓ | ▲ Improved | -31% | 0% |
Generate a prioritized daily briefing from all your channels.
Usage: /morning-briefing
ARGUMENTS: $ARGUMENTS
Step 0 — Calendar cache. CONDITIONAL: Google-calendar hosts only.
src/morning-briefing.py cannot reach the owner's Google Workspace calendar; it reads a cache the agent writes. Omitting this is silent: the briefing reports "couldn't read your calendar", or falls back to a local macOS Calendar read that stalls and can miss the work account entirely. Pull today's local-day events from the Google connector, then:
bashecho '[{"raw":"9:00-9:30am 1:1 w/ Sam","calendar":"work"}]' | python3 src/write_calendar_cache.py python3 src/write_calendar_cache.py --empty # ONLY for a genuinely empty day
Hosts with no Google connector skip STEP 0 ONLY — the reader falls back to local macOS Calendar. Step 1 below still runs on every host. See "Calendar source (Google Workspace) — activation" for the full contract.
Step 1 — Base data (canonical; runs on EVERY host, including hosts that skipped Step 0):
bashWORKSPACE="$(bash scripts/sutando-config.sh workspace)" python3 src/morning-briefing.py
src/morning-briefing.py is the single source of truth for core briefing data: weather (Open-Meteo), macOS Calendar, macOS Reminders, overnight Discord DMs, pending questions, and system health. It writes output to results/proactive-<ts>.txt and sends a Discord DM directly. Review its output before composing the full briefing — do NOT re-fetch those sources manually.
Then augment with the following if configured (skip if not available):
gws gmail +triage to get unread inbox. Summarize top 5 by priority. Flag anything urgent.gws calendar +agenda --today. List any meetings not already covered by the macOS Calendar output above.python3 src/daily-insight.py. If it produces an insight, include it at the end of the briefing as "💡 Insight: ..."python3 src/friction-detector.py. If friction items found, include as "⚠️ Friction: count] items need attention" with the top 3.src/morning-briefing.py already writes results/proactive-<ts>.txt (spoken by voice) and sends a Discord DM for the base data. If you gathered email or insight in steps 1–4, append them as a follow-up proactive file:
bashecho "📧 Email: [count] unread. [summary] 💡 Insight: [insight text]" > "$WORKSPACE/results/proactive-$(date +%s).txt"
src/morning-briefing.py is a standalone script and cannot reach the owner's Google Workspace calendar — the Station/Composio connector is agent-only. So the briefing reads a cache that the agent produces:
src/write_calendar_cache.py writes state/calendar-today.json — {"date": "YYYY-MM-DD", "events": [{"raw": "...", "calendar": "..."}]}, atomically (tmp + os.replace). date is today in local time so a stale cache is ignored, and events: [] means a verified-empty day (never rendered as "clear" from a missing cache). Feed it the events you pulled from the connector:bash echo '[{"raw":"9:00-9:30am 1:1 w/ Sam","calendar":"work"}]' | python3 src/write_calendar_cache.py python3 src/write_calendar_cache.py --empty # verified no events today
get_calendar_events() prefers the cache. Set MORNING_BRIEFING_CALENDAR_SOURCE=google to make the cache the only trusted source — if it's missing/stale the briefing reports "couldn't read your calendar" rather than falling back to a local macOS Calendar that may not include the work account (the 2026-07-21 "falsely clear" bug, #2256).Nothing writes the cache automatically, so a briefing that only runs the reader reports unread on a Google-source host. The producer is therefore step 0 of this skill's own flow (above), which covers both /morning-briefing and a cron declared as "prompt_skill": "morning-briefing" — the natural config. The expanded cron prompt under "Scheduling" below remains valid but is no longer the only place the producer appears.
Observed on Chis-Mac-mini: state/calendar-today.json was last written 2026-07-30 07:28 and the host's cron was {"name": "morning-briefing", "prompt_skill": "morning-briefing"}, so nothing invoked the producer. Three consecutive briefings reported no calendar, and the local fallback added a ~23s AppleScript stall before returning nothing.
The canonical daily schedule produces the Google-calendar cache first, then runs the briefing against it (see the activation section above):
json{ "name": "morning-briefing", "cron": "57 6 * * *", "prompt": "Morning briefing. FIRST produce the calendar cache from the owner's REAL Google calendar (the standalone script can't reach the connector): pull today's events via the Google-calendar connector (e.g. sutando-station composio_exec GOOGLECALENDAR_EVENTS_LIST, calendarId=primary, today's local-day window), then pipe them as a JSON array of {raw,calendar} to `python3 src/write_calendar_cache.py` (or `--empty` if genuinely no events). THEN run `MORNING_BRIEFING_CALENDAR_SOURCE=google python3 src/morning-briefing.py` to deliver the briefing. Speak the result if voice is connected, send as Discord DM otherwise." }
Calling /morning-briefing manually runs the same script plus GWS/insight augmentation.
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | fail→fail | 5,602 | 6,093 | +9% | 1 | 1 | 0% | 883 | 1,745 | +98% | 0 | 0 | — |
case-02 | fail→fail | 14,643 | 5,269 | -64% | 1 | 1 | 0% | 2,327 | 1,745 | -25% | 0 | 0 | — |
case-03 | fail→fail | 9,535 | 4,577 | -52% | 1 | 1 | 0% | 1,447 | 1,785 | +23% | 0 | 0 | — |
case-04 | fail→pass | 13,661 | 3,548 | -74% | 1 | 1 | 0% | 2,147 | 2,109 | -2% | 0 | 0 | — |
case-05 | fail→pass | 14,091 | 2,846 | -80% | 1 | 1 | 0% | 2,095 | 1,886 | -10% | 0 | 0 | — |
case-06 | fail→fail | 8,743 | 1,948 | -78% | 1 | 1 | 0% | 1,386 | 1,838 | +33% | 0 | 0 | — |
case-07 | fail→pass | 9,946 | 1,497 | -85% | 1 | 1 | 0% | 1,619 | 1,712 | +6% | 0 | 0 | — |
case-08 | fail→pass | 10,393 | 1,649 | -84% | 1 | 1 | 0% | 1,414 | 1,701 | +20% | 0 | 0 | — |
case-09 | fail→fail | 18,114 | 5,539 | -69% | 1 | 1 | 0% | 2,857 | 2,409 | -16% | 0 | 0 | — |
case-10 | fail→pass | 14,611 | 1,891 | -87% | 1 | 1 | 0% | 2,447 | 1,686 | -31% | 0 | 0 | — |
case-11 | fail→pass | 13,944 | 1,490 | -89% | 1 | 1 | 0% | 2,239 | 1,685 | -25% | 0 | 0 | — |
case-12 | fail→fail | 11,266 | 3,513 | -69% | 1 | 1 | 0% | 1,679 | 2,007 | +20% | 0 | 0 | — |
case-13 | fail→pass | 13,646 | 3,095 | -77% | 1 | 1 | 0% | 2,162 | 2,055 | -5% | 0 | 0 | — |
case-14 | pass→pass | 10,277 | 4,062 | -60% | 1 | 1 | 0% | 1,459 | 2,226 | +53% | 0 | 0 | — |
case-15 | fail→pass | 9,157 | 1,752 | -81% | 1 | 1 | 0% | 1,230 | 1,765 | +43% | 0 | 0 | — |
case-16 | fail→pass | 12,159 | 2,640 | -78% | 1 | 1 | 0% | 1,954 | 1,941 | -1% | 0 | 0 | — |
case-17 | fail→pass | 15,702 | 7,991 | -49% | 1 | 1 | 0% | 2,621 | 3,054 | +17% | 0 | 0 | — |
case-18 | fail→fail | 8,782 | 1,661 | -81% | 1 | 1 | 0% | 1,122 | 1,683 | +50% | 0 | 0 | — |
case-19 | fail→fail | 8,721 | 1,400 | -84% | 1 | 1 | 0% | 1,241 | 1,679 | +35% | 0 | 0 | — |
case-20 | pass→pass | 5,887 | 4,683 | -20% | 1 | 1 | 0% | 1,099 | 2,245 | +104% | 0 | 0 | — |
case-21 | pass→pass | 12,720 | 9,282 | -27% | 1 | 1 | 0% | 2,164 | 2,530 | +17% | 0 | 0 | — |
case-22 | pass→pass | 10,823 | 11,282 | +4% | 1 | 1 | 0% | 1,695 | 2,571 | +52% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted, and 19 counted toward the lift figure. The other 3 produced results that are not comparable between the two arms, so they are excluded from the headline rather than averaged into it. The headline lift of +45 percentage points is the difference between those two pass rates over the 19 comparable cases.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.