| name | daily-brief |
| description | Produce today's daily briefing across all Google Calendars, Gmail accounts, Slack workspaces, and Asana. Writes to + Atlas/Daily/YYYY-MM-DD.md and surfaces anything that needs the user's attention today. Safe to re-run — refreshes the `## Morning brief` section in place. |
/daily-brief
Assemble the user's daily briefing for today (or a date passed as $1). Creates or updates the matching daily note in + Atlas/Daily/. Re-runnable: the skill replaces the ## Morning brief section in place rather than appending a new one.
Inputs
$1 (optional): target date in YYYY-MM-DD. Defaults to today.
Procedure
Date check first. Before any other work, if $1 is not supplied, resolve "today" by running Bash: date "+%Y-%m-%d %A %H:%M %Z". Do not trust the session-injected currentDate field — it can lag the real clock by a day. Use the shell result as the target date for everything below.
Parallelization: steps 1–6 are all independent read-only gathers. Fan out every MCP call — all google_* accounts, all slack_* workspaces, all configured Asana workspaces, and Fathom — in a single tool-use block. Do not serialize across accounts or across steps.
-
Calendar sweep. For each google_* MCP, call google_calendar_list_events for the target date (00:00 → 23:59 local). Merge into a single timeline; tag each event with the owning account slug. Collapse duplicate events that appear on multiple calendars (same title + time).
1b. Fathom recordings. Call mcp_fathom_fathom_list_meetings for meetings in the last 24h. For each, note title, participants, and whether a summary is available. Surface under a Recent recordings section in the brief — title, attendees, and a fathom:<meeting-id> reference the user can pass to /capture-meeting if they haven't already processed it.
-
Priority mail. For each google_* MCP, google_gmail_search_emails with is:unread newer_than:2d (is:important OR is:starred OR label:^iim). Cap at 10 per account. Capture subject, sender, account slug.
-
Slack attention. For each slack_* MCP, fetch two complementary sources in the same parallel block:
slack_conversations_unreads with limit: 200 — top-level unread channels and DMs. The limit param caps channels scanned, not unreads returned, so smaller values miss DMs in lower-priority channels.
slack_my_mentions with hours: 24 — explicit <@me> mentions across channels and thread replies. This is required: conversations_unreads only checks each channel's top-level unread_count (from conversations.info), which excludes thread replies and mentions in channels you've already read. Without this call, @mentions in threads silently disappear.
After fetching both, dedupe and summarize the top 10 most relevant items.
-
Overdue tasks. For each configured Asana workspace (asana_personal, asana_work), asana_get_my_tasks with completed_since=now, opt_fields=name,due_on,due_at,completed,assignee_section.name,projects.name,permalink_url,recurrence, and post-filter to due date < today. The recurrence field is mandatory — see "Asana display ordering" below for why.
-
Stale relationships. Grep + Atlas/People/*.md for notes whose last_contact is older than their cadence allows (weekly: > 7d, monthly: > 30d, quarterly: > 90d, asneeded: never stale). Cap at 5.
-
People detection pass. From the calendar attendees + priority mail senders/recipients + Slack counterparties gathered in steps 1–3, check each identifier against + Atlas/People/*.md frontmatter (emails, slack, title, aliases). Unknown humans (after filtering no-reply/bots/resources per /sync-people rules) become a New faces candidate list — do not stage stubs from this skill; just surface them. Recommend /sync-people if the list is non-empty.
6b. Draft replies for actionable threads. After steps 1–6, invoke /draft-follow-up for each "Needs a reply" item where the user is the next actor. /draft-follow-up is the single source of truth for drafting mechanics (account selection, writing-style application, save tool, vault trail). This skill only decides which items get drafted.
Skip list (do not invoke /draft-follow-up for these):
- Items classified as
Delegated / FYI (care team, ops auto-alerts)
- Observer-only threads
- Automated notifications (Asana digests, Dependabot, commercial mailing lists)
For each remaining actionable item:
- Build the
/draft-follow-up input: pass the gmail thread id (for email) or slack permalink (for Slack) as $1, and a one-line intent hint as $2 derived from the thread.
- Invoke
/draft-follow-up. It will resolve the account, pull person context, apply the §6 writing style, save the draft via the matching gmail_draft_email or slack_drafts_create tool, and log the vault trail under the person's ## Threads section.
- Collect the returned draft id and account into this skill's "Drafted replies" output section (step 7).
Parallelization: /draft-follow-up invocations across distinct threads are independent. Fan out all invocations in a single tool-use block.
-
Compose the daily note. If + Atlas/Daily/<date>.md does not exist, scaffold from + Extras/Templates/Daily.md. If a ## Morning brief section already exists in the note, replace its body in place (find the ## Morning brief heading and overwrite everything up to the next H2 or EOF). Otherwise insert a new ## Morning brief section near the top. Contents:
- Today's calendar (merged timeline, grouped bullet list,
[HH:MM–HH:MM] Title · account-slug · other attendees if any)
- Recent recordings (Fathom meetings from last 24h not yet captured as interaction notes — title, attendees,
fathom:<id> ref; omit section if empty)
- Needs a reply (mail + slack, grouped by account/workspace)
- Drafted replies — list of drafts saved in step 6b. One bullet per draft:
- ✉️ [[Person]] — Re: Subject · gmail draft <draft-id> · <account> (or 💬 for Slack). Include a footer: _(Review and send from Gmail / Slack. Drafts are not sent automatically.)_. Omit the section if no drafts were generated (all items were delegated/FYI).
- Overdue in Asana
- People past cadence (link with
[[wikilinks]])
- New faces — unknown humans seen in today's activity, one line each with source context. Omit the section if empty.
- A single-line Focus suggestion based on the above
-
Never touch any other section of the daily note. Only the ## Morning brief section is managed by this skill.
-
Refresh Dashboard.md at the vault root. This skill is the primary owner of the dashboard and rebuilds it on every run, since it already has all the data in hand. Only run this step when the target date is today — historical reruns must not retroactively rewrite the dashboard. Procedure:
- For each H2 section in
Dashboard.md listed below, replace the body in place (find the heading and overwrite everything up to the next H2 or EOF). Do not create the file from scratch — if Dashboard.md is missing, log a warning and skip step 9. Never touch ## Quick links (static).
- Additional data gathering for week-ahead sections. Before composing
## This week and ## Top priorities, also fetch:
- Current-ISO-week calendar sweep across all
google_* accounts via google_calendar_list_events from start-of-week (Mon 00:00) → end-of-week (Sun 23:59) for the week containing today. Fan out in parallel across accounts.
- The 7-day Asana window for
## Top priorities is already covered by the "Asana scope note" below (asana_get_my_tasks post-filtered to due_on between today and today+7).
- Sections to rebuild every run:
## Today — <Day YYYY-MM-DD> — pivot meeting + 5–8 line condensed timeline of today's anchors. Update the heading date too.
## This week (<Mon M/D> → <Sun M/D>) — update heading dates to the current ISO week (Mon → Sun containing today). Two sub-sections: Work — meetings that matter (filter to events with attendees > 1; collapse Reclaim "Busy", out-of-office, and the user's solo blocks) and Personal anchors (recurring family / community / 1:1 events, multi-day travel/retreats). Plans shift mid-week — always rebuild from fresh calendar data so this stays accurate.
## Top priorities — two sub-lists: Work — due in next 7 days and Personal — due in next 7 days, each as a checkbox bullet with [[wikilinks]] to people where natural. Apply the Asana display ordering rules below (group by recurrence.type, sort least-frequent → most-frequent within each list).
## Needs a reply / open loops — same data as the brief's "Needs a reply" section, but formatted as one bullet per item with [[wikilinks]]. Filter out delegated/FYI noise.
## People past cadence — same content as the brief's section.
## Delegated / FYI — auto-alerts and FYI items surfaced today that the user does not need to action.
- Frontmatter. Update the
updated: field to <today> after writing.
- Idempotence. Re-running
/daily-brief on the same day must produce the same dashboard (modulo any new mail/slack/calendar deltas). Never append; always replace section bodies in place.
Output shape
Create or refresh the ## Morning brief section in + Atlas/Daily/<date>.md, plus the dashboard sections owned by this skill in Dashboard.md (see step 9). Report a short summary of what was (re)generated to the user in chat — including the dashboard refresh status.
Asana scope note
Step 4 ("Overdue tasks") is for the brief itself. For the dashboard's ## Top priorities stub generation in step 9, widen the Asana query to include tasks with due_on between today and today + 7 days, grouped by workspace. Use the same asana_get_my_tasks call — just don't post-filter to < today.
Asana display ordering
Whenever this skill renders a flat list of Asana tasks (in the Overdue in Asana section of the brief, the ## Today must-do block of the dashboard, or the ## Top priorities lists), group by due_on ascending (one date heading per day, earliest first), then within each day sort by recurrence frequency, least-frequent → most-frequent, so high-stakes one-offs bubble to the top of each day. Do not render frequency sub-labels — each day is a single flat list of checkboxes. The frequency ordering is implicit through sort order only.
Source of truth: the Asana recurrence.type field. Never guess from the task name. Heuristics are unreliable — task titles rarely encode their repeat cadence.
Required opt_fields. When this skill issues asana_get_my_tasks (step 4) or any task fetch that will feed into a display list, recurrence MUST be in opt_fields. Standard fetches don't return it. The recommended opt_fields string for this skill: name,due_on,due_at,completed,assignee_section.name,projects.name,permalink_url,recurrence.
recurrence.type → sort order within the day:
recurrence.type | Sort order |
|---|
never (one-off) | 1 (highest priority, top of day) |
yearly | 2 |
monthly | 3 |
weekly | 4 |
daily | 5 (bottom of day) |
If recurrence is missing from a task response (e.g. an API error or older field set), treat as never and flag the task with a ? so the user can verify.
Layout. Render each day as a bold date heading (e.g. **📅 Mon 6/01 (today)**), followed by a flat checkbox list of that day's tasks in the sort order above. No sub-labels, no nested bullets — sub-labels eat too much vertical space. Collapse same-frequency siblings onto one line with · separators when that keeps the list scannable (e.g. the three monthly resets on Mon 6/01). Daily-recurring tasks should be collapsed to a single bullet prefixed with _Daily (N open):_ so the daily checklist doesn't dominate the day's view. Omit empty days. This grouping is the default behavior when no explicit alternative sort is in effect. Why this ordering, not pure frequency-first: due-date primary lets the user scan a day-by-day plan; frequency-secondary within each day still floats the high-stakes one-offs above the recurring chore bundle. Pure frequency-first scattered today's items across 4 sections, which broke the daily-plan scan. And explicit frequency sub-labels add too much vertical chrome — the sort order alone communicates the priority.
Notes
- Idempotent by design. Running
/daily-brief twice on the same date replaces the section rather than duplicating it. The section header stays ## Morning brief (the name reflects content intent, not the time of day the skill was invoked).
- Never send any email or Slack message — this skill creates drafts only (step 6b). Drafts are not sent; the user reviews and sends from the native client.
- If a given MCP server fails, note it in the brief (
_(google_<slug>: unavailable)_) and continue.
- Respect the
#workspace/personal vs #workspace/work split only if the user asks for a single-workspace brief (e.g. /daily-brief work → skip all workspace=personal sources). Without a flag, include everything.