This is a new Tuesday series where I share the small tools I build for myself, with the actual instructions you need to set them up. You don’t need to know how to code. You need to be able to copy and paste. First up: a daily personal newspaper that publishes itself at 6am, costs a few cents a day, and lives at a URL you bookmark on your phone.
Like most founders, I subscribe to about a hundred Substacks (okay, maybe twenty). I have at least three podcasts on rotation that I want to listen to and never do. I have set news alerts for my industry. And most mornings used to start the same way. Coffee. Scrolling my mailbox for news. Checking what’s happening on Twitter. Feeling overwhelmed and shutting my phone.
The result? In almost every founder meetup or dinner I was the last person who knew what was happening in the world of tech.
So one day I decided to use Claude to my advantage.
I built a morning brief agent that runs at 6am Pacific every day. It reads news from a list of topics I care about, scans five founder-heavy subreddits and Twitter, opens the newsletters that landed in my Gmail in the last 24 hours, and checks for new podcast episodes from a curated list of shows. It assembles all of that into a single beautifully designed webpage, with framed paintings from the Art Institute of Chicago laid between the sections, and publishes it to a private URL I’ve bookmarked on my phone. No email. No app. No notification. Just a bookmark I open with my coffee.
The whole thing costs about a nickel a day in Claude usage. The hosting is free. The setup, if you follow this post, takes about thirty minutes.
Here it is. Steal it.
A Note Before We Start
I built this using Claude Code. If you've never used it, here are the install tutorials. PS you need the Pro plan.
You don’t need to learn to code. Claude Code understands plain English. You’ll see grey boxes throughout this post. You don’t read or edit them. You paste them into Claude Code when I tell you to, and Claude Code does the rest.
You also don’t have to use every section. There are five (news, social, substack, podcasts, and art). Pick what you want during the setup step below. The post will tell you to skip the agents you didn’t pick.
The rest of this post assumes you have Claude Code running.
The Move That Actually Matters
I’ve vibe coded over twenty projects, some for me and some for my clients, so trust me when I say this. Ideate before you build. The order matters more than the prompts.
I did not start in Claude Code. I started in Claude Design. Before I wrote a single instruction for an agent, I designed what the finished brief would look like. The layout, the typography, the framed art, the section order. Once I knew what I was building toward, the agents almost wrote themselves, because I had a template with empty slots and I just needed to fill them.
You should do the same. Skip the ideation step (this post is the ideation, the sources and sections and order are already decided). But the design is yours. Open Claude Design and paste this:
I'm building a daily morning brief that will live on a webpage I bookmark on my phone. It pulls from a few sources I care about. [ADD WHAT YOU ACTUALLY CARE ABOUT] Design what this should look like. I want it to feel like a [ADD WHAT YOU WANT IT TO LOOK AND FEEL LIKE]. Each section should feel distinct. Ask me thoughtful questions before you start designing. Show me a draft I can iterate on. Then ask me what I want to change.The first version will be rough. Iterate. Change the colors. Move the art. Make the headlines bigger. Try a serif. Try a sans. I spent an hour just getting the gold frames around the paintings to look like real frames instead of yellow rectangles. It matters more than you think. This is the thing you’ll open every morning.
When you like the design, save the HTML. You’ll hand it to Claude Code in the next step.
How The Thing Is Organized
In Claude Code, you can create something called a skill. It’s a folder of instructions Claude Code reads whenever you ask it to do a particular kind of task. Think of a skill as a job description you write once and Claude Code refers to every time.
The morning brief skill is one folder with a handful of files inside it. A main instruction file (the orchestrator, which is the manager), a config file with your preferences, sub-agent files (one per section you chose), and the template file you just designed. The folder lives at ~/.claude/skills/, inside a subfolder you'll name during the next step. The squiggle (~) is shorthand for your computer’s main user folder.
You’re not going to build this folder yourself. Claude Code will, in the next step.
Make It Yours
This is the most important step. We're going to do the personalization and the setup in one go. By the end, you'll have your folders, your config file, your template, and an orchestrator built around exactly the sections you want.
Tell Claude Code:
I want to build a daily morning brief. Interview me to set it up.
Step 1 — Understand what I actually need
Before asking about sections or topics, ask me these four questions (one at a time, wait for each answer before continuing):
1. What problem does this brief solve for you? What would you do differently if you had better information each morning?
2. What's something you wish you'd known 3 months ago — a story, a shift, a number — that you only found out too late?
3. What's one space adjacent to your work that you're curious about but don't currently follow?
4. When you think about the content you currently read, what feels like noise — topics that show up but you always skip?
Use my answers to build a picture of what I actually need signal on. You'll use this to suggest topics in Step 3.
Step 2 — Choose sections
Ask me which sections I want:
- News — Google News on topics I follow
- Social — Reddit and Twitter/X
- Substack — newsletters in my Gmail
- Podcasts — new episodes from shows I follow
- Art — a daily painting curator from the Art Institute of Chicago (this is handled automatically in the orchestrator — no setup needed from me)
Step 3 — Interview me on each section I chose
For News: Based on my answers in Step 1, suggest 8–10 specific topic strings I could track — not generic labels like "entrepreneurship" but precise search
phrases like "founder case study", "frontier AI startup adoption", "creator economy solo founder". Walk me through each suggestion and explain why you're
recommending it based on what I told you. Let me accept, reject, or modify each one. Also ask: how many articles per day (default 6), and max age in hours
(default 24).
For Social: Ask which subreddits I want. Suggest 4–6 based on my topics — include at least one that isn't the obvious choice. For Twitter/X: ask if there are
specific accounts I want to track. If I don't have names, suggest 4–5 handles relevant to my topic mix and explain who they are. Save confirmed handles as a
twitter_handles array in config. Ask for max threads (default 5).
For Substack: Ask if I've connected the Gmail MCP connector in Claude settings. If I haven't, walk me through it: open Claude settings → Connectors → Gmail →
authorize. Wait for confirmation. Ask for my Gmail address and whether there are any senders I want to skip (promotional Substack emails, digest roundups,
etc.).
For Podcasts: Ask me for show names. Look up the RSS feed URL for each show on the web and save it alongside the show name. If you can't find an RSS feed, tell
me and skip it. Do not invent URLs. Ask for max age in hours (default 48).
Step 4 — GitHub and timezone
Ask for my GitHub username and timezone.
Step 5 — HTML template
Ask me to paste the HTML template I designed. Save it as templates/template.html.
Step 6 — Create the skill
Ask what to name the skill folder. Validate: no spaces, no slashes, letters/numbers/hyphens/underscores only. If ~/.claude/skills/{name}/ already exists, tell
me and ask whether to pick a different name or overwrite.
Create the folder at ~/.claude/skills/{name}/ with three subfolders: agents/, staging/, templates/. Save my HTML at templates/template.html.
Step 7 — Write config.json
Write config.json in the skill root with this shape:
{
"schedule": { "time": "07:00", "timezone": "America/New_York" },
"delivery": {
"github_pages_url": "https://{username}.github.io/morning-brief/",
"github_repo": "{username}/morning-brief",
"github_pat_file": "~/.config/morning-brief/github-pat"
},
"topics": ["...confirmed topic strings..."],
"news": { "articles_per_run": 6, "max_age_hours": 24 },
"social": {
"platforms": ["reddit", "twitter"],
"subreddits": ["..."],
"twitter_handles": ["..."],
"max_threads": 5
},
"substack": {
"gmail_account": "...",
"max_age_hours": 24,
"skip_senders": ["reaction@mg1.substack.com", "forum@mg1.substack.com", "no-reply@substack.com"]
},
"podcasts": {
"feeds": [{ "name": "Show Name", "url": "https://..." }],
"max_age_hours": 48
},
"learnings": {
"articles_path": "~/notes/learnings/articles/",
"podcasts_path": "~/notes/learnings/podcasts/"
}
}
Step 8 — Write SKILL.md
Write SKILL.md in the skill root. It is the orchestrator that runs daily. It must do the following in order:
1. Read config.json and today's date in four formats: display (Monday, May 12, 2026), uppercase display, filename (2026-05-12), issue number (No. 12 for the
12th).
2. Read the instruction files for each chosen agent, then spawn all of them simultaneously as parallel sub-agents. Each agent writes its output to
./staging/{name}.json. The agents are:
- agents/news-agent.md → staging/news.json
- agents/social-agent.md → staging/social.json
- agents/substack-agent.md → staging/substack.json
- agents/podcast-agent.md → staging/podcast.json
3. Art curation (handled directly in the orchestrator — no separate agent):
- Read staging/art-state.json for seen_ids and rotation history
- Pick today's search term by day-of-month using a 13-term rotation: impressionism, post-impressionism, realism, american scene painting, modernism, landscape
painting, portrait, still life, romanticism, baroque painting, genre painting, expressionism, urban scene
- Fetch from AIC API: https://api.artic.edu/api/v1/artworks/search?q={term}&fields=id,title,artist_display,date_display,medium_display,image_id,description,st
yle_titles,subject_titles&limit=50&query[term][is_public_domain]=true
- Filter: image_id must be present and not in seen_ids. Pick 4.
- For each, write 2–3 sentences grounded only in API data (style_titles, subject_titles, medium_display, description). Do not invent biographical details.
- Build image URLs: https://www.artic.edu/iiif/2/{image_id}/full/1600,/0/default.jpg
- Update art-state.json: append today's 4 ids to seen_ids, trim to 120, update history.
4. Read all four staging JSON files.
5. Read templates/template.html. Replace every <!-- INJECT:NAME --> marker with the appropriate content. Never leave any marker unreplaced in the output. Key
injections:
- INJECT:DATE, INJECT:DATE_UPPER, INJECT:ISSUE_NUMBER, INJECT:TALLY
- INJECT:COVER_HEADLINE — 6–10 word editorial headline across today's themes
- INJECT:COVER_STAND — 2–3 sentence framing of today's edition, under 45 words
- News section: use articles[0] from news.json as the lead; articles[1…N] as grid cards
- Art: inject 4 artwork URLs, titles, artists, dates, mediums, and curator notes
- Social: sentiment, pullquote (not pull_quote), and threads (not items) from social.json
- Substack: newsletters array from substack.json
- Podcast section: inject only if has_episodes is true in podcast.json; omit entirely if false
- INJECT:COLOPHON_TALLY, INJECT:COLOPHON_ART, INJECT:YEAR
6. Write assembled HTML to staging/morning-brief-YYYY-MM-DD.html. Verify no <!-- INJECT:... --> markers remain before writing.
7. Push to GitHub Pages via the Contents API (GET the SHA first, then PUT). Also push to archive/YYYY-MM-DD.html. If the PAT file is missing or the API errors,
log and continue — do not abort.
8. Save learnings: write one markdown file per run to learnings.articles_path and (if episodes exist) learnings.podcasts_path.
9. Print a completion summary: date, live URL, article/newsletter/episode counts, learnings path.
Add this rule at the end of SKILL.md: If any agent fails, omit that section from the template and continue. Do not block the brief on one bad fetch.
Step 9 — Show me what we built
Print the full folder structure so I can see everything that was created.Claude Code will ask the questions one by one. Answer in plain English. By the end, your folders exist, your config file is written, your template is in place, and your orchestrator is built around exactly the agents you want. If you said you don’t care about podcasts, there’s no podcast agent in your orchestrator. If you only want news and art, that’s all your orchestrator runs.
Don’t worry about the format Claude Code uses to show you the folders. It’ll look like a little tree of file names. If the folders you expected are in there, you’re good.
The failure-handling line at the end is doing more work than it looks. The first version of this whole system would crash whenever Reddit was slow to respond, which was often. Now if any one source breaks, the brief just ships without that section. An imperfect brief at 6am beats a perfect brief at noon.
This is the only part of the build where you’re talking about yourself instead of pasting. The whole brief reads to you, not to me. So this step is the one that matters most.
The News Agent
Skip this if you didn’t pick it during the interview.
This one handles news. It reads Google News for the topics in your config, picks the most relevant ones for a solo founder, writes a short summary of each, and adds two things I find more useful than the summaries themselves. The first is Claude’s Take, one sharp sentence on what the article actually signals, not just what it says. The second is a content angle, a specific post idea the article suggests, so I can grab it later when I’m staring at a blank Substack draft.
Tell Claude Code:
Create a file inside the agents folder, named news-agent.md, with the following contents:
You are the News agent for the Morning Brief.
1. Fetch the Google News RSS feed for each topic listed in
config.json under "news_topics". Construct URLs like:
https://news.google.com/rss/search?q={topic}&hl=en-US
2. Dedupe across feeds by URL and by title similarity.
3. For each remaining article, score it 1-5 on relevance to
"a solo founder building a B2B or prosumer product." 5
means must-read. 1 means skip.
4. Keep only articles scored 4 or 5. From those, pick ONE lead
(highest score, breaks ties by recency) and up to 4 secondaries.
5. For each kept article, write:
- title (rewrite for clarity; do not parrot SEO headlines)
- summary (2-3 sentences, what happened and why)
- claude_take (ONE sentence. What does this actually signal,
not what does it say. Sharp. No hedging.)
- content_angle (ONE sentence. A specific Substack or
LinkedIn post premise this article suggests for a solo
founder to write.)
- source, url, published_at
6. Write the result to ./staging/news.json with this shape:
{ "lead": {...}, "secondary": [...] }
Do not include articles you scored below 4. A short brief is
better than a padded one.The Claude's Take field is what makes this read like a real publication instead of a feed reader. Anyone can summarize an article. Naming the signal underneath is the editorial muscle. That one sentence is the reason I read the brief instead of just looking at headlines.
The Social Agent
Skip this if you didn’t pick it during the interview.
This one handles Reddit and Twitter. It pulls the threads doing well in your subreddits (above a minimum threshold of upvotes and comments, so dead threads get skipped) and the highest-signal tweets from the accounts you follow. For each one, it writes a short take on the community mood and what it means, not on what the thread is about. It produces a sentiment breakdown (a quick read on whether the founder internet feels positive, neutral, or negative today), and it pulls one sharp anonymous quote as a daily pull quote.
Tell Claude Code:
Create a file inside the agents folder, named social-agent.md, with the following contents:
You are the Social agent for the Morning Brief.
1. For each subreddit in config.json under "subreddits", fetch
the top posts from the last 24 hours via:
https://www.reddit.com/r/{name}/top.json?t=day&limit=15
Filter to threads with score >= 50 or comments >= 25.
2. For each Twitter handle listed in config.json under
"twitter_handles", fetch the user's recent tweets (last 24
hours) using the Twitter MCP connector if available. If no
connector is set up, fall back to scraping the public
profile via nitter.net or similar mirror. Filter to tweets
with likes >= 100 OR retweets >= 25 OR replies >= 20.
3. For each remaining Reddit thread, read the post and top 5
comments. For each remaining tweet, read the tweet and top
replies. Then write:
- title (use the original)
- source ("reddit/r/{name}" or "twitter/@{handle}")
- signal (2-3 sentences. NOT what the thread is about. What
the community mood is, and what that mood means for a
solo founder paying attention.)
- url, score, comments
4. Across all items kept, produce a single sentiment object:
{ "positive": int, "neutral": int, "negative": int }
The three values must sum to 100. Base this on overall
tone for the day, not any one thread.
5. Pick ONE pull quote from the day's items. A real comment
or tweet, no more than 30 words, attributed by username.
Choose for sharpness, not popularity.
6. Write to ./staging/social.json:
{ "sentiment": {...}, "pull_quote": {...}, "items": [...] }
If no items cleared the filters on either source, write
{ "has_content": false } and stop.The pull quote is my favorite feature. One sharp anonymous voice every morning, sitting under the sentiment bar. It's the thing that makes the brief feel like a person put it together instead of an algorithm.
The Substack Agent
Skip this if you didn’t pick it during the interview.
This one reads your actual Gmail. It uses an MCP connector, which is a permission slip you give Claude to talk to another app on your behalf. You’ll connect Gmail once in your Claude settings, and after that this agent can read newsletters that landed overnight. It writes a short summary of each, pulls out the most useful idea, and suggests a content angle in case you want to write a response later.
Tell Claude Code:
Create a file inside the agents folder, named substack-agent.md, with the following contents:
You are the Substack agent for the Morning Brief.
1. Use the Gmail MCP connector to search for emails received in
the last 24 hours from senders listed in config.json under
"newsletter_senders".
2. For each email, extract the article body (strip the email
chrome, footers, unsubscribe links). Get the canonical URL
from the email if present.
3. For each newsletter, write:
- title (the post title, not the email subject if different)
- author (sender name, cleaned)
- summary (3-4 sentences. What the piece argues. Not "the
author talks about." What they actually claim.)
- key_insight (ONE sentence. The single most useful idea
for a solo founder, stated as a takeaway not a quote.)
- content_angle (ONE sentence. A response, counterpoint, or
extension a solo founder could write this week.)
- url, received_at
4. Write to ./staging/substack.json as a list. If nothing came
in overnight, write [] and stop. An empty Substack section
is fine. A fake one is not.The Podcast Agent
Skip this if you didn’t pick it during the interview.
This one checks for new podcast episodes in the last three days from a list of shows in your config. It only keeps episodes that are actually relevant, and for those, it writes a short summary plus a few timestamped key moments so you know what to skip to. If nothing new and good came out, the whole podcast section gets omitted from the brief that day.
Tell Claude Code:
Create a file inside the agents folder, named podcast-agent.md, with the following contents:
You are the Podcast agent for the Morning Brief.
1. For each show listed in config.json under "podcasts", search
for episodes published in the last 72 hours. Use the show's
RSS feed URL from the config.
2. For each new episode, score 1-5 on relevance to a solo
founder building a B2B or prosumer product. Keep only
episodes scored 4 or 5.
3. For each kept episode, write:
- title, show, host, duration, published_at, audio_url
- summary (3 sentences. What the episode is actually about,
not the marketing description.)
- key_moments: a list of up to 3 objects, each:
{ "timestamp": "HH:MM:SS", "note": "what's said here" }
4. Write to ./staging/podcast.json:
{ "has_episodes": true, "episodes": [...] }
If no episodes cleared the bar, write:
{ "has_episodes": false }
The orchestrator will omit the Podcast section entirely
when has_episodes is false. Do not pad.The podcast agent reads RSS feed URLs from your config. The interview step already looked these up for you when you named your shows, so you shouldn't have to do anything here. If a podcast section never shows up and you think it should, the RSS URL is probably the thing to check first.
The Art Curator
Skip this if you didn't pick it during the interview. If you change your mind later, paste the prompt below and ask Claude Code to add the curator to your orchestrator.
This is the part I’m proudest of, and it’s what turns the brief from a dashboard into something that feels like a magazine.
Every edition includes four paintings from the Art Institute of Chicago’s collection. The AIC has a free public image service (no account, no key) that serves high-resolution versions of everything they own. About a hundred thousand works.
The curator is a sub-agent. Every morning it picks one art movement from a rotating list of thirteen (impressionism, post-impressionism, baroque, urban scene, surrealism, and so on), searches the AIC for that movement, filters out anything that’s appeared in the last thirty days, and selects four fresh paintings. The next day, a different movement. By day fourteen it’s cycled through all thirteen and starts over, but with completely different paintings, because the previous set is still on the recently-seen list. Nothing repeats within a month.
For each painting, the curator writes a short story in a specific voice. The factual base comes from the AIC’s own metadata (style, museum description, medium, year). The curator can only assert things the data supports. No invented biographies, no fake anecdotes. The story is short, in second person, with a little bite.
Tell Claude Code:
Create a file inside the agents folder, named art-curator.md, with the following contents:
You are the Art Curator for the Morning Brief.
Your job is to pick 4 fresh paintings from the Art Institute
of Chicago's public collection every day, and write a short
story for each in the voice described below.
1. Read ./staging/art-state.json. It contains:
- "seen_ids": AIC artwork IDs that have appeared in the
brief in the last 30 days
- "movement_rotation": a 13-item list of art movements
["impressionism", "post-impressionism", "baroque",
"urban scene", "surrealism", "japanese woodblock",
"american modernism", "cubism", "fauvism",
"abstract expressionism", "renaissance", "romanticism",
"realism"]
- "rotation_index": integer 0-12, wraps around
2. Pick today's movement using rotation_index. Search the AIC
API:
https://api.artic.edu/api/v1/artworks/search
?q={movement}
&fields=id,title,artist_display,style_titles,
description,medium_display,date_display,image_id
&limit=50
3. Filter out:
- Any artwork whose id appears in seen_ids
- Any without an image_id
- Any without an artist_display
4. From the remaining candidates, select 4. Prioritize
variety (no two works by the same artist) and recognizable
quality (works with a museum description tend to be the
majors).
5. For each painting, write:
- image_id (use directly from the API)
- title (use the API's title)
- artist (just the name, no dates)
- year (from date_display)
- story: 2-4 sentences, second person, with bite. Use
style_titles, description, and medium_display as the
factual base. ONLY assert what the API data supports.
Do not invent biographical details, prices, or anecdotes.
6. Write the result to ./staging/art.json as a list of 4
objects.
7. Update ./staging/art-state.json:
- Append today's 4 ids to seen_ids
- Drop any ids older than 30 editions
- Increment rotation_index by 1, wrapping at 13
If the API errors or fewer than 4 candidates clear the filter,
write { "fallback": true } and stop.The line about not inventing biographies is the one I rewrote the most. The curator is good at writing in voice. It’s a little too good at inventing context to fit the voice. The first version once told me, confidently, that a 17th-century Dutch painter had been disowned by his family. He had not. He had simply painted a lot of taverns.
So now the stories are quieter sometimes. But they’re true.
Publishing It
Now for the last step. You need three things to happen: your brief has to live on the internet somewhere, it has to run automatically every morning, and you have to know the URL to bookmark.
All three happen in one prompt. Claude Code will walk you through the parts you have to click yourself, wait for you to confirm each one, verify it worked, schedule the brief to run at the time you want, and give you the URL at the end.
Tell Claude Code:
I'm ready to ship my morning brief. Walk me through this one step at a time. Wait for me to confirm each step is done before moving to the next, and verify the result whenever you can. First, help me set up GitHub Pages. Tell me how to create a free GitHub account (if I don't have one), how to make a new public repository called morning-brief, how to turn on GitHub Pages in the repo settings, and how to generate a personal access token with the right permissions. After each click step, ask me to confirm. After I confirm the token, save it to my config.json. Then verify the GitHub repo and Pages are set up correctly by checking the URL. Second, ask me what time I want the brief to run and which timezone I'm in. Convert that into the right cron schedule for UTC and set up a Claude Code remote routine that runs my news-digest skill at that time, every day. Third, run the brief once now as a test so we can confirm the whole pipeline works end to end. If anything fails, tell me what failed and how to fix it. Finally, give me the bookmark URL where my brief will live, and tell me when the next scheduled run is.That’s the last thing you have to paste.
When Claude Code finishes, you’ll have a URL. Open it on your phone. Bookmark it. Tomorrow morning, when you reach for your coffee, that’s where you’ll go.
If you get stuck on the GitHub part, reply to this email or message me and I’ll walk you through it.
What I’d Do Differently
I tried to make every section equally important. Same card size, same length, same weight. It read like a feed. The fix was hierarchy. Make the most important thing the biggest and the least important thing the smallest. One lead article gets a drop cap. Four secondary articles sit in a grid below it. The sentiment bar is a thin strip, not a section. Podcasts only show up when there’s something worth listening to.
I also included too much. Eight subreddits. Ten newsletters. Six podcasts. The brief got long and I started skimming. So I cut everything in half. I read all of it now. Fewer inputs, sharper outputs.
The first version had no failure handling. One slow API call would kill the entire 6am run. Now every agent has a quiet contract. If you fail, the brief still ships without your section. Things break. The brief still comes out at 6am.
Ready To Steal
My whole system is in this post. Top to bottom. The design step, the interview, the agents you chose, the art curator, the deploy, the schedule. Paste them in order. The interview does the heavy lifting in the middle. By the time you’re done, you have a bookmark.
It’s set up for me. The topics, the subreddits, the senders, the podcasts. The first thing you should do, before anything else, is design your own brief and run the interview. Make it yours. The whole point is that it reads to you, not to me.
If you build something with this, reply and send me the link. I want to see what your 6am looks like.








Nice concept. Mine version is via chat but I really like the idea of a publication-style format for better legibility and skimming.