Daily Briefing
by @antgly
Generates a warm, compact daily briefing with weather, calendar, reminders, birthdays, and important emails for cron or chat delivery.
clawhub install daily-briefingπ About This Skill
name: daily-briefing description: Generates a warm, compact daily briefing with weather, calendar, reminders, birthdays, and important emails for cron or chat delivery. metadata: {"openclaw":{"emoji":"π ","requires":{"os":["darwin"],"bins":["curl","bash"]},"optional_bins":["icalpal","gog","himalaya"]}} user-invocable: true
daily-briefing
Generates a compact, warm daily message suitable for cron delivery (stdout/chat reply). Always succeeds even with minimal context.
Skill Type: System Skill (Orchestrator Pattern)
This skill uses the System Skill pattern for execution on macOS. The agent must:
1. Never run raw CLI commands directly (except curl for weather).
2. Always invoke the runner script to gather data.
3. Read gathered data from JSON after the script completes.
4. Generate the briefing text using the agent's own capabilities.
Quick reference:
# Invoke data gatherer (waits for completion)
"{baseDir}/skills/daily-briefing/bin/run_daily_briefing.sh"Read output
cat /tmp/daily_briefing_data.json
Output Contract (STRICT)
CRITICAL: Output only the briefing text. No prefaces, no explanations, no "Done", no file paths, no tool output, no markdown code fences around the briefing.
Line 1 Format (Required)
Line 1 must begin exactly with the time-appropriate greeting:
Good {time_of_day} - Today is {Weekday}, {Month} {D}, {YYYY}. {Skies sentence}.
π Happy Birthday! Today is {Weekday}, {Month} {D}, {YYYY}. {Skies sentence}.
Greeting Selection (Local Time)
| Time Range | Greeting | |------------|----------| | 05:00β11:59 | Good morning | | 12:00β16:59 | Good afternoon | | 17:00β21:59 | Good evening | | 22:00β04:59 | Good night | | Unknown | Good morning (default) |
Skies Sentence Rules
If weather is usable:
{Conditions} skies, around {TEMP}Β°{time_clause}{low_clause}{precip_clause}.
, with a low around {LOW}Β°, and a {CHANCE}% chance of {rain/snow/precipitation}If weather is not usable: Use exact fallback:
I can't access weather right now.
Layout Rules
{Line 1: Greeting with skies sentence}{Birthdays section - only if any today or upcoming}
{Calendar events section - only if any}
{Reminders section - only if any}
{Important emails section - only if enabled and any}
{Anchors - only if real priorities from context}
{Closing line - always required}
Vibe and Tone
System Skill Execution
Step 1: Check Mode (Interactive vs Cron)
If interactive AND missing critical info (location/timezone/units):
emails.enabled in config; note iCloud Mail requires an app-specific password (emails.icloudPassword).If non-interactive (cron/automation):
Step 2: Invoke the Data Gatherer
"{baseDir}/skills/daily-briefing/bin/run_daily_briefing.sh"
scripts/daily_briefing_orchestrator.sh.Step 3: Read the Gathered Data
After the app completes, read:
/tmp/daily_briefing_data.json
JSON structure:
{
"generated_at": "ISO timestamp",
"system": {
"timezone": "America/New_York",
"local_time": "2024-02-03T08:30:00",
"hour": 8
},
"config": {
"location": "New York, NY",
"units": "C",
"birthdays_enabled": true,
"birthdays_lookahead": 14,
"calendar_google_enabled": true,
"calendar_icloud_enabled": true,
"calendar_lookahead": 0,
"reminders_enabled": true,
"reminders_due_filter": "today",
"reminders_include_past_due": true,
"emails_enabled": false,
"emails_limit": 10,
"emails_sort_newest": true,
"emails_starred_first": true,
"emails_unread_only": true
},
"birthdays": {
"available": true,
"user_birthday_today": false,
"data": [
{"name": "Jane Doe", "date": "2024-02-03", "days_until": 0},
{"name": "John Smith", "date": "2024-02-05", "days_until": 2}
]
},
"calendar": {
"available": true,
"data": [
{"title": "Team standup", "start": "09:00", "end": "09:30", "all_day": false, "date": "2024-02-03", "source": "google"},
{"title": "Doctor appointment", "start": null, "end": null, "all_day": true, "date": "2024-02-03", "source": "icloud"}
]
},
"reminders": {
"available": true,
"data": [
{"title": "Pick up prescription", "due": "2024-02-03"}
]
},
"emails": {
"available": true,
"data": [
{"id": "abc123", "from": "Amazon", "from_email": "shipment@amazon.com", "subject": "Your order has shipped", "preview": "Your package is on its way...", "starred": false, "unread": true, "date": "2024-02-03T07:30:00Z", "source": "gmail"},
{"id": "def456", "from": "Chase", "from_email": "alerts@chase.com", "subject": "Payment received", "preview": "We received your payment of...", "starred": true, "unread": true, "date": "2024-02-03T06:15:00Z", "source": "icloud"}
]
},
"contacts": {
"available": true,
"data": [
{"name": "Jane Doe", "email": "jane@example.com"},
{"name": "John Smith", "email": "john@example.com"}
]
}
}
Step 4: Fetch Weather (Agent Task)
The agent must fetch weather directly using curl (not via orchestrator):
curl -fsSL --max-time 12 "https://wttr.in/{ENCODED_LOCATION}?format=j1"
config.location from gathered data; if empty/null, weather is unavailable.Parse from JSON response:
current_condition[0].weatherDesc[0].valuecurrent_condition[0].temp_Ccurrent_condition[0].temp_Fweather[0].maxtempCweather[0].maxtempFweather[0].mintempCweather[0].mintempFweather[0].hourly[*].chanceofrain (as integers)Units: Use config.units ("C" or "F"). Default to Celsius if unknown.
CRITICAL: Do NOT output raw curl/tool output. Do NOT use wttr.in one-line formats.
Step 5: Classify Important Emails (Agent Task)
Only if config.emails_enabled is true and emails.available is true.
For each email in emails.data, use the agent's own semantic analysis to determine importance.
Important Email Criteria (any match qualifies):
Exclusions: The following are never important, even if matching other criteria:
Failure behavior: If semantic analysis fails, silently omit the entire email section.
Apply filters and sorting:
1. Filter by emails_unread_only if true
2. If emails_starred_first is true, starred emails first
3. Sort by date per emails_sort_newest
4. Limit to emails_limit
Step 6: Generate the Briefing
Using all gathered and processed data, compose the briefing text following the Output Contract.
Section Formats:
Birthdays:
π Birthdays:
β’ Today: Name
β’ Feb 5: Name
Calendar Events:
π
Today's schedule:
β’ All-day: Event title
β’ 9:00 AM: Event title
Reminders:
β
Reminders:
β’ Pick up prescription
Important Emails:
π§ Emails needing attention:
β’ Amazon: Your order has shipped
β’ Chase: Payment received
β’ Sender: Subject (truncated if needed)Anchors:
Closing Line:
quote field from the gathered JSON data.Step 7: Output the Briefing
Return only the briefing text. Nothing else.
Configuration
Configuration is read from ~/.openclaw/openclaw.json at path skills.entries.daily-briefing.config:
{
"skills": {
"entries": {
"daily-briefing": {
"config": {
"location": "New York, NY",
"timezone": "America/New_York",
"units": "C",
"birthdays": {
"enabled": true,
"lookahead": 14,
"sources": ["contacts", "google"]
},
"calendar": {
"enabled": true,
"lookahead": 0,
"sources": ["google", "icloud"]
},
"reminders": {
"enabled": true
},
"emails": {
"enabled": false,
"icloudPassword": "",
"limit": 10,
"sortNewest": true,
"starredFirst": true,
"unreadOnly": true
}
}
}
}
}
}
Configuration Options
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| location | string | "" | Location for weather (e.g., "New York, NY") |
| timezone | string | system | Timezone (e.g., "America/New_York") |
| units | string | "C" | Temperature units: "C" or "F" |
| birthdays.enabled | bool | true | Enable birthday tracking |
| birthdays.lookahead | int | 14 | Days ahead to show upcoming birthdays |
| birthdays.sources | array | ["contacts"] | Sources: "contacts" (iCloud), "google" |
| calendar.enabled | bool | true | Enable calendar events |
| calendar.lookahead | int | 0 | Days ahead (0 = today only) |
| calendar.sources | array | ["google", "icloud"] | Calendar sources |
| reminders.enabled | bool | true | Enable Apple Reminders |
| reminders.dueFilter | string | "today" | Due date filter: "today", "week", or "all" |
| reminders.includePastDue | bool | true | Include overdue/past-due reminders |
| emails.enabled | bool | false | Enable important emails feature |
| emails.icloudPassword | string | "" | iCloud Mail app-specific password |
| emails.limit | int | 10 | Maximum emails to show |
| emails.sortNewest | bool | true | Sort newest first |
| emails.starredFirst | bool | true | Prioritize starred emails |
| emails.unreadOnly | bool | true | Only show unread emails |
Defaults
Dependencies
Required:
curl β for weather fetchingbash β for orchestrator scriptOptional:
gog β brew install steipete/tap/gogcli (Google Calendar, Gmail, Contacts)icalpal β brew install ajrosen/tap/icalpal (iCloud Calendar)himalaya β brew install himalaya (iCloud Mail via IMAP)File Structure
daily-briefing/
βββ SKILL.md
βββ README.md
βββ install.sh
βββ scripts/
β βββ daily_briefing_orchestrator.sh
βββ bin/
βββ run_daily_briefing.sh (created by install.sh)
Example Output
Good morning - Today is Saturday, February 3, 2024. Partly cloudy skies, around 45Β°F this afternoon, with a low around 32Β°F.π Birthdays:
β’ Today: Jane Doe
β’ Feb 5: John Smith
π
Today's schedule:
β’ All-day: Doctor appointment
β’ 9:00 AM: Team standup
β
Reminders:
β’ Pick up prescription
π§ Emails needing attention:
β’ Amazon: Your order has shipped
β’ Chase: Payment received
Take things one step at a time todayβyou've got this.
Cleanup
"{baseDir}/skills/daily-briefing/bin/run_daily_briefing.sh" --cleanup
βοΈ Configuration
Configuration is read from ~/.openclaw/openclaw.json at path skills.entries.daily-briefing.config:
{
"skills": {
"entries": {
"daily-briefing": {
"config": {
"location": "New York, NY",
"timezone": "America/New_York",
"units": "C",
"birthdays": {
"enabled": true,
"lookahead": 14,
"sources": ["contacts", "google"]
},
"calendar": {
"enabled": true,
"lookahead": 0,
"sources": ["google", "icloud"]
},
"reminders": {
"enabled": true
},
"emails": {
"enabled": false,
"icloudPassword": "",
"limit": 10,
"sortNewest": true,
"starredFirst": true,
"unreadOnly": true
}
}
}
}
}
}
Configuration Options
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| location | string | "" | Location for weather (e.g., "New York, NY") |
| timezone | string | system | Timezone (e.g., "America/New_York") |
| units | string | "C" | Temperature units: "C" or "F" |
| birthdays.enabled | bool | true | Enable birthday tracking |
| birthdays.lookahead | int | 14 | Days ahead to show upcoming birthdays |
| birthdays.sources | array | ["contacts"] | Sources: "contacts" (iCloud), "google" |
| calendar.enabled | bool | true | Enable calendar events |
| calendar.lookahead | int | 0 | Days ahead (0 = today only) |
| calendar.sources | array | ["google", "icloud"] | Calendar sources |
| reminders.enabled | bool | true | Enable Apple Reminders |
| reminders.dueFilter | string | "today" | Due date filter: "today", "week", or "all" |
| reminders.includePastDue | bool | true | Include overdue/past-due reminders |
| emails.enabled | bool | false | Enable important emails feature |
| emails.icloudPassword | string | "" | iCloud Mail app-specific password |
| emails.limit | int | 10 | Maximum emails to show |
| emails.sortNewest | bool | true | Sort newest first |
| emails.starredFirst | bool | true | Prioritize starred emails |
| emails.unreadOnly | bool | true | Only show unread emails |