--- name: daily-brief description: > Use when the user wants to set up OR run their xTiles Daily planner — a Daily page that serves as a live morning brief from connected tools (Slack, Gmail) plus signals that need attention. Only the Daily period is supported. Setup triggers: "set up my planner", "personalize my workspace", "connect my planner to my tools", "create daily", "onboard a new xTiles user into the Planner". Digest triggers: "show me my morning brief", "what do I need to know today", "run my digest". Also runs automatically via scheduled tasks. Config is read from the scheduled task prompt — no separate file needed. For manual runs: look for config in today's Planner; if there's none, start from the survey flow below. allowed-tools: > mcp__xtiles__xtiles_get_planner_content, mcp__xtiles__xtiles_create_tiles_from_markdown_in_my_planner, mcp__xtiles__xtiles_get_user_timezone, mcp__claude_ai_Slack__slack_search_channels, mcp__claude_ai_Slack__slack_search_public_and_private, mcp__claude_ai_Slack__slack_read_channel, mcp__claude_ai_Gmail__search_threads, mcp__claude_ai_Gmail__list_labels, mcp__claude_ai_Gmail__get_thread, mcp__claude_ai_Google_Calendar__list_events, mcp__claude_ai_Granola__list_meetings, mcp__claude_ai_Google_Drive__list_recent_files, mcp__claude_ai_Linear__list_issues, mcp__mcp-registry__suggest_connectors, anthropic-skills:schedule, mcp__scheduled-tasks__create-scheduled-tasks --- # xTiles Daily Planner — Setup & Daily Digest ## Four principles 1. **Survey first, write to xTiles last.** Nothing gets created until the user has seen the preview and said "yes". 2. **Real data, not placeholders.** Pull from connectors before preview so the user sees live content. 3. **Match the user's language** throughout the entire flow — match the language of the user's first message and adapt if they switch. 4. **Every write is followed by the layout pass.** The moment tiles are created in step 7, re-lay them out into a justified grid via the shared `tile-layout` workflow — automatically, before the CTA, never skipped. --- ## Algorithm **Period is always Daily.** At the start of the flow, tell the user: "I'll set up your **Daily** planner page — a live morning brief from your connected tools." Never ask which period to set up. **Run mode — detect before step 1:** - **Scheduled run**: the incoming message contains `role:`, `tools:`, and `daily_content:` (config injected by the `schedule` skill). Do not show the survey. Extract the config from the message. If a connector from the config is not detected — offer to walk the user through connecting it before continuing. **Skip steps 5 and 6 (preview and approval) — after the fetch, write directly to xTiles. Also skip the schedule widget in step 7 — the task is already scheduled.** Then jump to **step 4 (Silent data fetch)**. - **Fast-track or fresh manual run**: proceed to step 1. ### 1. Fast-track If the user is specific ("give me daily for today", "I want to see Slack in the morning") — skip the full survey. Minimum needed: which connectors to pull from — infer from the message, then check the detection table (step 2) to confirm which are actually available. If a required connector is not detected — offer to walk the user through connecting it (see **How to connect connectors**); wait for confirmation before proceeding. Pull only from connectors that are both mentioned and confirmed available. Jump to **step 4**. If the request is general — run the full flow. --- ### 2. Survey — who are you and what's connected **Before calling `show_widget`**: Make a lightweight test call to each connector's identifying MCP tool (e.g. `list_events` with `maxResults:1` for Calendar, `slack_search_channels` with query `general` for Slack — this is an auth check only, not channel discovery). For any connector that responds without an auth error, pre-select its card in the widget HTML by setting `class="card sel"`. Generate the widget with those pre-selections applied, then call `show_widget`. **Show the survey widget** (HTML form) in Cowork. In Claude Code (no Cowork environment), ask the same questions inline as plain text — role, tools, content preferences, schedule. **Connected tools** (multi select, show all regardless of what's actually detected): - Slack - Gmail - Other After receiving answers — detect which MCP tools are actually available: | Connector | Identifying MCP tools | |-----------|-----------------------------------------------------------------------------------------------------------------| | Slack | `mcp__claude_ai_Slack__slack_search_channels`, `mcp__claude_ai_Slack__slack_read_channel` | | Gmail | `mcp__claude_ai_Gmail__search_threads`, `mcp__claude_ai_Gmail__list_labels`, `mcp__claude_ai_Gmail__get_thread`| | xTiles | `mcp__xtiles__xtiles_create_tiles_from_markdown_in_my_planner` | | Calendar | `mcp__claude_ai_Google_Calendar__list_events` | | Granola | `mcp__claude_ai_Granola__list_meetings` | | Google Drive | `mcp__claude_ai_Google_Drive__list_recent_files` | | Linear | `mcp__claude_ai_Linear__list_issues` | These connectors are external and optional — they are not shipped with this plugin. The user must connect them separately. **For "Other" connectors named by the user** — treat them identically to the known connectors above: attempt detection via available MCP tools; if not detected, walk through connecting via `mcp__mcp-registry__suggest_connectors`. **Before starting the connection flow, say the connector name explicitly** (e.g. "I'll now connect Plaud for you"). After the connection flow completes, explicitly resume: "Plaud connected. Continuing with [full list of tools]…". Carry the full list of selected tools — including every custom connector — through every subsequent step. Never drop a custom connector that the user named, even during multi-step connection flows. **If xTiles is not connected** — do not continue. Immediately walk the user through connecting xTiles (see **How to connect connectors** below). Wait for confirmation that xTiles is connected before proceeding. **If a connector the user selected isn't connected** (Gmail, Slack, etc.) — immediately walk them through connecting it step by step. Do not move to the next step until they confirm it's connected or explicitly choose to skip that connector. --- ### 3. Daily content clarification Question: "What do you want to see on your Daily each morning?" Options — include only those relevant to connected tools: - Unread emails that need a reply *(only if Gmail connected)* - Newsletters — curated summaries from your subscriptions *(only if Gmail connected)* - Slack messages from key channels *(only if Slack connected)* - Workload — calendar analysis: day shape, conflicts, focus windows *(only if Calendar connected)* - Other (describe in next message) Do NOT suggest tasks — they're already in xTiles by default. **If Slack is selected and the user has not already named their channels:** Use the role captured in the form as the anchor for this whole discovery — it drives both the interest search (Step C) and how specialized channels are scored (Step D). The goal is to surface *this specific user's* channels, not a generic company list. **Step A — universal channels (every role).** Call `mcp__claude_ai_Slack__slack_search_channels` for each of these names: `general`, `all`, `team`, `company`, `announcements`, `product`. Collect every channel that actually exists — these are candidates for the shared/general slot, never for the specialized slot. **Step B — activity signal (the strongest relevance signal).** Call `mcp__claude_ai_Slack__slack_search_public_and_private` twice: once with query `from:me` (channels where the user actually posts) and once with query `to:me` (channels where the user is @mentioned or replied to). For every result, record the channel and the message timestamp. Per channel, track two things: **recency** — the timestamp of the user's most recent post or mention there, and **frequency** — total hit count across both queries. A channel the user posted or was mentioned in yesterday is more relevant right now than one with more total hits but nothing in weeks — recency is the primary activity signal, frequency only breaks ties between channels with similarly recent activity. **Step C — role & interest/affinity search.** Reason from the user's role: what does this person actually write and receive in Slack day-to-day? Derive 2–3 short phrases that would naturally appear in messages in their active channels and search for them. Then run a second, broader pass for interest and affinity-group channels that may exist regardless of role — e.g. terms like `women`, `parents`, `wellness`, `book club`, `volunteering`, `pride`, `remote`, `pets`, or other hobby/interest terms suggested by the role context. Do not use a fixed table for either pass — think from context. If the user explicitly named topics or interests, search those first. **Step D — merge, rank, and select.** 1. Merge every channel found in Steps A–C, removing duplicates (a channel found in more than one step counts once, keeping its highest score). 2. Drop low-signal: name contains `random`, `fun`, `off-topic`, `bots`, `test`, `hiring`, `onboarding`. 3. Score each channel, in this order: **Step B activity ranks highest** — sort by recency of the user's last post/mention there first, then by frequency as the tiebreaker among similarly-recent channels; **then** role/interest/affinity matches from Step C; **then** bare universal presence from Step A alone. A channel where the user was just mentioned yesterday outranks a role-matched channel they never actually post in. 4. Show every remaining discovered channel as a selectable card — cast a wide net across interests and affinity groups so the user has real options to add, not just a token list. 5. **Pre-select (mark active) up to 5 total, no more:** at most 2 from the universal slot (highest-scoring first, e.g. general → all → team → announcements → company → product), and the rest from the highest-scoring specialized channels in Step D's ranking — the channels this specific user actually writes in, is mentioned in, or that match their role/interests. Every other discovered channel stays visible but unchecked — the user decides what else matters to them each morning. **Fallback:** if Steps B and C both return zero results — call `mcp__claude_ai_Slack__slack_search_public_and_private` with query `team update` and extract channels from those results. Generate an HTML multi-select widget with the discovered channels as selectable cards — mark the up-to-5 chosen in Step D.5 with the pre-selected `sel` state — and call `show_widget`. Include a free-text input for unlisted channels. Use `sendPrompt()` to submit. Template (inject one card per discovered channel; add `sel` to the class and keep `data-v` in sync for the pre-selected ones): ```html

Which channels do you open first each morning?

Pre-selected: your most active and relevant channels. Add any others you want to see.

``` **If Newsletters is selected:** **Important:** if the user selected "Newsletters" in the survey widget (step 2), this discovery flow must still run — do not skip it because newsletters was pre-selected there. The survey captures the preference; this step discovers the actual sources. First, silently call `mcp__claude_ai_Gmail__search_threads` with query `from:(@substack.com OR @beehiiv.com OR @convertkit.com OR @mailchimp.com) newer_than:30d` to discover newsletters already in the inbox. Extract unique sender/publication names from results. If publications found — call `show_widget` with an HTML multi-select listing the discovered newsletters as selectable cards. Template (inject one card per found publication): ```html

Which newsletters do you want in your Daily?

``` If nothing found — call `show_widget` with a simple text input widget asking the user to name the newsletters they want to track. Add all selected/typed senders to the config. Tip: newsletters typically come from `@substack.com`, `@beehiiv.com`, `@convertkit.com`, `@mailchimp.com`. **General rule:** if the user writes something custom — add it as-is. Don't reshape it into a predefined option. --- ### 4. Silent data fetch **Silently, without messaging the user**, pull fresh data from connectors based on selected sections and content choices: - **Gmail — unread emails**: `mcp__claude_ai_Gmail__search_threads` — query `is:important in:inbox newer_than:1d`. For each thread call `mcp__claude_ai_Gmail__get_thread` to get sender, subject, and threadId for the direct link (`https://mail.google.com/mail/u/0/#inbox/{threadId}`). - **Gmail — newsletters**: `mcp__claude_ai_Gmail__search_threads` — query `from:({sender1} OR {sender2} ... OR @substack.com OR @beehiiv.com OR @convertkit.com) is:unread newer_than:1d` — combine user-named senders with common newsletter domains. Fetch each thread with `get_thread` for a one-line summary and `threadId` for the link. - **Slack**: two parallel reads: 1. `mcp__claude_ai_Slack__slack_read_channel` for each chosen channel (top 50 messages). Filter to last 24 hours (timestamp ≥ now − 24 h). Discard older messages. Skip channels with no messages silently. 2. `mcp__claude_ai_Slack__slack_search_public_and_private` with query `to:me` to find messages where the user was @mentioned or DM'd. Filter results to last 24 hours. This covers both public and private channels, including ones not in the chosen list. After collecting, analyse all messages together and group semantically. For every item include a **direct permalink to the specific message** — extract `permalink` from the message object (or build `https://slack.com/archives/{channel_id}/p{ts_without_dot}`). Never link to the channel homepage — always to the individual message. - **Mentions** *(highest priority)* — all messages from the `to:me` search. For each: who mentioned the user, in which channel, what was asked or said — one line per mention, message permalink. If the mention requires a response — flag it as ⚡. - **Topics** — what was discussed in channels; group by theme, one topic = one line, permalink to the most relevant message, channel attribution `[#channel](permalink)` - **Decisions** — where something was agreed, committed to, or confirmed — include message permalink - **Open questions** — where a question was raised but no clear answer came yet — include message permalink, mark as ⏳ - **Calendar**: `mcp__claude_ai_Google_Calendar__list_events` — today's events. For each event extract: start/end time, title, participant names (first name + last name or company), and meeting link (Google Meet, Zoom, or other video URL from event data). Compute: - **Summary line**: event count, total hours occupied, longest free focus window (HH:MM–HH:MM, duration in hours) - **Per-event row**: time range · title — participants list · [meeting link label](url) if present - **🧠 context** (only if Granola or Gmail connected): for each meeting, find the last Granola note involving the same participants and/or the most recent open Gmail thread with the organiser — write one sentence summarising what the meeting is about or what was discussed last time. Only include if relevant context is found; skip silently otherwise. - **⚠️ anomalies** — collect all, show at the bottom of the tile (not inline): overlapping events, back-to-back with no gap, events after 20:00, events without description/agenda, potential duplicate titles close together Classify emails into three buckets. **Newsletters are fetched separately — exclude them here entirely and do not count them in any bucket.** - 🔴 **Потребує дії** — emails where the user must take a concrete next step (reply, decide, act, log in) - 🟡 **До уваги** — FYI only: confirmed meetings, signed documents, payments, status updates — past/present tense, nothing to do - ⚪ **Шум** — notifications, automated alerts, service emails — do not describe individually; count only **Tone for 🔴 and 🟡 — Poke-style, capitalized:** - Retell the email, do not copy the subject line. Subject → action → consequence in second person: not "Your account closed" but "Google закрив твій рекламний акаунт учора" - For 🔴: weave the next step into the sentence: "Залогінься і віднови — вікно на апеляцію обмежене" - Use people's names, not email addresses. Context in parentheses if needed: "Стефан (influencers.club)" - Telegraphic, conversational. First letter capitalized, no bureaucratic language. - 🟡 items are one-liners — no link needed. For every 🔴 email, derive one verb-first action item (e.g. "Відновити рекламний акаунт Google"). Collect as a flat list — used in preview and tile. Use only real data from connectors. Do not invent names, events, or messages. All names and message content must come directly from API responses — never from examples in this skill file. If a connector call fails (error, timeout, 401) — record the failure. Do not write "No data" for a failed call — surface the error explicitly in step 5 so the user knows the connector did not respond. --- ### 5. Preview — show content in chat Show real content with real data. Not structure, not headings with "(TBD)" — actual text. Format (adapt to selected pages): ``` Here's what I've prepared: --- 📅 DAILY — [actual date] ### Emails 🔴 Потребує дії (N) - [Poke-style description — 1–2 sentences, second person, action + consequence] → [Відкрити лист](https://mail.google.com/mail/u/0/#inbox/{threadId}) - [Next 🔴 email, same format] → [Відкрити лист](https://mail.google.com/mail/u/0/#inbox/{threadId}) 🟡 До уваги (N) - [One-line item — no link] - [One-line item] ⚪ Шум - N сповіщень (sources) — нічого термінового **Action items:** - [ ] [verb-first task from 🔴 email 1] - [ ] [verb-first task from 🔴 email 2] *(omit Action items entirely if no 🔴 emails)* ### 📧 Newsletters **[Newsletter Name](https://mail.google.com/mail/u/0/#inbox/{threadId})** One-line summary. **[Another Newsletter](https://mail.google.com/mail/u/0/#inbox/{threadId})** One-line summary. ### 💬 Slack **Channels:** #channel1 (N) · #channel2 (N) #### ⚡ Mentions - **@Name** in [#channel](url) — what they asked/said ⚡ #### 💬 Topics - **[Topic name]** — [one-sentence summary] — [#channel](url) #### ✅ Decisions - [Decision] — [#channel](url) #### ❓ Open - [Question] — [#channel](url) ⏳ ### 📅 Calendar **N events · ~X h occupied · longest focus window HH:MM–HH:MM (X h)** **HH:MM–HH:MM · Meeting name** — Participant1, Participant2 · [Google Meet](url) 🧠 [one sentence: meeting point / what will be discussed] **HH:MM–HH:MM · Meeting name** **HH:MM–HH:MM · Meeting name** — Participant from Company · [Google Meet](url) 🧠 [meeting point] ⚠️ [anomaly — e.g. two external calls back-to-back in the evening, 30 min gap between them] --- ``` Each 🔴 email uses the real `threadId` from `get_thread` for the [Відкрити лист] link. 🟡 items are one-liners with no link. Each newsletter is shown as its own named section in the preview — never mixed into the Emails section. Separate each item with a blank line for readability. **Rules:** - Show only selected sections the user asked for - If a connector returned no data — write exactly that ("No unread emails", "No newsletters today", "No Slack updates today") — never skip the section silently; its absence looks like a bug - If a connector call failed — write "Could not fetch [connector] data — connector error" (not "No data") - No placeholder names, example events, or invented data — ever - After the preview, **stop and wait**. Do not write anything to xTiles yet. --- ### 6. Approval **Mandatory. Never skip this step.** After showing the preview, call `show_widget` with the **Approval widget HTML** (see below). Do not call `xtiles_create_tiles_from_markdown_in_my_planner` until the user explicitly clicks **"Looks good — create it"**. If the user asks for a change — clarify exactly what, update only that section, re-show preview, ask again. --- ### 7. Write to xTiles **Only after explicit approval.** Tool: `mcp__xtiles__xtiles_create_tiles_from_markdown_in_my_planner` - `period`: "day" - `date`: current date in ISO 8601 **Write all sections in a single call.** Combine all selected connectors (Gmail, Slack, etc.) into one markdown and call the tool once — never split into separate calls per connector. **Do NOT create a date/header tile.** Never write `### [date]` or any title-only tile as the first item — start directly with content tiles. **Tile formatting** — each `###` section must include color and style annotations immediately after the heading (no blank line between): ``` ### [emoji] [Title] @colorSize: LIGHTER @color: [COLOR] [content] ``` - `@colorSize` is always `LIGHTER` - `@color` — pick randomly for each section from this list **exactly as written**: `GHOST, CUMULUS, GOSSIP, COLDTURKEY, BLUE_CHALK, MILK_PUNCH, HAWKES_BLUE, PATTENS_BLUE, SAIL, ATHENS_GRAY, BERMUDA, PERFUME, SELAGO, RICE_FLOWER, WHITE_LINEN, POLAR` **CRITICAL: never use semantic color names (RED, BLUE, GREY, ORANGE, YELLOW, GREEN, etc.) — they will not render. Only the exact names from the list above.** - Each section gets a different color — do not repeat the same color twice in a row **Content formatting inside each tile:** - **All links must be Markdown hyperlinks** — always `[text](url)`, never a bare URL. If you include a link, it must have a label. - Separate each item with a blank line — never write items as a continuous block - **Emails**: structure the tile in three labeled blocks followed by action items: ``` 🔴 **Потребує дії (N)** - [Poke-style description — 1–2 sentences, second person, action + consequence] → [Відкрити лист](https://mail.google.com/mail/u/0/#inbox/{threadId}) - [Next 🔴 item, same format] → [Відкрити лист](url) 🟡 **До уваги (N)** - [One-line item — no link, never] - [One-line item] ⚪ **Шум** - N сповіщень (sources) — нічого термінового --- **Action items** - [ ] [Verb-first task from 🔴 email 1] - [ ] [Verb-first task from 🔴 email 2] ``` Omit `Action items` section entirely if no 🔴 emails. Newsletters are in the separate `### 📧 Newsletters` tile — never include them here. - **Newsletters**: ALL newsletters go in a **single `### 📧 Newsletters` tile** — never create a separate tile per newsletter. Structure: - Each newsletter as a bold hyperlink title followed by a one-line summary on the next line: ``` **[Newsletter Name](https://mail.google.com/mail/u/0/#inbox/{threadId})** One-line summary. ``` - Blank line between entries. - The link IS the title — no separate "Open" button or link at the bottom of each entry. - Omit the entire tile only if there are no unread newsletters at all. - **Slack**: **ALL Slack channels go in a SINGLE `### 💬 Slack` tile** — never split channels into separate tiles. Structure the tile content using semantic `####` subheadings: - First line (no subheading): channel activity summary — `**Channels:** #channel1 (N) · #channel2 (N)` - `#### ⚡ Mentions` — messages where the user was @mentioned. One line per mention: `- **@Name** in [#channel](message_permalink) — what they asked/said`. Add ` ⚡` if a response is needed. **Omit subheading only if no mentions found.** - `#### 💬 Topics` — one line per topic: `- **Topic name** — one-sentence summary — [#channel](message_permalink)` - `#### ✅ Decisions` — one line per decision: `- Decision made — [#channel](message_permalink)`. Omit subheading if no decisions. - `#### ❓ Open` — one line per unanswered question: `- Question — [#channel](message_permalink) ⏳`. Omit subheading if no open questions. - **All Slack links must point to the specific message permalink, never to the channel homepage.** - **If no messages from today across all channels** — still create the tile, skip the `**Channels:**` line and all subheadings, and write a single line: `No updates today.` Never omit the tile entirely — its absence looks like a connector failure. - **Calendar**: tile titled `### 📅 Calendar`. Use this exact structure: ``` ### 📅 Calendar @colorSize: LIGHTER @color: [pick randomly from the color list] **N events · ~X h occupied · longest focus window HH:MM–HH:MM (X h)** **HH:MM–HH:MM · Meeting name** — Participant1, Participant2 · [Google Meet](url) 🧠 [one sentence: meeting point / what will be discussed] **HH:MM–HH:MM · Meeting name** **HH:MM–HH:MM · Meeting name** — Participant from Company · [Zoom](url) 🧠 [meeting point] ⚠️ [anomaly] ``` Rules: - Summary line is bold, always first - Each event on its own bold line: `**HH:MM–HH:MM · Title**` — append ` — Participants · [Link label](url)` if participants or meeting link exist - 🧠 goes on the next paragraph directly under its event — only if Granola or Gmail context was found; omit otherwise. Use Markdown hyperlinks for Granola note and Gmail thread: `[Note title](url)` + `[Thread subject](gmail-url)` - All ⚠️ anomalies collected at the bottom, one per line - Blank line between every item (event, 🧠, ⚠️) for readability - Omit tile entirely if Calendar returned no events - This ensures the tile is scannable, not a wall of text **If xTiles is not connected** — do not output the digest as plain text in chat. Walk the user through connecting xTiles (see **How to connect connectors**), wait for confirmation, then write. **If the page already exists:** 1. Call `mcp__xtiles__xtiles_get_planner_content` 2. Compare existing H3 headers (`###`) with what you're about to add 3. Append only sections whose headers don't exist yet 4. If everything already exists — ask: replace all, append anyway, or cancel? **After each successful write — run these four steps in order, no exceptions:** 1. Write `✅ Daily created.` 2. **Layout pass — mandatory stage after adding tiles. Runs on every write (scheduled runs included); never skipped, never deferred, never asked about.** Freshly written tiles land in a default stack — re-lay them out *now*, before the CTA and schedule widgets below: - Read `view_id` and `tile_ids` straight from the `xtiles_create_tiles_from_markdown_in_my_planner` response (`tile_ids` is ordered to match the `###` sections you just wrote). Keep `view_id` — step 3 reuses it, do not re-fetch it. - Call `mcp__xtiles__xtiles_get_workflow` with id `tile-layout` and follow it exactly: pass `tile_ids` as its "added tiles", the markdown you just wrote as their content, and these **layout hints** — 1–4 tiles · default 2 per row · give a heavy tile (usually 💬 Slack or Emails) its own full-width row. - Apply the layout silently — no message, no confirmation. Only once it is applied, continue to step 3. 3. Reuse the `view_id` from the write response (step 2) — **do not call `get_planner_content` to re-derive it.** Call `show_widget` with the **CTA widget HTML** (see below), replacing `{VIEW_URL}` with `https://xtiles.app/{view_id}`. Translate the button label into the user's language. **Never output a markdown link instead of the widget.** 4. **For non-scheduled runs only**: Immediately call `show_widget` with the **Schedule widget HTML** (see below). Do not skip this step, do not ask first — just show it. **If an error occurs:** briefly say what went wrong, offer to retry or skip that page. --- ### 8. Schedule (optional) The schedule widget is shown in step 7 above. This step handles the user's response. In Claude Code (no Cowork): after writing, ask inline: "Want me to run this every morning automatically? What time? (default: 9:00 AM)" - If the user selects **"Yes, schedule it"** — first invoke `anthropic-skills:schedule`, then call `mcp__scheduled-tasks__create-scheduled-tasks`. Pass to both: - **`prompt`**: the full config string assembled from values collected during setup — ``` Run daily digest — role: {role} · tools: {tools} · daily_content: {content} · schedule: daily-{HH:MM} days:{days} ``` Replace `{role}`, `{tools}`, `{content}`, `{HH:MM}`, and `{days}` with the actual values parsed from the widget response. Do not leave placeholders. - **`schedule`**: cron expression derived from the widget. The widget sends `cron: HH:MM days:1-5` or `cron: HH:MM days:*` — parse both values: time gives H and M, days gives the weekday field. Build: `M H * * {days}`. Examples: `cron: 08:30 days:1-5` → `30 8 * * 1-5` · `cron: 08:30 days:*` → `30 8 * * *`. Default if missing: `0 9 * * 1-5`. - **`timezone`**: the user's local timezone — call `mcp__xtiles__xtiles_get_user_timezone` to get it before scheduling if it hasn't been fetched yet. This prompt fires each morning and triggers `daily-brief` in scheduled-run mode — the full config must be embedded so the survey is skipped automatically. After scheduling succeeds, confirm: "Done — your Daily will be ready in xTiles every morning at [chosen time]." Then call `show_widget` with the **CTA widget HTML**, replacing `{VIEW_URL}` with `https://xtiles.app/{view_id}` (the same `view_id` from step 7). Never output a markdown link here — always the button widget. - If the user selects **"No, thanks"** — acknowledge briefly. Either way, continue to **step 9 (Related workflows)** — do not stop here. --- ### 9. Related workflows **After every manual run, once step 8 is resolved** (scheduled or declined) — offer related workflows. Skip this on scheduled runs, which end silently after step 7. Ask via `AskUserQuestion` (single select): "Want to set up anything else on xTiles?" - 🌙 Evening Reflection — an end-of-day synthesis seeded for tomorrow - 📰 Today News — a daily news digest on topics you care about - 📊 Weekly Review — a weekly summary of what moved forward this week - Nothing else, thanks **Never list these as plain text requiring the user to retype a choice — always use the interactive question.** On selection, send the exact matching phrase to hand off to that skill (do not attempt to run it yourself): - Evening Reflection → `Set workflow of Evening Reflection (evening-reflection) on xTiles MCP` - Today News → `Set workflow of Today News (today-news) on xTiles MCP` - Weekly Review → `Set workflow of Weekly Review (weekly-review) on xTiles MCP` - "Nothing else" — acknowledge briefly and stop. --- ## How to connect connectors Do not send the user to settings manually and do not give a URL to follow. Call `mcp__mcp-registry__suggest_connectors` — it renders interactive connect buttons directly in the Cowork UI. **Flow:** 1. Call `mcp__mcp-registry__suggest_connectors` passing the names of the missing connectors. 2. Show the **Done widget** (see **Done widget HTML** below) directly under the connector form. 3. The user clicks the connect buttons in the UI — the auth flow runs natively. When finished, they click **"Done"**. 4. Confirm: "Connected. Continuing…" and resume the flow from where it was interrupted. --- ## Approval widget HTML Show this via `show_widget` after the preview in step 6. If the user clicks "Change something" — ask what to change in plain text, update that section, re-show the preview, then show this widget again. ```html
``` --- ## Done widget HTML Show this widget via `show_widget` immediately after calling `mcp__mcp-registry__suggest_connectors`. The user clicks **Done** when they have finished connecting — this sends a message to chat and resumes the flow. ```html ``` --- ## Survey widget HTML Show this form via `show_widget` at the start of setup in Cowork. After Submit, the user sends a string of answers to chat — process it and continue the flow. ```html
Step 1 of 2

About you

What's your role?
Product Manager
Designer
Engineer
Growth & Marketing
Founder / CEO
Support & Success
Other role…
Which tools do you use?
Select all that apply — I'll pull live data from them
Slack
Gmail
Calendar
Granola
Linear
GitHub
Google Drive
Gamma
Figma
``` --- ## CTA widget HTML Show this immediately after a successful write. Replace `{VIEW_URL}` with the real xTiles page URL before calling `show_widget`. ```html Open in xTiles → ``` --- ## Schedule widget HTML Show this widget via `show_widget` after a successful write in Cowork. After the user clicks a button, the widget calls `sendPrompt()` and the response lands in chat. ```html

Run this every morning?

I'll fetch your signals and write your Daily to xTiles automatically — no need to ask each time.

📅 Every at
``` --- ## How to behave - Use the survey widget for setup; ask inline for approval and any follow-up clarifications - **Never output the digest as plain text in chat** and ask the user to copy it manually — always write to xTiles directly, or walk through connecting xTiles first - **Never skip a connector** the user selected — if it's not connected, walk through the connection before continuing, don't silently drop it - Never create anything without preview and explicit approval - Never put example names, example events, or example messages into the preview — only real data from connectors - **All clarifying questions and approvals after the main survey form** (channel selection, newsletter names, approval, change requests) — use `show_widget` with HTML, never `AskUserQuestion` or plain text - If context is missing — ask, don't guess - If the user gives new information along the way — pick it up, don't wait for the "right step" - Real data from connectors always beats placeholders - Daily is the only period. If the user asks for Weekly or Monthly, tell them only the Daily planner is currently supported and offer to create a Daily page instead — never silently downscope. - Match the user's language, adapt if they switch - Show the survey widget in Cowork only — in Claude Code, ask the same questions inline