morning-brief
Your indie hacker morning briefing — one glance, one focus, one question.

Pulls GitHub, your task list, and your reading queue into one 30-second morning brief.
BYOK Claude. Works on any machine with Node 18+.
Why
You wake up. You open GitHub. Then Linear. Then your bookmarks. Then Slack. Then your notes app. 20 minutes later you still haven't decided what to actually do today.
morning-brief pulls from every source you care about and asks Claude to write you a scannable brief:
- One-line orientation — what IS today about?
- Today's shape — compact section per source
- What demands attention first — ranked, with "why now" reasons
- What can wait — the noisy stuff that looks urgent but isn't
- One question worth sitting with — based on the signal mix
Everything is BYOK (you bring your own Claude key). Nothing gets stored or sent anywhere but Claude.
Quick start
npm install -g morning-brief
export ANTHROPIC_API_KEY=sk-ant-...
export GITHUB_TOKEN=ghp_...
export GITHUB_USER=your-username
export BURN_MCP_TOKEN=...
morning-brief --output today.md
Or skip install:
ANTHROPIC_API_KEY=sk-ant-... GITHUB_TOKEN=ghp_... GITHUB_USER=foo \
npx morning-brief
Supported sources
Work sources
github | Open PRs (yours), assigned issues, review requests | ✅ v0.1 |
tasks | Local JSON list of priorities / TODOs | ✅ v0.1 |
calendar | Today's meetings, conflicts, prep time | 🔜 v0.3 |
linear | Current sprint, assigned, blocking others | 🔜 v0.3 |
slack | Threads waiting on you, unread DMs | 🔜 v0.3 |
Reading sources (pick one — or wire multiple)
burn | 24h Flame countdown — articles about to expire, recent Vault | ✅ v0.1 |
readwise | Reader queue (later/new/shortlist) + stale-unread signal | ✅ v0.2 |
rss | Fresh items from feeds you care about (last 24h) | ✅ v0.2 |
urls | Plain text file of URLs — the zero-service fallback | ✅ v0.2 |
raindrop | Favorites + collections + highlights | 🔜 v0.3 |
karakeep | Self-hosted bookmarks + tags | 🔜 v0.3 |
pocket | RIP 2025 — use Readwise (Pocket imports land there) | ⚰️ never |
Any reading source works. Use Readwise, an RSS feed, or a plain text file — morning-brief adapts the brief to what signal the source provides. Burn brings the most (24h urgency, kept vs. burned triage), but the tool is not Burn-only.
Configuration
Two ways to configure — mix freely.
1. Env vars (quickest)
export ANTHROPIC_API_KEY=sk-ant-...
export GITHUB_TOKEN=ghp_...
export GITHUB_USER=Fisher521
export BURN_MCP_TOKEN=...
export READWISE_TOKEN=...
export MORNING_BRIEF_URLS=/path/to/reading.txt
export MORNING_BRIEF_TASKS=/path/to/tasks.json
2. brief.json (persistent, project-local)
{
"anthropic_api_key": "sk-ant-...",
"sources": {
"github": {
"enabled": true,
"token": "ghp_...",
"user": "Fisher521"
},
"burn": { "enabled": true, "token": "..." },
"readwise": { "enabled": false, "token": "...", "location": "later" },
"rss": { "enabled": false, "feeds": ["https://simonwillison.net/atom/everything/"], "hours": 24 },
"urls": { "enabled": false, "file": "./reading.txt" },
"tasks": { "enabled": true, "file": "./tasks.json" }
}
}
morning-brief looks for ./brief.json first, then ~/.morning-brief.json.
tasks.json format (any of these work)
["Ship morning-brief v0.1", "Write weekly digest post", "Refactor auth middleware"]
Or with metadata:
[
{ "title": "Ship morning-brief v0.1", "priority": "P0", "due": "2026-04-14" },
{ "title": "Write weekly digest post", "priority": "P1" },
{ "title": "Refactor auth middleware", "priority": "P2", "notes": "blocked on auth team" }
]
Or grouped:
{ "priorities": [...], "someday": [...] }
Usage
morning-brief [options]
Options:
--config=<path> | ./brief.json, then ~/.morning-brief.json | Config file |
--output=<path> | stdout | Write brief to file |
--dry-run | — | Print assembled prompt, skip LLM call |
--help | — | Show help |
Examples
Daily cron (local launchd / systemd / cron)
0 7 * * * /usr/local/bin/morning-brief --output ~/brief/$(date +\%F).md
GitHub Action — daily brief to repo
on:
schedule:
- cron: '0 12 * * *'
workflow_dispatch:
jobs:
brief:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npx morning-brief --output brief-$(date +%F).md
env:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GITHUB_USER: ${{ github.repository_owner }}
BURN_MCP_TOKEN: ${{ secrets.BURN_MCP_TOKEN }}
- run: |
git config user.name "morning-brief"
git config user.email "bot@users.noreply.github.com"
git add brief-*.md
git commit -m "brief: $(date +%F)" && git push
Pipe to Slack / email
morning-brief | slack-cli post --channel=self
morning-brief | mail -s "Morning brief" me@example.com
How it works
- Each adapter (
src/sources/<name>.mjs) fetches from one source and returns a normalized signal.
- All signals get stapled into one prompt.
- Claude writes the brief — structured, scannable, opinionated about what matters first.
No storage, no server, no account. Just env vars → API calls → markdown.
Roadmap
Contributing
PRs welcome — especially new source adapters. Each adapter:
- Lives in
src/sources/<name>.mjs
- Exports an async
collect<Name>(config) function
- Returns
{ source: '<name>', items: ..., summary: {...} } or throws
See src/sources/github.mjs for the simplest example.
About
Built by @hawking520 — exploring AI-era content & attention workflows in public.
Part of an open ecosystem:
- Burn — reading triage MCP server (26 tools)
- reading-digest — weekly digest from your bookmarks
morning-brief — this
License
MIT — see LICENSE