morning-brief
v0.2.0
Published
Your indie hacker morning briefing — synthesize GitHub, tasks, reading, and more into one daily report. Works with any source, BYOK Claude.
Downloads
231
Maintainers
Readme
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
# 1. Install
npm install -g morning-brief
# 2. Set your Claude API key
export ANTHROPIC_API_KEY=sk-ant-... # https://console.anthropic.com/settings/keys
# 3. Plug in sources via env vars (or brief.json, see below)
export GITHUB_TOKEN=ghp_... # https://github.com/settings/tokens
export GITHUB_USER=your-username
export BURN_MCP_TOKEN=... # from burn451.cloud → Settings → MCP Server
# 4. Brief me
morning-brief --output today.mdOr skip install:
ANTHROPIC_API_KEY=sk-ant-... GITHUB_TOKEN=ghp_... GITHUB_USER=foo \
npx morning-briefSupported sources
Work sources
| Source | What it shows | Status |
|---|---|---|
| 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)
| Source | What it shows | Status |
|---|---|---|
| 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
# Pick one reading source:
export BURN_MCP_TOKEN=... # burn451.cloud → Settings → MCP
export READWISE_TOKEN=... # readwise.io/access_token
export MORNING_BRIEF_URLS=/path/to/reading.txt # or plain text file
# Optional:
export MORNING_BRIEF_TASKS=/path/to/tasks.json2. 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:
| Flag | Default | Description |
|---|---|---|
| --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)
# crontab -e
0 7 * * * /usr/local/bin/morning-brief --output ~/brief/$(date +\%F).mdGitHub Action — daily brief to repo
# .github/workflows/morning-brief.yml
on:
schedule:
- cron: '0 12 * * *' # 7am EST
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 "[email protected]"
git add brief-*.md
git commit -m "brief: $(date +%F)" && git pushPipe to Slack / email
morning-brief | slack-cli post --channel=self
morning-brief | mail -s "Morning brief" [email protected]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
- [x] v0.1 — GitHub + Burn + tasks adapters, Claude synthesis
- [x] v0.2 — Readwise + RSS + urls-file reading sources (pluralize reading)
- [ ] v0.3 — Calendar (Google/iCal), Linear, Slack, Raindrop, Karakeep
- [ ] v0.4 — Output formats: HTML email, TTS podcast, Telegram push
- [ ] v0.5 — MCP server wrapper:
morning-briefbecomes a tool Claude/Cursor can call on demand
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
