changelog.earth
Your planet. The release notes.
New species. Balance changes. Unresolved bugs.
A few good things on Earth, one patch at a time.
!changelog.earth with a rotating ASCII planet and dated news panels
An unofficial changelog for Earth
What if the news read like a game's patch notes?
+ New cat spawned
- Elder chimp vision patched
~ Airport map rework underway
changelog.earth collects recent reporting and turns selected headlines into short planetary updates. Open a story's info button for the original headline, publisher summary and source link. The examples above illustrate the editorial style; the feed changes as new stories arrive.
- Daily editions. Aim for 3–6 worthwhile stories per publication day, prioritising discoveries, conservation wins and useful progress. Quiet days can have fewer.
- Reporting you can trace. Original links, publishers and dates stay attached to every update.
- Follow via RSS. Subscribe at
/feed.xmlfor the latest 100 published patch notes, with source links and stable IDs. The feed refreshes on the same 15-minute schedule as the homepage and never generates AI drafts. - A living terminal. A rotating ASCII Earth, dated panels and compact source stacks.
- Loading feedback. A mint Orbit indicator from loading.dev appears while a page is loading, respects reduced motion, and never delays the cached content.
- Saved editions during outages. Groq selects stories and writes patch titles. Failed requests leave the saved archive intact; raw headlines never fill the gap.
- A structured record underneath. Every archived story can be classified into a domain, a change type, a scope, an evidence status and a significance level, with the reasoning kept next to it. See event taxonomy.
Run locally
Requires Node.js 22.13 or newer and npm. Windows, macOS and Linux are supported.
git clone https://github.com/byalex33/changelog.earth.git
cd changelog.earth
npm ci
Copy .env.example to .env.local, then add your Groq API key:
GROQ_API_KEY=your_key_here
GROQ_MODEL=openai/gpt-oss-120b
npm run dev
This starts the Next.js development server, the same framework and webpack build that Vercel runs in production. Open http://localhost:5173. Without a Groq key, the app serves the saved archive but cannot select new stories. Restart the server after changing environment variables. Keep the key server-side. Configure the same variables in Vercel for production.
Collection also requires ARCHIVE_SECRET. Generate a random token with node -e "console.log(require('node:crypto').randomBytes(32).toString('hex'))" and set the same value in the hosting environment and the repository's GitHub Actions secret named ARCHIVE_SECRET. For local collection, add it to .env.local. Never use a NEXT_PUBLIC_ variable for this token. Missing or incorrect bearer tokens receive HTTP 401 before any feed or AI calls; public saved editions remain accessible.
How it works
flowchart LR
A[Twice-daily archive job] --> B[RSS feeds and Spaceflight News]
B --> C[Validate and deduplicate]
C --> D[Groq selects stories and writes titles]
D --> F[Commit saved editions]
F --> G[Homepage, API and RSS]
The Archive daily editions GitHub Actions workflow collects stories at 00:23 and 12:23 UTC. It requests drafts from /api/news?archive, then commits them to data/editions.json. Normal homepage, API and RSS requests read saved editions without calling feeds or AI. Failed collection leaves published stories intact. After an editorial style change, each run re-reviews up to 24 archived stories instead of collecting new ones until the archive is current.
Groq assesses headlines for worldwide relevance and writes game-style patch titles. Original source links, dates and publisher summaries remain attached. Generated labels can be wrong, so the linked reporting remains the reference.
On Vercel, Next.js serves the homepage as cached HTML and regenerates it on visits after 15 minutes. Failed or empty regeneration keeps the previous page; an initial build without a valid edition fails. Local development renders on demand, so use a production build to measure caching.
See collection, archive and caching details for the editorial rules, outage behaviour and provider limits.
Structured archive
The patch notes are the readable layer. Underneath, the archive is being shaped into a structured, source-backed record of changes to Earth: events with domains, change types, evidence and a significance ladder, each traceable to the reporting it came from. That work is deliberately retrospective and offline, so it never touches collection, the homepage or the feed.
The vocabulary is a draft, and it is validated against the archive rather than assumed. docs/event-schema.md is the contract; lib/taxonomy.mjs holds the machine-readable version of it, and lib/taxonomy-fallback.mjs holds the separate heuristics that infer a story against it when no record exists.
node scripts/classify-archive.mjs # one-off retrospective classification, resumable
node scripts/report-classification.mjs # distribution, examples per level, vocabulary gaps
Classification writes data/classifications.json with its own provenance, and never modifies data/editions.json. Stories without a record are derived on read and reported as inferred.
Make it yours
| Change | File |
| --- | --- |
| Add or adjust an RSS feed | lib/rss-feeds.mjs |
| Tune story selection and patch-note wording | lib/changelog.mjs |
| Adjust freshness, filtering and source caching | lib/news.mjs |
| Change the ASCII globe | components/ascii-earth.tsx and lib/ascii-earth.mjs |
| Edit the page and theme | app/page.tsx and app/globals.css |
| Change story popouts and the source directory | components/news-details.tsx |
| Change the event vocabulary or its labels | lib/taxonomy.mjs and docs/event-schema.md |
| Change how unclassified stories are inferred | lib/taxonomy-fallback.mjs |
| Change the retrospective classification pass | lib/classification.mjs, lib/classification-prompt.mjs, lib/classification-records.mjs |
| Change how the archive is measured and reported | lib/classification-report.mjs and lib/classified-archive.mjs |
Built with Next.js 16, React 19, TypeScript and Tailwind CSS 4, deployed on Vercel. An optional Cloudflare Workers build uses Vinext. Groq uses the REST API directly. The interface uses shadcn/ui, Radix, Motion and Hugeicons.
Checks
Run npm run lint for ESLint. The contribution guide lists the focused checks for parsing, editorial rules, publication, caching, RSS and globe geometry. They use Node's built-in assertions and mocked provider requests.
Deploy to Vercel
Import this GitHub repository in Vercel. The included vercel.json selects Next.js, installs with npm ci, and builds with next build --webpack. Add GROQ_API_KEY as a server-side environment variable, optionally set GROQ_MODEL, then deploy. The news function allows up to 180 seconds for upstream fetches and generation.
For analytics, create a website in Tracwell, use its private collection mode, and add the production domain to its allowed domains. Set NEXT_PUBLIC_TRACWELL_PROJECT_KEY to the public browser project key before building. No analytics script is loaded when this value is absent. Never use a Tracwell server key in this variable.
Add your custom domain in the Vercel project settings and apply the DNS records Vercel provides at your DNS host.
Build for Cloudflare
Vercel is the production host. A secondary Cloudflare Workers target builds the same app with Vinext and has its own scripts:
npm run dev:cf # Vinext dev server on the Workers runtime, http://localhost:5173
npm run build:cf
npm run start:cf
npm run build:cf produces a Cloudflare Worker under dist/server; npm run start:cf previews it locally through Wrangler. To host it on your own Cloudflare account, configure your Worker and secrets, then deploy the generated Worker configuration.
Set GROQ_API_KEY as a production secret and optionally set GROQ_MODEL. Do not commit credentials.
Contributing
Read the contribution guide for setup, checks and pull request expectations. Everyone taking part should follow the code of conduct.
License and credits
Project code is available under the MIT license. Third-party components retain their own notices:
- BeUI motion components
- shadcn styles
- JetBrains Mono and Plus Jakarta Sans, under the SIL Open Font License