A minimal, private, distraction-free personal feed, arranged by day.
Dispatch is a small, focused tool in the spirit of minimal, effective, undistracted, private software: one screen, your feeds, nothing else. Your subscriptions become a focused daily reading stream you can swipe through — a row of live date bubbles up top, the selected day below, and a swipe left or right to move between days. Every day shows the articles, videos and podcast episodes your sources published that day, with cards that link out to the Substack, YouTube or Apple Podcasts apps. No algorithm, no notifications, no feed of feeds — just what you chose to follow, when it appeared.
Everything runs in your browser and everything stays on your device:
- No account, no backend, no central infrastructure. Dispatch is a static PWA — anyone can host it (or just open the hosted version) and get a personalized feed.
- Local persistence. Sources and feed items live in IndexedDB on your device, and Dispatch asks the browser for persistent storage, so your history survives restarts and works offline.
- Desktop-friendly updates. An installed copy checks for a new app shell when it opens and reloads into it automatically, while IndexedDB stays untouched. A small local source manifest can restore your subscriptions if the browser ever evicts the database.
- Local feed pulling. Feed fetching happens in your browser. Feeds that allow direct access are read directly; feeds that block browser requests fall back to a small list of public CORS proxies, in order. Feed responses are validated before they are accepted, and YouTube can fall back from its Videos playlist to the stable channel feed. No feed data ever touches a server you don't choose.
- Arranged by day. A spotlight carousel of circular day bubbles: scroll the strip and dates slide through a fixed centre — whatever lands there becomes the selected day. The weekday title stays perfectly centred, and the day view swipes left and right like a pager. Built to the Apple Human Interface Guidelines with a monochrome palette that follows light/dark appearance. Swiping beats scrolling: one day, one glance.
- Three kinds of sources, fully extracted.
- Text — Substack and any RSS/Atom feed: cover image (pulled from the post's media, first embedded image, or article Open Graph metadata), byline, and a pulled summary. Substack audio posts keep this same editorial card layout, with their duration in the metadata and a Listen action.
- Video — YouTube channels, using the channel's long-form Videos playlist so Shorts are excluded, with thumbnail, title, channel profile icon and a duration badge where the feed provides one.
- Podcast — native audio RSS feeds, with artwork or the show's source logo, show name, episode duration and a link into Apple Podcasts (resolved via the iTunes search API at add time).
- Manage sources. A Sources screen lists everything you follow. Swipe a source row left to reveal Refresh or right to reveal Delete; removing a source removes its items from the past, the present and the future.
- Reliable refresh. Dispatch starts a source refresh on every app load while the boot screen is present, renders cached content immediately, and retries each source with backoff. It also refreshes stale sources when the app returns to the foreground and periodically while it's open, while keeping the last good items visible if a network request fails. Pull down on any day to refresh immediately, or open Sources and swipe a source row left to reveal Refresh.
- Explicit provenance. Actions identify the destination: “Read on Palladium”, “Read on Substack”, “Listen on Substack”, “Watch on YouTube”, or “Listen on Apple Podcasts”.
- Installable. Add it to your iPhone home screen (Share → Add to Home Screen) — it runs full-screen with its own icon, and works offline thanks to the service worker.
- Adding a source. Paste the publication, channel, show or feed URL — a
Substack publication page or profile link (
substack.com/@handle), a YouTube channel page (/channel/…,/c/…,/user/…or@handle), an Apple Podcasts show page, a podcast RSS URL, or any RSS/Atom feed. Dispatch adapts the URL to the underlying feed, fetches it, classifies it (text / video / podcast), and stores it locally. For podcasts it also looks up the show on Apple Podcasts so cards can deep-link into the app. - Fetching. Feeds are parsed in the browser (RSS 2.0, Atom, and the
YouTube Videos playlist feed). Each item is bucketed into the device-local
day its
pubDatefalls on, deduplicated by GUID, and stored in IndexedDB. The rolling local window keeps the previous seven days and today ready. Card media for that window is warmed through the browser's cache with a bounded queue; media binaries are never copied into IndexedDB. - The calendar. The home strip shows recent days through today and never shows or loads future dates. It extends toward older dates as you scroll. Each bubble shows a live day/month date; the day view shows that day's feed items newest-first.
- Refresh scheduling. There is no background daemon — iOS doesn't allow web apps to fetch in the background. Instead Dispatch starts a refresh on every load, before the cached interface leaves its boot screen, and brings the latest successful result into the existing local view. It also checks on foreground and every 30 minutes while open when sources are stale. A failed source is retried automatically with short backoff, while other sources continue through a bounded queue.
Dispatch is a static site — no build step, no dependencies.
cd dispatch
python3 -m http.server 8787
# open http://localhost:8787For the full install experience (service worker, icons, manifest), serve over HTTPS or use a tool that sets the right headers:
npx serve .The app is plain HTML/CSS/JS — edit and reload. The checked-in monochrome home-screen icons are canonical product assets. Do not replace them by typesetting the mark with a local fallback font.
- Write the product name as lowercase
dispatchin the visual lockup. - Keep the shipped lowercase
dicon (icons/icon-512.png) as the sole mark; do not recreate it with a font or substitute generated artwork. - Use
by gbrlpzzas the compact credit. - Keep the product palette monochrome, using neutral system greys.
Any static host works. Vercel (this repo's setup):
vercel --prodor push to GitHub and import the repo in the Vercel dashboard — vercel.json
ships with clean URLs, the correct service-worker headers and the manifest
content type.
Most feeds (Substack, YouTube, most podcast hosts) don't send CORS headers, so a browser can't fetch them directly. Dispatch tries, in order:
- the feed directly,
cors.io(fast JSON envelope for Substack and YouTube),corsproxy.io,api.allorigins.win(raw),api.codetabs.com,api.allorigins.win(JSON wrapper).
You can edit the PROXIES array at the top of app.js to use your own
proxy or remove the fallbacks entirely. Note that feed URLs and titles pass
through whatever proxy you choose; the default list only forwards the bytes.
Dispatch stores everything in your browser's IndexedDB and never phones home. The only network requests are: the feeds you add, the CORS proxies above, Apple's iTunes Search API (podcast lookup), and YouTube's oEmbed endpoint (video titles). No analytics, no tracking, no accounts.
Monochrome Apple Human Interface Guidelines, using the neutral greys from
gabrielepizzi.com (gbrlpzz/index). System grouped background and card
surfaces, translucent blurred navigation bars, label/secondary/tertiary text,
system-fill pills, continuous-corner cards, SF-style glyphs drawn inline,
the iOS motion curves, light and dark appearance, safe-area insets, and a
full-screen standalone experience on iPhone. Text is sized in rem against the
system body font, so iOS Dynamic Type scales the whole interface; the
prefers-reduced-motion setting is honoured; every touch target meets the
44pt HIG minimum. Every accent is pure black in light mode and pure white in
dark mode — nothing else, so it reads as one system.
MIT — see LICENSE.
