Cosmos Config Manifest¶
How cross-cutting config (newsletter URL, feedback link, parent site, etc.) lives in one place per repo, gets vendored to all 5 manifests, and propagates to every consumer with zero code changes.
Sush's principle (5 May 2026)
"Whatever direction we take the newsletter is one of many — a single place to update changes should reflect everywhere."
The problem this solves¶
Before 5 May 2026, the newsletter URL https://guided-weekly.beehiiv.com/subscribe was hardcoded in:
- Earth's homepage form (layouts/index.html)
- Earth's homepage form's submit handler (separate <script> in the same file)
- Shift's /wire/ form (already broken — submitting to a dead /wire/signup endpoint)
- The newsletter pitch text was hardcoded too ("Cloud & AI insights, every Sunday — in 2 minutes. Free.")
When Sush wanted to evaluate switching from Beehiiv to Buttondown (or anything else), there was no single place to flip. He'd have to remember every place the URL appeared, AND keep the marketing pitch consistent across all of them.
The fix: elevate cross-planet config into the cosmos manifest itself, alongside the planets list.
The schema¶
Every planet's planets.json / planets.toml now has a top-level [cosmos] block:
[cosmos]
newsletter_url = "https://guided-weekly.beehiiv.com/subscribe"
newsletter_label = "A Guide to Cloud Newsletter"
newsletter_pitch = "Cloud & AI insights, every Sunday — in 2 minutes. Free."
feedback_url = "https://www.aguidetocloud.com/about/"
parent_site = "https://www.aguidetocloud.com/"
[[planets]]
# … planets list (see Cosmos Nav Playbook)
| Field | Type | Used by |
|---|---|---|
newsletter_url |
string | Form submit URL — opens in popup with email pre-filled |
newsletter_label |
string | Display text for the link/anchor (e.g., "A Guide to Cloud Newsletter") |
newsletter_pitch |
string | Marketing pitch shown above the signup form |
feedback_url |
string | "Send feedback" links across planets (currently still hardcoded in many places — future cleanup) |
parent_site |
string | Cross-planet "back to home" links (Brain Bar uses this for its parent_site Hugo param too) |
Where it's vendored¶
Five files. When you change any field, change all five in the same commit:
| Repo | Path | Format |
|---|---|---|
aguidetocloud-revamp |
data/planets.toml |
TOML |
aguidetocloud-revamp |
brainbar/data/planets.toml |
TOML |
guided |
src/data/planets.json |
JSON |
shift |
src/data/planets.json |
JSON |
plainai |
content/planets.json |
JSON |
Where it's consumed¶
Currently consuming newsletter_url + newsletter_pitch + newsletter_label¶
| File | What it does |
|---|---|
aguidetocloud-revamp/layouts/index.html |
Homepage newsletter section. Renders newsletter_pitch as <p>, sets data-newsletter-url attribute on the section. Inline JS reads from the attribute, builds ${newsletter_url}?email=${email} and opens in popup |
shift/src/pages/wire/index.astro |
The /wire/ page. Reads cosmos block in frontmatter. Form button posts to newsletter_url via JS popup. Visible label uses newsletter_label |
Not yet consuming (future cleanup candidates)¶
The feedback_url field is currently hardcoded in many places across the four repos (e.g., https://www.aguidetocloud.com/about/ and https://www.aguidetocloud.com/feedback/ show up scattered across templates). A future session could refactor these to read from the manifest. Search:
grep -ri "aguidetocloud.com/feedback\|aguidetocloud.com/about" --include="*.html" --include="*.astro" --include="*.mjs"
Same for parent_site — Hugo Brain Bar reads it from [Params].parent_site in hugo.toml, which duplicates with the manifest. Consolidate when convenient.
How to swap newsletter platform (Beehiiv → Buttondown / Substack / etc)¶
This is the workflow you set out to make easy. Here's the full procedure, ordered by safety:
Pre-swap checklist¶
- Confirm new platform's URL pattern — does it accept
?email=pre-fill? If yes, drop-in replacement. If no, you'll need a small JS update to convert email → query string in the new format. - Test the new URL manually — sign up with a test address, confirm the new platform handles it cleanly.
- Check email export — does the existing Beehiiv list export to the new platform? If you're migrating subscribers, do that first; if you're starting fresh, the URL swap is enough.
The swap (5-file edit, one commit per repo)¶
For each of the 5 manifest files above:
# BEFORE
newsletter_url = "https://guided-weekly.beehiiv.com/subscribe"
newsletter_label = "A Guide to Cloud Newsletter"
# AFTER (e.g., switching to Buttondown)
newsletter_url = "https://buttondown.email/aguidetocloud"
newsletter_label = "A Guide to Cloud Newsletter"
Commit message template:
chore(cosmos): switch newsletter URL from Beehiiv to Buttondown
Updates [cosmos].newsletter_url across all 5 planet manifests in the same
commit. No code changes — every consumer reads from manifest:
- Earth homepage form (layouts/index.html)
- Shift /wire/ form (pages/wire/index.astro)
- Future: any new newsletter signup on any planet
Old URL: https://guided-weekly.beehiiv.com/subscribe
New URL: https://buttondown.email/aguidetocloud
Subscriber migration: [link to Buttondown import job / fresh start note]
Push each repo separately. Cloudflare deploys each automatically.
Post-swap verification¶
- Hard-refresh
https://www.aguidetocloud.com/— submit a test email, confirm popup opens to the new URL - Hard-refresh
https://shift.aguidetocloud.com/wire/— same test - Search the deployed HTML to confirm no leftover Beehiiv URLs:
What if the new platform needs a different request format?¶
Some platforms want POST instead of GET, or different field names, or auth headers. If ?email= doesn't work:
- Update the JS in
aguidetocloud-revamp/layouts/index.html(the<script>after the newsletter section) - Update the JS in
shift/src/pages/wire/index.astro(the<script is:inline define:vars={{ newsletterUrl }}>) - Both already read
newsletter_urlfrom the manifest, so only the request shape changes, not the URL source
Keep the URL still in the manifest — even if the request format changes, the URL itself is still one source.
Plain AI's intentional opt-out¶
Plain AI has [cosmos] newsletter_url in its manifest for cross-planet consistency, but Plain AI's /about/ page explicitly states:
"It's free. There's no signup, no ads, no newsletter. The point is just for it to be useful."
This is a brand promise. Don't add a newsletter form to Plain AI without re-evaluating its identity. The manifest field is there so future code (e.g., a "more from the cosmos" footer) can mention the universe-wide newsletter without breaking Plain AI's "no newsletter" stance.
What else could use the manifest pattern?¶
Sush asked: "now I have to think what other things we can do this way so it's efficient."
High-value candidates already identified:
🎯 Strong candidates (add when you next touch them)¶
| Candidate | Current state | Why manifest |
|---|---|---|
| Social media URLs (YouTube, LinkedIn, Ko-fi) | Hardcoded in Earth's homepage <section class="zh-who">, Shift's footer, Brain Bar's about, Plain AI's footer |
If you ever rebrand a handle, every site needs updating |
| OG default image | Hardcoded in each repo's <meta property="og:image"> defaults |
Centralized branding refresh |
| Brand monograms / first letters | Earth has A, Plain AI has P, etc. — hardcoded in nav/wordmark CSS |
Could be part of [planets] entries (would need to ensure each planet's local register can override) |
| Author info ("Susanth Sutheesh, Microsoft NZ") | Hardcoded in JSON-LD schemas, multiple about pages, footer | Author data block in cosmos manifest |
| Site analytics ID (GA / Plausible / etc.) | Hardcoded in baseof.html where present | If you switch analytics, one update |
🟡 Maybe candidates (proceed cautiously)¶
| Candidate | Tension |
|---|---|
| Brand colors | Each planet INTENTIONALLY has different colors (cosmos philosophy: own atmosphere). Don't centralize — would tempt visual parity drift |
| Featured tools | Already has a manifest (toolkit_nav.toml) — separate concern from cosmos |
| Email contact | Currently hello@aguidetocloud.com in a few places. Worth centralizing if you ever change it |
| Currency / pricing | Already has dedicated manifests (licence_picker/plans.toml) per-tool. Don't merge into cosmos manifest — different lifecycle |
🔴 Don't centralize¶
Things that MUST stay per-planet (cosmos philosophy: each atmosphere is its own world):
- Fonts (Inter on Earth, Iowan on Shift, Inter on Plain AI, JetBrains Mono on Brain Bar)
- Visual color palettes (indigo / red / cyan-purple-pink / phosphor)
- Voice register (Sush's English on Earth, newspaper on Shift, plain-English-explainer on Plain AI, terminal on Brain Bar)
- Animation rules (Zen restraint on Earth, tape-ticker on Shift, gradients on Plain AI)
- Page templates (each planet picks its own structure)
The general "cosmos manifest" pattern¶
If you want to apply this pattern to something else, here's the template:
- Identify the cross-cutting concern that's currently scattered. It must:
- Have ONE canonical value used by multiple worlds
- Change rarely (otherwise centralizing isn't worth the friction of editing 5 files)
- Not be a visual decision (those belong to each planet)
- Decide where it lives in the manifest — add a new top-level block (like
[cosmos]) or add fields to an existing block - Update all 5 manifests in the same commit — set the field, write a short comment explaining why
- Update consumers to read from the manifest:
- Hugo:
(index hugo.Data "planets").<block>.<field> - Astro:
import data from '../../data/planets.json'thendata.<block>.<field> - Plain AI build:
JSON.parse(await fs.readFile(...))thendata.<block>.<field> - Document the field in this doc + the Cosmos Nav Playbook under "Schema"
When NOT to use this pattern¶
The manifest is the right tool when: - The data is shared across multiple repos - The data is truly identical across repos (newsletter URL, feedback link) - Changing it requires updating multiple consumers
It's the WRONG tool when: - Data is per-repo only (use that repo's own data file) - Data changes frequently (the 5-file edit cost is non-trivial) - Data is a visual decision (cosmos philosophy → keep per planet) - Data has structure too complex for the format (use a dedicated file)
Related docs¶
- Cosmos Philosophy — why each planet keeps its own atmosphere
- Cosmos Nav Playbook — how the planets list itself works
- Deployment Playbook — pre-push checklist for any change touching 5 repos at once
Document established: 5 May 2026. The day Sush said "single place to update changes — reflect everywhere" and we baked it into the architecture.