daily-briefing — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited daily-briefing (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Produces a daily prioritized briefing over the user's monday CRM data and publishes it as a monday artifact — so the brief lives inside monday, not just in the chat.
Works for any monday CRM setup: pipeline users get deal buckets and pipeline totals; contacts/accounts users get relationship health and follow-up queues; lead managers get inbound lead status. If the user has no monday CRM board at all, the skill runs in standalone mode — ask for context, produce a useful brief from what they tell you.
When monday CRM features are in use, the brief automatically gets richer:
| monday CRM feature | What it adds | MCP access |
|---|---|---|
| Notetaker | Recent meeting notes matched to open deals or contacts | get_notetaker_meetings |
| Activity log | Logged calls, emails, and meetings on deals/contacts (last 48h) | get_board_activity + get_updates |
| Tasks / follow-ups | Items with a date column = today across deals or contacts board | get_board_items_page with date filter |
| Calendar sync (Outlook/Google) | Today's CRM-linked meetings | Not yet in MCP — skipped; wired when available (see workset status.md) |
| Email sync (Gmail/Outlook) | Tracked email threads on deals/contacts | Not yet in MCP — skipped; logged emails accessible today via get_updates on contacts/deals |
monday CRM's calendar and email sync features exist in the product but are not fully exposed via the MCP connector yet. The skill attempts to reach them via all_monday_api raw GraphQL. If the data isn't there, it notes the gap in the brief and skips the section — it does not error out.Flow: Connector check → Mode → Connector discovery → Board detection → Board type → Data pull → Synthesize → Publish → Share (opt-in) → Proactive (opt-in).
Morning Briefing — <weekday>, <Mon DD>. Body carries the Generated by Claude footer + an HTML comment <!-- claude-skill-id: daily-briefing --> for idempotency. Markdown brief printed in chat as a mirror.create_update on stalled records; create_notification for commitments due today.get_user_context — resolve user + favorite boards.list_workspaces — enumerate workspaces when search is ambiguous.search — find CRM boards by broad search terms.get_board_info — board schema + column IDs + labels.get_column_type_info — resolve columns by type when names aren't English.get_board_items_page — pull active records, recently closed, recent activity.board_insights — aggregate fallback when >200 items.create_update — publish α to pinned item; proactive nudges on stalled records.create_doc — publish α as a doc when no pinned item exists.create_notification — β share; proactive alert for commitments due today.list_users_and_teams — resolve recipient for β share.all_monday_api — escape hatch for doc updates / metadata lookups not in wrapped tools./monday-crm:forecast-dashboard./monday-crm:board-diagnosis.Goal: Fail fast if the user has no monday MCP connection.
mcp__monday__get_user_context.user.id and user.name.PAUSE: do not write any create_* call before Step 6, and never before Step 0 passes.Goal: Know write behavior and output preferences before doing anything else.
create_* or change_* call in chat before executing.If no mode declared, assume Default. Trigger: morning briefing silent / morning briefing proactive / mode: proactive in project instructions.
Hard safety rail regardless of mode: no deletes, no amount-column writes, no cross-workspace moves. Stage, owner, last-touch, and source column edits are allowed when bundled in a batched-confirm plan (Default) or session-level approval (Proactive).
Read from project instructions or per-run prompt. All fields are optional — defaults apply when absent.
Verbosity (default: full)
full — all sections, per-deal detail, pipeline totalsquick — headline numbers + top 3 action items only (fits in ~20 lines)tldr — single paragraph: one priority, one number, one actionTrigger phrases: quick brief / quick morning briefing → quick; tldr / tldr my day → tldr.
Sections (default: all on)
Set per-run with natural language ("skip yesterday's movements", "only show what needs attention") or in project instructions:
output:
sections:
pipeline_totals: true # "Pipeline at a glance"
yesterday_movements: true # won/lost since last run
meeting_today: true # deals with a meeting today (requires notetaker or calendar)
tasks_today: true # tasks/follow-ups due today
needs_action: true # slipping, stale, follow-up buckets
on_track: true # hot deals
activity_summary: true # logged calls/emails/notes count
new_this_week: false # new deals added (off by default — low urgency)
data_hygiene: true # missing fields, unowned itemsAny section with no items is automatically omitted regardless of config (don't print empty headers).
Style (default: bullets)
bullets — markdown bullets and headers (default, renders well in monday docs and chat)tables — key data in markdown tables (better for scanning many deals)prose — short paragraph per section (better for sharing / pasting into email)Trigger: morning briefing table format → tables; morning briefing prose → prose.
Destination (default: monday+chat)
monday+chat — publish artifact to monday AND mirror in chatmonday — publish to monday only, no chat mirrorchat — chat only, no monday artifact (useful for quick checks without cluttering monday)doc — force a new monday doc even if a "My Morning" pinned item existsTrigger: morning briefing chat only → chat; morning briefing doc → doc.
Config precedence: per-run prompt overrides project instructions, which overrides defaults. A per-run phrase like "quick brief" applies to this run only — it does not change stored config.
Goal: Know which monday-native data sources are live before pulling CRM data. Run in parallel with Step 2.
Try each source silently — don't stop if one fails:
get_notetaker_meetings. If it returns results, cache them. If it errors or returns empty, mark notetaker: false.calendar: false. Skip. Will be wired when monday exposes calendar_events in the MCP connector (tracked in workset status.md).email: false. Skip. Will be wired when monday exposes crm_emails in the MCP connector (tracked in workset status.md). Note: logged emails stored as item updates on contacts/deals are accessible today via get_updates — those are handled in Step 5d.get_user_context → relevantBoards for a board named tasks|to-do|actions|follow-up. If found, mark tasks_board: <boardId>. If not found, skip — tasks will be inferred from deal/contact items with date columns = today.None of these failing should block the rest of the skill. Calendar and email sync are product features not yet fully exposed in the MCP — the attempt is best-effort. Notetaker and tasks are available today.
Goal: Find the user's CRM board(s), or confirm there are none and fall back to standalone.
Broad search — cast the net wide:
boardId directly.mcp__monday__search(searchType: "BOARD", searchTerm: <arg>). One match → use it. Multiple → AskUserQuestion.get_user_context → relevantBoards + favorites for names matching any of:deal|deals|opportunity|opportunities|pipeline|salescontact|contacts|account|accounts|client|clients|customer|customerslead|leads|prospect|prospects|inboundpartner|partners|renewal|renewals|relationshipsearch with searchTerm: "crm" then "contacts" then "deals". Collect all candidates.updated_at on its items — this is the board the user is actively working in. Note the selection in the brief's Data hygiene section: "Briefing on [Board Name]. To brief a different board, pass its name as an argument."updated_at is the same day or indeterminate: AskUserQuestion with board names + "all of them" option.If the user explicitly picks "all": run Steps 3–7 per board and publish one combined α artifact.
Goal: Tailor the data pull and synthesis to what the user actually has.
After resolving the board, call get_board_info and classify as one of:
| Type | Signals |
|---|---|
pipeline | status column with is_done: true labels (Won) + numbers column with $ unit (value) |
leads | status column without is_done: true (no Won state) + lead-sounding labels (e.g. "New", "Contacted", "Qualified", "Disqualified") |
contacts | Majority text / email / phone columns; few or no numbers columns; no Won/Lost pattern |
accounts | Mix of text, numbers (revenue/ARR), status columns; company-centric item names |
general | CRM board that doesn't fit above — treat like accounts |
Cache the detected boardType for Steps 3–6.
If a user has both a pipeline board and a contacts/accounts board, run both paths and combine into one brief under separate sections.
Goal: Still produce a useful briefing even without a monday board connected.
Run this path if Step 2 found zero boards OR the user says "I don't have a CRM set up yet."
Ask the user two questions (one AskUserQuestion call, both together):
Work with whatever they provide. Produce a briefing using the Standalone template (§ Step 6c). Skip Steps 3–5 and Steps 7–9 (nothing to publish). Print the brief in chat only.
Goal: Resolve column IDs by type — global teams have non-English column titles.
get_board_info(boardId). Cache columns.Pipeline columns:
| Concept | Type | Title hint | Fallback |
|---|---|---|---|
| Stage | status | stage, status | first status with is_done labels |
| Owner | people | owner, rep, person | first people column |
| Value | numbers | value, amount, revenue, size | first numbers with $ unit |
| Close probability | numbers | probability, % | first numbers with % unit |
| Expected close date | date | close, expected, target | first date-type column matching |
| Last interaction | date | interaction, activity, touch, contacted | second date-type column |
| Forecast value | formula | forecast, weighted | optional; computed from value × prob if absent |
Contacts/accounts columns (additional):
| Concept | Type | Title hint |
|---|---|---|
| Company | text | company, account, organization |
email | ||
| Phone | phone | phone |
| Last contacted | date | last contacted, last touch, last interaction |
| Next follow-up | date | follow-up, next contact, next step |
| Owner | people | owner, rep, assigned |
| Status | status | status, stage, health |
| Tags | tags | tags, segment, type |
get_column_type_info.Goal: Distinguish closed records from active — without hardcoding English.
Skip this step for contacts, accounts, general board types.
From the stage column's settings.labels:
is_done: true.lost|closed lost|cerrado perdido|verloren|perdu.is_done: true label exists, ask the user which label means "won".Cache label index values.
Goal: Get the items needed to build the brief. Adapt the queries to the board type.
Three passes:
Pass A — Active: get_board_items_page with stage not_any_of [won_idx, lost_idx], limit 200. Pass B — Recent closures: stage any_of [won_idx, lost_idx], ordered by updated_at desc, limit 50; in-memory filter to items with updated_at within last 24h. Pass C — Recent activity: reuse Pass A; sort by updated_at desc; last 24h.
Volume edges:
board_insights fallback if >200 active items for aggregate-only view.Two passes:
Pass A — All active contacts/accounts: get_board_items_page, no status filter (include all non-archived), limit 200. Include: owner, last-contacted date, next-follow-up date, status, company.
Pass B — Recent activity: sort Pass A by updated_at desc; last 48h.
Two passes:
Pass A — Open leads: get_board_items_page, filter out terminal labels (e.g., "Disqualified", "Converted"), limit 200. Pass B — Recent additions: sort by created_at desc, last 48h.
This is the primary way to get logged emails, calls, and activities from monday CRM today. When users log a call, send an email (via monday email sync), or add a note on a contact or deal, it's stored as an update thread on that item. get_updates surfaces all of it.
For each resolved board:
get_board_activity(boardId, from: <48h ago>) — structural changes: stage moves, owner assignments, column edits. Tells you what changed on which items.get_updates(boardId, limit: 100) — update threads: logged calls, tracked emails, meeting notes, manual notes added by reps. This is the activity log.If either call returns a permission error (403 or similar): note in the brief's Data hygiene section — "Activity log unavailable — the MCP connector lacks read access to this board's activity feed. A board admin can grant it under Board Settings → Permissions → View board." Do not stop or retry; proceed without activity data.
Classify each update body by content signals:
For the contacts board specifically: this is where email/activity history lives. Pull updates for all contacts that appear in your deals or that you own — not the full board. Filter by updated_at within last 48h to stay relevant.
Cache per item: {itemId, activityType, summary (first 100 chars), timestamp, author}[]. Group by deal/contact for synthesis.
If notetaker: true from Step 1b: the cached get_notetaker_meetings results contain recent meeting recordings/notes with associated items.
For each notetaker entry:
matched_meeting_notes[] for synthesis.Unmatched meetings (no CRM item linked): surface separately in the brief under "Meetings not linked to a deal" — they're an upsell opportunity.
If tasks_board was found in Step 1b: call get_board_items_page on that board filtered by due date = today.
If no tasks board: scan Pass A results (deals/contacts) for items where any date column = today that isn't the close date (treat as a follow-up or task date).
Cache as tasks_today[] with item name, assigned owner, linked board.
Not available via monday MCP today. Skip. When monday exposes calendar_events on the connector: pull today's events, cross-reference with open deals/contacts by crm_item link or attendee domain match, cache as crm_meetings_today[] for synthesis Step 6a. See workset status.md for tracking.
Not available via monday MCP today. Skip. Logged emails stored as item updates on contacts/deals are covered by Step 5d (get_updates). When monday exposes crm_emails on the connector: pull unread emails + awaiting_reply threads, cross-reference with CRM items, surface in the brief under "Email priorities". See workset status.md for tracking.
429 → exponential backoff 3x (1s, 2s, 4s). On third failure: "monday is rate-limiting right now. Retry in 60 seconds, or narrow to fewer boards." Stop.
Goal: Rank items by what needs action today.
| Bucket | Criteria |
|---|---|
| Meeting today | deal has a crm_meetings_today entry — always surface, regardless of other signals |
| Task due today | deal appears in tasks_today — surface with task description |
| Commit-today | close_date = today AND stage ≠ Won/Lost |
| Slipping | close_date in past AND stage ≠ Won/Lost |
| Stale | last_interaction > 14d ago AND stage in non-closed |
| Follow-up | last_interaction > 7d ago AND probability ≥ 50% |
| Hot | probability ≥ 70% AND last_interaction ≤ 7d AND close_date ≤ 30d |
| New | created within last 7d AND stage = earliest-index label |
Priority order: Meeting today > Task due today > Commit-today > Slipping > Stale > Follow-up > Hot > New.
A deal can appear in multiple buckets — display in the highest-priority one only, but annotate lower-priority signals inline (e.g., a Stale deal that also has a meeting today → show under "Meeting today" with a 🔴 stale flag).
Totals: active pipeline Σ value; forecast Σ (value × prob/100); closing this week count + Σ value; yesterday wins Σ value; yesterday losses count.
Section header counts must match body item counts exactly. Count the items in each bucket after applying verbosity limits, then write ### Slipping (N) where N is the actual number of lines that follow. Never use a pre-limit count in the header.
Activity summary: count of logged calls, emails, meetings, and notes in the last 24h across all active deals. Surface as a one-liner in the brief (e.g., "5 activities logged yesterday — 2 calls, 2 emails, 1 note").
| Bucket | Criteria |
|---|---|
| Overdue follow-up | next_follow_up date in past |
| Going cold | last_contacted > 21d ago AND no upcoming follow-up |
| Follow-up today | next_follow_up = today |
| Recently active | updated_at within last 24h |
| New this week | created_at within last 7d |
Priority order: Overdue > Follow-up today > Going cold > Recently active > New.
No pipeline totals for contacts boards. Instead surface: total contacts, unowned contacts (%), contacts with no follow-up date set.
| Bucket | Criteria |
|---|---|
| Hot leads | status in early/qualified stages AND created within last 7d |
| Unassigned | owner column empty |
| Stale | created > 14d ago AND no status change in 7d |
| Recent additions | created_at within last 48h |
Surface: total open leads, unassigned count, conversion rate (if terminal labels detected).
Prioritize from user-provided input:
Goal: Put the brief inside monday. Skip for standalone mode (nothing to publish to).
Respect the destination config from Step 1:
chat → skip this step entirely; print to chat only.doc → skip "My Morning" search; go directly to create_doc.monday or monday+chat (default) → follow steps below.search(searchType: "ITEM", searchTerm: "My Morning"). Filter results to boards the user owns or is a member of (to avoid false matches on shared workspaces). If exactly one match → create_update on that item. If multiple → take the one in the user's personal workspace (from get_user_context → personal_workspace_id). If none → proceed to step 2.create_doc in personal workspace with title Morning Briefing — <weekday>, <Mon DD>, <YYYY>.— v2). Never duplicate.Before assembling the brief body, apply the config from Step 1:
pipeline_totals + needs_action (top 2 items max per bucket, 1-line each). Skip yesterday_movements, on_track, new_this_week, activity_summary, data_hygiene. Hard cap: 25 lines total including headers and footer. (~20 is achievable when fewer buckets are populated; top 2 per bucket keeps within cap even when all three action buckets are full.)| Deal | Stage | Value | Alert |) instead of bullets.If a section is configured on but has zero items, omit it silently — don't print "(none)".Pipeline template:
# CRM Morning Briefing — <weekday>, <Mon DD>
<!-- claude-skill-id: daily-briefing -->
## Pipeline at a glance
- Active pipeline: $<total>K across <N> deals
- Forecast: $<forecast>K (weighted)
- Closing this week: <N> deals, $<value>K
## Yesterday's movements
- Won: <deal> ($<value>K, <owner>)
- Lost: <deal> ($<value>K, <owner>)
## Needs you today
### Closing today (<N>)
- <deal> — <stage>, $<value>K, owner <name>, last touch <X days ago>
### Slipping (<N>)
- <deal> — <stage>, $<value>K, expected <date> (<X> days overdue), owner <name>
### Going cold (<N>)
- <deal> — <stage>, no touch in <X> days, owner <name>
### Follow-up (<N>)
- <deal> — <stage>, <probability>%, last touch <X days ago>
## On track
- <deal> — <stage>, <probability>%, closing in <X> days
## Data hygiene
- <N> deals missing owner · <N> missing close date · <N> missing amount
---
Generated by Claude · <ISO timestamp> · run `/monday-crm:daily-briefing` to refresh.Contacts / accounts template:
# CRM Morning Briefing — <weekday>, <Mon DD>
<!-- claude-skill-id: daily-briefing -->
## Relationships at a glance
- <N> contacts/accounts total · <N> owned by you · <N> unowned
## Needs you today
### Overdue follow-ups (<N>)
- <name> (<company>) — follow-up was due <date>, owner <name>
### Follow up today (<N>)
- <name> (<company>) — scheduled for today, last touched <X days ago>
### Going cold (<N>)
- <name> (<company>) — no contact in <X> days, no follow-up scheduled
## Recently active
- <name> — updated <X hours ago>
## New this week
- <name> (<company>) — added <date>
## Data hygiene
- <N> contacts missing owner · <N> with no follow-up date set
- (Run `/monday-crm:board-diagnosis` for a full audit.)
---
Generated by Claude · <ISO timestamp> · run `/monday-crm:daily-briefing` to refresh.Leads template:
# CRM Morning Briefing — <weekday>, <Mon DD>
<!-- claude-skill-id: daily-briefing -->
## Leads at a glance
- <N> open leads · <N> unassigned · <N> added this week
## Needs you today
### Unassigned leads (<N>)
- <lead name> — <stage>, added <date>
### Hot leads (<N>)
- <lead name> — <stage>, <X> days old, owner <name>
### Going stale (<N>)
- <lead name> — <stage>, no activity in <X> days
## Recent additions
- <lead name> — added <X hours ago>, source <source>
## Data hygiene
- <N> leads unassigned · <N> with no status change in 7+ days
- (Run `/monday-crm:board-diagnosis` for a full audit.)
---
Generated by Claude · <ISO timestamp> · run `/monday-crm:daily-briefing` to refresh.Standalone template (chat-only, no artifact):
# Morning Brief — <weekday>, <Mon DD>
## #1 Priority
**[Most important thing from what you told me]**
[Why it matters]
## Today's meetings
- [Time / Company / What's at stake]
## Needs attention
- [Item 1 — why]
- [Item 2 — why]
## Suggested next actions
1. [Action] — [why now]
2. [Action] — [why now]
3. [Action] — [why now]Print before any create_*: "I'll publish this as `<target>`. OK to post? (yes / no / show first)." Silent and Proactive modes skip this.
monday+chat (default): print the brief in chat as a mirror + artifact URL on last line: Posted: <url>.monday: print one-liner only: Posted: <url> — no full mirror.chat: print the full brief in chat. No artifact URL.doc: same as monday+chat.create_update → create_doc → print-only with banner "Couldn't publish to monday (permission error). Brief below."Runs only if user explicitly asked ("share with my manager", "post to the team", or Proactive mode selected Share).
list_users_and_teams → resolve recipient. Default to declared manager if present; else AskUserQuestion with top-5 linked teammates.create_notification({ userId, itemId: <artifact>, text: "Morning briefing for <Mon DD>" }).create_update on a team-rollup board (resolve by search / AskUserQuestion — don't assume a fixed name). Same footer + skill-id-comment convention.Runs only if mode = Proactive AND session decision was "approve all" or "review each".
For each item in Stale / Going cold bucket:
create_update(itemId, "*Claude nudge:* No activity in <X> days. What's the next step?").For each item in Commit-today / Overdue follow-up bucket:
create_notification({ userId: <owner>, itemId, text: "Action due today on <name>" })."Review each" flow: print a one-line proposal per item before writing. yes → execute; no → skip; stop → halt.
Guard rails:
Proactive actions — <date>) with a single prompt.Print: Published Morning Briefing — <date>. <N> items scanned, <N> actions posted, <N> pending.
If any write failed mid-run: list written items in chat for manual cleanup. Do not attempt compensating deletes.
Generated by Claude · <timestamp> footer + <!-- claude-skill-id: daily-briefing --> HTML comment.| Failure | Behavior |
|---|---|
| Connector not installed | Step 0 stops; print install link |
| No CRM board found | Standalone fallback (Step 2c) — don't stop |
| Board >10K items | Cap at 2K most-recent, flag sampling |
| MCP tool error (retryable) | Backoff 3x; skip that strand; surface partial brief |
| Same-day artifact exists | Update in place |
| User halts mid-session | List written items in chat; no compensating deletes |
| 429 rate limit | Backoff 3x, then stop with retry message |
| Publish perms failure | Degrade to doc → print-only |
| Multiple CRM boards | AskUserQuestion with "all of them" option |
| Non-English columns | Resolve by type via get_column_type_info |
| Proactive writes >20 | Batch into one review-list doc |
Generated by Claude footer + <!-- claude-skill-id: daily-briefing --> comment.~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.