plugins/obsidian/skills/today/SKILL.md
Produces a prioritised daily briefing by aggregating tasks from Obsidian TaskNotes, Google Calendar, Gmail, Linear, and GitHub, then writes the result to today's daily note in the Obsidian vault. Activate when the user runs "/today", asks "what's on my plate today", "give me my daily briefing", "what do I need to do today", or "morning briefing". Works from any directory without requiring Obsidian to be running.
npx skillsauth add talent-factory/claude-plugins todayInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Collect all relevant tasks and events for today from all configured sources, rank them by urgency, and write a structured briefing to today's Obsidian daily note.
Read the following keys from ~/.claude/CLAUDE.md at skill start. Environment
variables listed under each key take precedence over the CLAUDE.md value.
| CLAUDE.md key | Env var | Default | Description |
|---|---|---|---|
| obsidian_vault | OBSIDIAN_VAULT | auto-detect via .obsidian | Absolute path to vault root |
| obsidian_daily_dir | OBSIDIAN_DAILY_DIR | Daily | Daily notes folder (relative to vault) |
| obsidian_template_daily | OBSIDIAN_TEMPLATE_DAILY | <vault>/Templates/Daily Note.md | Daily note template |
| user_email | USER_EMAIL | git config user.email | Your email address (used to detect unanswered Gmail threads) |
Vault auto-detection (applied when obsidian_vault is not set):
find "$HOME" -maxdepth 5 -name ".obsidian" -type d 2>/dev/null | head -1 | xargs dirname
Halt with a clear error message if the vault cannot be resolved.
Script locations (resolved at runtime via the plugin root):
# Note update script
SCRIPT="${CLAUDE_PLUGIN_ROOT}/skills/today/scripts/update_daily_note.py"
# TaskNotes script (same plugin)
TASKNOTES="${CLAUDE_PLUGIN_ROOT}/skills/tasknotes/scripts/tasks.py"
# Fallback: plugin cache
[ -f "$TASKNOTES" ] || TASKNOTES=$(find ~/.claude/plugins/cache/talent-factory/obsidian \
-name "tasks.py" -path "*/tasknotes/scripts/*" 2>/dev/null | sort -V | tail -1)
If TASKNOTES remains empty, fall back to the direct file scan in Step 1b.
Resolve configuration, then run steps 1–5 in parallel. Compose and write the briefing afterwards.
1a — via script (preferred):
uv run "$TASKNOTES" list --scan \
| python3 -c "
import json, sys
from datetime import date
today = date.today().isoformat()
tasks = json.load(sys.stdin)
out = []
for t in tasks:
if t.get('status') == 'done':
continue
due = (t.get('due') or '')[:10]
sched = (t.get('scheduled') or '')[:10]
status = t.get('status', '')
if due == today or sched == today:
t['_bucket'] = 'today'
elif due and due < today:
t['_bucket'] = 'overdue'
elif status == 'in-progress':
t['_bucket'] = 'in-progress'
else:
continue
out.append(t)
print(json.dumps(out, indent=2))
"
1b — direct file scan (fallback when script is unavailable):
grep -rl 'tags:.*task\|tag: task' "$VAULT" --include="*.md" -l \
| xargs python3 -c "
import sys, re
from datetime import date
from pathlib import Path
today = date.today().isoformat()
for path in sys.argv[1:]:
text = Path(path).read_text()
fm = re.search(r'^---\n(.*?)\n---', text, re.DOTALL)
if not fm: continue
block = fm.group(1)
def val(k): m = re.search(rf'^{k}:\s*(.+)', block, re.M); return m.group(1).strip() if m else ''
status = val('status')
if status == 'done': continue
due = val('due')[:10]; sched = val('scheduled')[:10]
if due == today or sched == today: bucket = 'today'
elif due and due < today: bucket = 'overdue'
elif status == 'in-progress': bucket = 'in-progress'
else: continue
print(bucket, Path(path).stem, 'due='+due, 'sched='+sched, 'prio='+val('priority'))
"
Relevant fields per task: filename (= title), priority, due, scheduled,
status, projects, _bucket.
Tool: mcp__claude_ai_Google_Calendar__list_events
Parameters:
timeMin: <today>T00:00:00
timeMax: <today>T23:59:59
maxResults: 20
Extract: summary, start.dateTime, end.dateTime, location. Compute
free time blocks ≥ 30 min within 08:00–18:00 and suggest them as focus
windows in the briefing.
Tool: mcp__claude_ai_Gmail__search_threads
Parameters:
query: "is:unread newer_than:7d -from:noreply -from:no-reply -category:promotions -category:updates"
maxResults: 15
Flag a thread as "needs reply" if the last message in the thread is not from
$USER_EMAIL. Extract: sender, subject, age.
Tool: mcp__plugin_linear_linear__list_issues
(filter: assigned to me, state not completed/cancelled)
Sort by priority: urgent → high → normal → low. Flag any issue with
dueDate ≤ today.
gh pr list --author @me --state open \
--json number,title,headRepository,updatedAt,reviewDecision 2>/dev/null
gh pr list --review-requested @me --state open \
--json number,title,headRepository,updatedAt 2>/dev/null
gh issue list --assignee @me --state open \
--json number,title,repository,labels,updatedAt 2>/dev/null
Skip silently if gh is unavailable or unauthenticated.
Assign each item a score and sort descending. Top 10 items → Priorities list; remainder → source sections.
| Score | Condition | |---|---| | 100 | Linear: Urgent | | 85 | TaskNote: overdue > 2 days, priority urgent/high | | 70 | Linear: High + due today | | 65 | TaskNote: overdue, any priority | | 55 | Linear: High | | 50 | TaskNote: due today, priority urgent/high | | 45 | GitHub PR: CHANGES_REQUESTED | | 35 | Gmail: unread > 24 h, actionable | | 30 | TaskNote: due today, priority normal | | 25 | GitHub PR: open, no review yet | | 20 | Linear: Normal | | 15 | TaskNote: scheduled today | | 10 | GitHub issue assigned | | 5 | Linear: Low |
Priority emoji by score: 🔴 ≥ 65 · 🟠 35–64 · 🟡 15–34 · ⚪ < 15
Always include deep links so every item is directly clickable:
[ID](url) — url field from the API response[Mail](https://mail.google.com/mail/u/0/#inbox/<thread_id>) — id field[[Filename without .md]] — Obsidian internal link, clickable in vault[Event name](htmlLink) — omit link for all-day/multi-day events[#N title](html_url)### :LiSun: Daily Briefing — YYYY-MM-DD
_updated: HH:MM_
#### Calendar
- HH:MM [**Event**](calendar-url) (Xm) — Location
- *(no events)* if empty
**Free blocks:** HH:MM–HH:MM (Xh), HH:MM–HH:MM (Yh)
#### Priorities
1. 🔴 [Linear] **[ABC-17 Title](https://linear.app/...)** — URGENT
2. 🟠 [Task] **[[TaskNote Filename]]** — 3 days overdue
3. 🟡 [GitHub] **[PR #N Title](github-url)** (repo) — awaiting review
...
#### Emails
- **Sender**: [Subject](https://mail.google.com/mail/u/0/#inbox/thread-id) (age)
*(omit section if empty)*
#### GitHub
- [PR #N **Title**](github-url) (repo) — status
*(omit section if empty)*
Source labels: [Task] [Linear] [GitHub] [Mail]
python3 "$SCRIPT" \
"$(date +%Y-%m-%d)" \
"<briefing markdown>" \
--vault "$VAULT" \
--daily-dir "$DAILY_DIR" \
--template "$DAILY_TEMPLATE"
The script creates the note from template if it does not yet exist (substituting
{{yesterday}} / {{tomorrow}}), inserts the briefing after
> ![[tasks-default.base]] on first run, and replaces the existing
### :LiSun: Daily Briefing block on subsequent runs.
After writing, output only the following (not the full briefing):
✓ Briefing → Daily/2026-05-08.md
📅 3 events | free blocks: 10:30–14:00 (3.5h)
🔴 2 urgent 🟠 4 due today 🟡 3 watch
📧 2 emails · GitHub: 1 PR, 2 issues
references/priority-guide.md — Extended priority rules, edge cases, and tuning guidancescripts/update_daily_note.py — Note create/update script (configurable via CLI flags)documentation
Creates comprehensive handoff documentation before a /compact operation, enabling a new agent with fresh context to seamlessly continue the work. Activate when the user says "prepare a handoff", "document before compact", "context is getting too large", "I need to hand this off", "create a handoff document", "end of session notes", or "document the current state for tomorrow". Supports --output and --linear-issue options.
documentation
Collects completed tasks, GitHub activity, calendar meetings, wiki learnings, and Linear progress for the past week, then writes a structured retrospective to the Obsidian vault. Activate when the user runs "/weekly-review", asks "what did I accomplish this week", "weekly retrospective", "summarise my week", or "prepare weekly review". Works from any directory.
tools
Provides a quick status snapshot of all GitHub repositories in a configured organisation — active, dormant, stalled — plus open pull requests and issues. Terminal output only, optimised for speed. Activate when the user runs "/project-pulse", asks "what is the status of my GitHub projects", "show me my repos", "which projects are active", "project overview", "GitHub pulse", or "what is happening in [org]". Works from any directory.
development
Surfaces new product, feature, and business ideas by cross-referencing the user's knowledge wiki, GitHub repositories, customer or project notes, and current market trends. Writes a structured ideas document to the Obsidian vault. Activate when the user runs "/ideas", asks "what could I build next", "give me new project ideas", "what opportunities am I missing", "brainstorm project ideas", or "what should I work on strategically".