ai/skills/morning-focus/SKILL.md
Pull together the signals that should shape my day — PRs, reviews, issues, Slack, calendar, Shopify internal Vault projects, and messages from others, especially my manager — then recommend a priority focus list. Run via `/morning-focus`.
npx skillsauth add juharris/configs morning-focusInstall 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.
Produce a concise morning briefing that tells Justin Harris (GitHub alias: juharris) what to focus on today. Gather signals from GitHub, Slack, Google Calendar, and Shopify internal Vault in parallel, then synthesize them into clear sections followed by a top-3 focus list.
Run all of the following in one tool-call batch:
date +%Y-%m-%d — today's date.date -v-3d +%Y-%m-%dT%H:%M:%S%z — 3-day lookback cutoff (macOS).Fire all of these in one batch. Do not serialize them.
Important: gh search prs and gh pr view expose different --json fields. If a query errors with "Unknown JSON field", run the same command with an invalid field (e.g. --json _) to get the current list of valid fields, then retry. Do not hardcode field lists from memory. In particular, review decision and CI status are typically only available on gh pr view <number> --repo <owner/repo>, so follow up per-PR on the 1–3 most interesting open PRs (usually your most recent non-draft PR awaiting review).
gh search prs --author @me --state open --json repository,title,url,number,createdAt,updatedAt,isDraft,commentsCount --limit 50gh search prs --assignee @me --state open --json repository,title,url,number,author,createdAt,updatedAt,isDraft,commentsCount --limit 50
Merge these with the authored list under "PRs — mine", deduping by url. Drafts are kept here (they're still yours to drive).
For each non-draft PR in this merged list, fetch the real state so you know what action is actually needed:
gh pr view <number> --repo <owner/repo> --json reviewDecision,statusCheckRollup,mergeable,latestReviews
Use the raw state to decide what to say — do NOT invent fixed tags. Phrase the bullet around the concrete next action the state implies:
reviewDecision == "APPROVED" + CI green + mergeable == "MERGEABLE" → the PR is ready to land. Say so plainly and surface it; this often belongs in the top 3.reviewDecision == "CHANGES_REQUESTED" → name the reviewer whose feedback is outstanding so Justin knows whose concerns to address.statusCheckRollup → name the failing check(s) so Justin can go straight to them.gh search prs --review-requested @me --state open --draft=false --json repository,title,url,number,author,createdAt,updatedAt --limit 50 -- '-reviewed-by:@me'
Why the -reviewed-by:@me negation matters: --review-requested @me alone returns every PR where Justin is on the reviewer list, and GitHub does NOT remove him from that list after he approves. Adding -reviewed-by:@me filters out PRs he's already reviewed in any state (APPROVED / COMMENTED / CHANGES_REQUESTED).
Syntax: all gh flags (including --json, --limit) must come BEFORE the -- separator. The -- ends flag parsing, and the quoted '-reviewed-by:@me' is passed through as a raw GitHub search qualifier. If you put --json after --, it's treated as a literal query string and you'll get tabular output instead of JSON.
These PRs are safe to list under "PRs — awaiting my review" with no further filtering — by construction, the ball is with Justin.gh search prs --reviewed-by @me --state open --draft=false --updated ">=$DATE_3D" --json repository,title,url,number,author,updatedAt --limit 50
The search layer cannot tell whether the author pushed new commits after Justin's last review, so per-PR follow-up is required:
gh pr view <number> --repo <owner/repo> --json reviewDecision,latestReviews,commits
Then include the PR under "PRs — awaiting my review" ONLY if ALL of these hold:
reviewDecision != "APPROVED" (if it's APPROVED the PR is green — nobody is blocked).latestReviews where author.login == "juharris") has state of COMMENTED or CHANGES_REQUESTED — not APPROVED.committedDate (from commits[-1]) is LATER than Justin's review submittedAt — i.e. the author has actually pushed something since his feedback.
If any condition fails, drop it. Note that GitHub does not invalidate an existing approval when the author pushes new commits (unless the repo enforces it), so a later commit after an APPROVED review is still not blocking Justin.gh search issues --assignee @me --state open --json repository,title,url,number,updatedAt --limit 50gh search issues --repo shop/issues-sidekick --mentions @me --state open --updated ">=$DATE_3D" --json title,url,number,updatedAt --limit 30count: 50 or lower — higher counts can exceed the token limit; if the response reports truncation with a file path, read that file in chunks rather than retrying with the same count.from:@manager.handle after:YYYY-MM-DD (plain date, no time). Do NOT combine from: and to: in the same query — Slack search returns no results for that pattern; instead rely on from:@manager then filter to threads that mention Justin or are in DMs with him. If the manager's Slack handle isn't available, search Slack users by the manager's name to find it.Cross-reference the raw data to find what actually needs attention. An item is "unaddressed" when:
Skip items where Justin has clearly already responded or where the thread has since concluded.
Output in this exact structure. Use GitHub-flavored markdown. No emojis unless Justin's tone elsewhere uses them.
# Morning focus — <YYYY-MM-DD>
## Top 3
1. **<Title>** — <one-line reasoning: who's blocked, what's stale, why it matters>. <link>
2. ...
3. ...
## Calendar today
- <HH:MM–HH:MM> <title> — <note if prep needed or if it eats a focus block>
- ...
## PRs — mine
- <status emoji-free tag like [stale 3d]> <title> (<repo>#<number>) — <what's needed from me>
- ...
## PRs — awaiting my review
- <age> <title> (<repo>#<number>) by <author> — <why it matters>
- ...
## Issues
- <title> (<repo>#<number>) — <next action>
- ...
## Slack — unaddressed
- **<channel or DM>** — <one-line summary of what's unanswered> (from <person>, <age>)
- ...
## From <manager name>
- <one-line summary> (<age>, <link or channel>)
- ... (omit this section entirely if nothing)
## Active Vault projects
- <project title> — <current phase/status, recent activity note>
- ...
- … and N more line.<Nd> for days, <Nh> for hours. Use the most recent activity time, not creation time.[text](url) markdown link style so the output is clickable in IDE and terminal.https://app.graphite.com/github/pr/<owner>/<repo>/<number>. This applies to every PR reference in the briefing — "PRs — mine", "PRs — awaiting my review", and any PR mentioned inline in top-3 reasoning or Slack context. Use github.com links only for issues and non-PR references.After the briefing, ask Justin one short question: whether he wants to dive into item #1, see more context on a specific item, or dismiss the briefing. Do not auto-start any follow-up work.
business
Summarize work done in the last week from authored pull requests, Slack activity, and calendar meetings.
documentation
Review pull requests using personal guidelines
databases
Gather evidence of interactions with a peer and draft structured peer feedback with ratings and written responses.
development
Use this skill when sending or drafting messages on behalf of the user via Slack, other messaging platforms, or making social posts. Covers AI disclosure, tone, and formatting guidelines. Also covers GitHub PR commenting etiquette.