From matty-tiger-skills
Daily morning briefing that syncs tasks from Asana and GitHub to Obsidian, scans yesterday's Slack for action items, and briefs on what's due today and this week. Trigger when the user runs /morning-update or says "morning update", "daily briefing", "start my day", "what's on my plate", or pastes the morning routine prompt from their daily note.
How this skill is triggered — by the user, by Claude, or both
Slash command
/matty-tiger-skills:morning-updateThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
This skill runs the daily morning briefing: sync Asana tasks and GitHub issues/PRs into
This skill runs the daily morning briefing: sync Asana tasks and GitHub issues/PRs into Obsidian, scan Slack for things that need attention, and brief on today's schedule and upcoming deadlines.
The flow is always: gather data → present sync conflicts → get approval → update Obsidian → deliver briefing. Never write to Obsidian without explicit user approval.
Before doing anything else, load two context sources:
Read 00 - System/Claude Context.md from the Obsidian vault using obsidian_get_file_contents.
This is the memory layer — it tells you who Matty is, his team, shorthand, active projects,
and preferences. Internalize it silently (don't summarize it back). This is the context-loader
skill's load mode, inlined here to avoid a separate skill invocation.
Read CLAUDE.md from the Obsidian vault root using obsidian_get_file_contents.
This contains formatting rules, folder structure, and guardrails. Pay special attention to:
Read config.json from the plugin root to get:
asana_project_id — the MKTG Content Calendar FY27 projectslack_user_id — your Slack user ID (for DM delivery if needed)slack_channels — array of channel names to scangithub_org — the GitHub organization to query for issues and PRs (e.g., "timescale")This is the most important part of the morning update. It ensures Obsidian reflects what's actually assigned in Asana.
Use asana_search_tasks to find incomplete tasks assigned to the user:
assignee_any: "me"completed: falseprojects_any: use the asana_project_id from configopt_fields: "name,due_on,completed,permalink_url"Use obsidian_get_file_contents to read 03 - Areas/Content Production.md.
Parse the task list under the ## Upcoming Content heading. Each task follows this format:
- [ ] (Type) Task Title 📅 YYYY-MM-DD
https://app.asana.com/0/...
Completed tasks look like:
- [x] (Type) Task Title 📅 YYYY-MM-DD ✅ YYYY-MM-DD
https://app.asana.com/0/...
Match Asana tasks to Obsidian tasks by comparing:
app.asana.com/0/project/task and app.asana.com/1/workspace/task/...)Build three lists:
New in Asana (not in Obsidian): Tasks that exist in Asana but have no matching entry in Content Production.md. For each, show the task name, due date, and Asana link.
Date mismatches (Asana is canonical): Tasks where the Asana due date differs from the Obsidian due date. Show both dates. Asana is the source of truth for dates — but don't auto-fix, because the user may have a reason for the discrepancy.
Completion mismatches:
Tasks marked complete in Obsidian ([x]) but still open in Asana, or tasks completed in
Asana but still open in Obsidian. Both directions matter.
Show all three lists to the user clearly. For each category, ask what to do:
Wait for the user to confirm before making any changes. They may want to handle some manually or skip certain items.
For approved changes, use obsidian_patch_content to update 03 - Areas/Content Production.md.
Critical formatting rules (from CLAUDE.md):
- [ ] (Type) Task Title 📅 YYYY-MM-DD- [x] (Type) Task Title 📅 YYYY-MM-DD ✅ YYYY-MM-DDWhen using obsidian_patch_content:
:: separator to specify the full heading path
(e.g., target="Content Production::Upcoming Content")For new tasks being added:
## Upcoming Content sectionPersonal tasks from Slack:
If the Slack scan (Step 3) surfaces action items that become tasks, and those tasks are
personal in nature (not work-related), add #personal to the task line:
- [ ] Schedule dentist appointment #personal 📅 2026-03-20
This ensures the Dashboard and daily note templates correctly categorize them.
If obsidian_patch_content fails (it can be finicky with complex edits), fall back to
providing paste-ready markdown text that the user can add manually. Don't silently fail.
This step syncs GitHub issues assigned to the user and PRs awaiting their review into
03 - Areas/GitHub.md. GitHub is the source of truth — Obsidian tracks what's on your
plate so it flows into the Dashboard alongside Asana tasks.
Use the github_org value from config. Make two API calls:
Issues assigned to you:
Use search_issues with query: assignee:@me org:{github_org} state:open
Sort by updated, order desc.
PRs awaiting your review:
Use search_pull_requests with query: review-requested:@me org:{github_org} state:open
Sort by updated, order desc.
Also query for PRs assigned to you (your own open PRs):
Use search_pull_requests with query: assignee:@me org:{github_org} state:open
Sort by updated, order desc.
From each result, extract: title, number, html_url, state, and the repo name
(parse from repository_url — it ends with repos/{owner}/{repo}). Also extract labels
if present.
Use obsidian_get_file_contents to read 03 - Areas/GitHub.md.
Parse the task lists under ## Issues and ## Review Requests. Tasks use inline links:
- [ ] Task title [#43](https://github.com/timescale/marketing-skills-issues/issues/43)
Or with an optional due date:
- [ ] Task title [#43](https://github.com/timescale/marketing-skills-issues/issues/43) 📅 2026-03-20
Completed tasks:
- [x] Task title [#43](https://github.com/timescale/marketing-skills-issues/issues/43) 📅 2026-03-20 ✅ 2026-03-22
Issues are grouped under repo-name headings (### level) within ## Issues. Review
Requests are flat under ## Review Requests and use the format
[repo-name#number](url) to identify the repo:
- [ ] Fix caching logic [timescale/tiger-den#247](https://github.com/timescale/tiger-den/pull/247)
Match GitHub items to Obsidian tasks by extracting the URL from the inline markdown
link and comparing to the html_url from the API.
Build three lists:
New in GitHub (not in Obsidian): Issues or PRs that exist in GitHub but have no matching entry in GitHub.md. For each, show the title, repo, number, and link.
Closed in GitHub (still open in Obsidian):
Items marked [ ] or [/] in Obsidian but whose GitHub state is closed. These
should be marked complete. Show each one.
In Obsidian but gone from GitHub (unassigned/transferred): Items in Obsidian that no longer appear in the GitHub search results. These may have been reassigned, transferred, or the user was removed. Flag them — don't auto-remove.
Show all three lists. For each category:
📅 YYYY-MM-DD at the end of the task
line (must be the LAST token). If they say no or skip, omit the due date.Wait for confirmation before making changes.
For approved changes, use obsidian_patch_content to update 03 - Areas/GitHub.md.
Task format — Issues (grouped by repo):
### timescale/marketing-skills-issues
- [ ] Add guard to release.yml [#43](https://github.com/timescale/marketing-skills-issues/issues/43)
- [ ] Create PR reviewer docs [#33](https://github.com/timescale/marketing-skills-issues/issues/33) 📅 2026-03-20
Task format — Review Requests (flat list):
- [ ] Fix caching logic [timescale/tiger-den#247](https://github.com/timescale/tiger-den/pull/247)
Key formatting rules:
[#number](url) or [repo#number](url) is both the display text
and the sync key — never break this format## Issues when an
issue appears in a repo not yet representedobsidian_patch_content with target="GitHub::Issues" or
target="GitHub::Review Requests" as appropriateMarking items complete:
Change - [ ] to - [x] and append ✅ YYYY-MM-DD (today's date). Keep due dates
in their original position (before the ✅).
If obsidian_patch_content fails, fall back to providing paste-ready markdown. Don't
silently fail.
Scan yesterday's messages in the configured Slack channels for anything the user needs to
act on. The channels to scan are defined in config.json under slack_channels.
Default channels:
#team-devrel-private#content-flywheel#marketing-leadership#marketing-privateUse slack_search_public_and_private with appropriate date filters (after: yesterday's
date, before: today's date) and channel filters.
Flag messages that are actionable for the user specifically:
Do NOT flag:
Group by channel. For each actionable item, show:
Keep it tight. The goal is "here's what you missed that matters" — not a transcript.
Before anything else, check Obsidian for any tasks currently marked [/] (in-progress
status from Task Genius). Use obsidian_simple_search with query [/] or scan the
Content Production and GitHub data already loaded. Surface these first — they represent
work already started and should be top of mind. Present as: "You have N tasks in progress: ..."
Check for any tasks tagged #focus in Obsidian. These are intentionally capped at 3 and
represent the user's near-term priorities. Call these out separately if present.
Use gcal_list_events to pull today's calendar. Present a clean list of meetings with
time, title, and attendees count. Skip personal blocks if they're obviously non-work
(use judgment — things like "Lunch", "Walk dogs", "Commute" can be skipped; anything
ambiguous should be included).
From the Asana data already pulled in Step 1, list tasks due today.
Also check Obsidian for any non-Asana tasks due today (including GitHub tasks with due
dates) — use obsidian_simple_search with today's date in 📅 format, or rely on the
Content Production and GitHub data already loaded.
List tasks due through the end of this week (Sunday). Group by day. Highlight anything that looks tight (due tomorrow with no draft link, multiple items due the same day, etc.).
Surface any tasks past their due date that are still incomplete. These need attention.
When presenting tasks in any of the above sections, note whether each is work or
personal. Tasks from 03 - Areas/Home.md or tagged #personal are personal;
everything else is work. A simple inline label like "(personal)" is enough — don't
over-format it.
Present everything in a single, scannable briefing. Structure it as:
[/] that are already underwayKeep the tone direct and useful — this is a morning briefing, not a report. Think "chief of staff handing you a one-pager" not "quarterly business review."
After delivering the briefing, if there are real meetings on today's calendar, ask:
"Want me to create meeting notes for today's meetings?"
If the user says yes, hand off to the meeting-notes skill. The calendar data already fetched in Step 4 can be reused — pass the events to the meeting-notes flow starting at its Step 2 (filter events). This avoids a redundant calendar API call.
If the user says no or doesn't respond, move on. This is a convenience offer, not a required step.
Obsidian MCP unavailable: Skip the task sync and Obsidian reads. Run Asana + Slack + Calendar portions and tell the user the Obsidian sync was skipped because the connector isn't available.
Asana MCP unavailable: Skip the Asana task sync and Asana-based due date sections. Run GitHub sync + Slack + Calendar + whatever Obsidian data is available. Note the gap.
GitHub MCP unavailable: Skip the GitHub sync (Step 2). Run Asana sync + Slack + Calendar + whatever Obsidian data is available. Note it. If GitHub.md already has tasks from a previous sync, those still flow into the briefing via Obsidian — just mention that the GitHub data may be stale.
Slack MCP unavailable: Skip the Slack scan. Run everything else. Note it.
Calendar MCP unavailable: Skip the calendar section. Run everything else. Note it.
No conflicts found in task sync: Great — say "Asana and Obsidian are in sync, no changes needed" and move on. Don't pad the briefing.
User says "skip sync" or "just brief me": Skip Steps 1 and 2 entirely and go straight to Slack scan + briefing.
Weekend or no meetings: Adjust the Slack scan window if it's Monday (scan Friday + weekend). If there are no meetings today, say so — don't fabricate a schedule section.
npx claudepluginhub mattstratton/skills-poc --plugin matty-tiger-skillsSyncs tasks from GitHub Issues/project trackers into TASKS.md, triages stale items, fills memory gaps for people/projects, extracts links/statuses. Use --comprehensive for deep scans of chat/email/docs.
Provides a concise briefing on current state — tasks, emails, handovers, and priorities — by reading a lazily-regenerated cache. Useful for status checks, morning reviews, or end-of-day wrap-ups.
Generates async standup notes from Git commits, Jira tickets, and Obsidian vault. Useful for remote teams wanting daily visibility without synchronous meetings.