← Corpus / lossless-monorepo / habit
Maintain a Github Splash Page for each Repo
Every Lossless Group repo ships a small Astro site under splash/ that turns the repo into a free GitHub Pages landing page — hero, curated gallery, changelog and context-v rendering — without committing to a real marketing surface too early.
- Path
- habits/Maintain-a-Github-Splash-Page-for-each-Repo.md
- Augmented with
- Claude Code on Opus 4.7
- Tags
- Habit · Astro-Knots · Github-Pages · Splash-Page · Pseudomonorepos
Maintain a Github Splash Page for each Repo
Repo-level habit. Generic to every repo we own. Reference implementation:
content-farm/splash/— read itsREADME.mdend-to-end before scaffolding a new one. First instance (predates the habit):ai-labs/memopop-ai/apps/memopop-site/(lives atapps/<name>for historical reasons; new splashes usesplash/).
Why this exists
GitHub Pages is free. Every repo has a story — the why, the what, the where-it’s-going — and a README pull-quote isn’t enough. Readers want a hero, links, a sense of the artifact. We have a unified marketing surface at https://lossless.group but it’s busy and indivdual projects get buried. The primary org website also has its own style and aesthetic, and splash pages can serve as experimentation for radically different design, layout, and UX/UI innovations. And, rather than wait the full-org collaboration and page development process, we ship a small splash page (possibly with supporting pages and docs) per repo off GitHub Pages, named splash/ precisely to leave linguistic room for the eventual marketing site without renaming this one.
This is a starting point, not the destination. When a project deserves a custom-domain, or featuring on the lossless-group site, we build that separately; the splash stays put as the source repo’s own Pages presence hosted on github.
[!IMPORANT] Update the splash in addition to readme and docs
This does mean we have
one more thingto maintain, but given the speed of agent-human cooperation and the contextual information all being created already, it’s worth the tradeoff.
What “having one” means
Every repo should ship:
- A landing page — hero, value proposition, curated content gallery, philosophy/principles, recent-activity teaser, CTA.
- A changelog renderer — list (
/changelog/) + per-entry detail (/changelog/[...slug]). - A context-v renderer — list grouped by subdirectory (
/context-v/) + per-entry detail (/context-v/[...slug]). - A deploy pipeline — push to
mainbuilds and deploys. No manual deploy. - A README at
splash/README.md— local dev, deploy, where content lives, how to update.
[!NOTE] Iteration towards consistent and usable frontmatter
Because the splash page concept is much newer than changelog and content-v, historical projects may not have consistency to enable the rendering of all content in the
changelogandcontext-vdirs. This is not a critical problem, but over time agent-human teams should revise/update historical frontmatter to enable better rendering.
For pseudomonorepos (children as submodules), the splash also aggregates each child’s changelog/ and context-v/ into the parent’s feeds via the roll-up pattern (see below).
Locked conventions
These are deliberate. Don’t drift without a reason.
Tech & structure
- Astro. No React, no JSX. (See the
astro-knotsskill.) - Directory name:
splash/at repo root. Notsite/. Notapps/<name>. The name preserves linguistic space for a future custom-domain marketing site. - Package name:
<repo>-splash.private: true. Astro is the only required dep at minimum. - TypeScript path aliases in
tsconfig.json:@components/*,@layouts/*,@loaders/*,@content/*,@pages/*,@/*— so loader code never needs../../../guesswork.
Build & host
- Host: GitHub Pages, project-page form. Live URL pattern:
https://lossless-group.github.io/<repo>/. astro.config.mjs:site: 'https://lossless-group.github.io',base: '/<repo>/',trailingSlash: 'ignore',build.format: 'directory'. If a custom domain is ever added, setsiteto it andbaseto'/'.- Build trigger: push to
main. Aligns with thedevelopment→main→mastertier model — things land onmainwhen they’re noteworthy enough to publish. - Deploy action:
actions/deploy-pages@v4withactions/configure-pages@v5usingenablement: trueso the workflow bootstraps Pages on first run. - No submodule fetching in CI for pseudomonorepos — rolled-up content is pre-synced and committed; CI does pure file IO.
Local dev
pnpm install --ignore-workspace— required because the parent monorepo’spnpm-workspace.yamldoes not include splash sites; the splash installs its deps independently.pnpm devrespects the configuredbase; visithttp://localhost:4321/<repo>/.
How the splash stays isolated from its parent repo
The splash sits inside a repo that may itself be built, rendered, or deployed. Several different mechanisms keep them from stepping on each other — they’re often confused, so to be explicit:
| Concern | What enforces it |
|---|---|
| Don’t publish the splash to the npm registry | private: true in splash/package.json |
| Parent install/build skips the splash | parent’s pnpm-workspace.yaml (omit splash/ from packages:) — and inside splash/, use pnpm install --ignore-workspace to opt out of the parent workspace |
| Parent Astro site doesn’t render splash content | parent’s content.config.ts globs don’t reach into splash/ |
| Splash content commits with the repo | nothing — git tracks it by default, which is what we want |
private: true is only about the npm registry. Workspace boundaries are what keep the parent’s tooling from touching the splash.
Content rendering
- Use Lossless Flavored Markdown (LFM) for body rendering once wired in. Until then, Astro’s built-in
render(entry).Contentagainst a.prosestyling target is acceptable. - Lenient frontmatter schemas: every field in
content.config.tsusesz.preprocessto coerce empty strings, nulls, and unexpected types gracefully. Schemas never throw on legacy entries — theysafeParseand store raw frontmatter as a fallback. publish: falsein any frontmatter excludes that entry from listings everywhere. Honor it.- Curated highlights collection drives any landing-page gallery. One markdown file per item under
src/content/<thing>-highlights/. Frontmatter:title,lede,order(integer; lower sorts first; alphabetical tiebreak by filename — never throws),status,repo,icon,featured,tags. The body renders as the long-form description.
Editorial
- Hand-curated gallery. No algorithmic manifest pulling. A coding agent edits the curated list when the set changes.
- Provenance visible on rolled-up entries — readers can see which child repo each entry came from.
- Hero copy lives in
src/lib/seo.tsand theindex.astrofrontmatter. Short, opinionated, written for someone who’s never heard of the repo. - Stats / philosophy / contributor bands are optional but encouraged. They make the repo feel intentional and they’re cheap.
Reference file layout
<repo>/
├── splash/
│ ├── astro.config.mjs # base: '/<repo>/', trailingSlash: 'ignore'
│ ├── package.json # private; "<repo>-splash"; astro
│ ├── tsconfig.json # path aliases
│ ├── .env.example # GITHUB_API_TOKEN= (pseudomonorepos only)
│ ├── README.md # local dev, deploy, curation, where things live
│ ├── public/ # favicon.svg, og image, brand marks
│ ├── scripts/
│ │ └── rollup-sync.ts # pseudomonorepos only
│ └── src/
│ ├── content.config.ts # lenient schemas + (pseudomono) unionLoader
│ ├── content/<thing>-highlights/ # curated gallery cards (one .md per item)
│ ├── rollup/ # pseudomono only — synced submodule content; committed; do not hand-edit
│ ├── loaders/ # frontmatter, githubContentApi, parseGitmodules, rollupFetch
│ ├── lib/seo.ts # static SEO copy
│ ├── layouts/BaseLayout.astro # tokens, fonts, head, body shell
│ ├── components/ # PluginCard / ProjectCard, MetaTags, etc.
│ └── pages/
│ ├── index.astro
│ ├── changelog/index.astro
│ ├── changelog/[...slug].astro
│ ├── context-v/index.astro
│ └── context-v/[...slug].astro
└── .github/workflows/pages.yml # deploy splash/ on push to main
The roll-up pattern (pseudomonorepos only)
A splash inside a pseudomonorepo aggregates each child’s changelog/ and context-v/ into the parent’s feeds. Use sync-on-demand, never sync-on-build.
| Sync-on-build | Sync-on-demand (required) | |
|---|---|---|
| Build time | 30s+ (API calls) | ~1s (file IO) |
| CI auth | needs GITHUB_TOKEN | none |
| Rate limits | every build counts against 5000/hr | sync runs at human cadence |
| Diff visibility | invisible — content materializes only at render | git diff shows what rolled up |
| Determinism | depends on remote state at build time | what you commit is what deploys |
Implementation rules:
pnpm rollup:syncwrites tosplash/src/rollup/. Commit those files.- Each synced file gets injected provenance frontmatter:
from(child slug),from_path(path within source repo), optionallegacy: true. - A one-line marker at the top of each synced file:
<!-- Rolled up from <slug>/<path>. Edit at the source, not here. Re-run \pnpm rollup:sync` to refresh. —>`. src/content.config.tsuses aunionLoaderto merge parent’s localchangelog/andcontext-v/with thesrc/rollup/tree.- Auth:
GITHUB_TOKENorGITHUB_API_TOKENfrom shell orsplash/.env. Anonymous (60 req/hr) is acceptable for occasional manual syncs; one full sync uses ~60–70 calls. - The sync script writes a marker
src/rollup/README.mdso anyone exploring the tree sees the directory is generated and gets the refresh recipe.
When to run rollup:sync:
- A child shipped a noteworthy
changelog/entry you want surfaced. - You bumped a submodule pointer.
- Periodically (e.g. weekly) to catch upstream drift.
Acceptance — “this repo has a splash”
Verify before declaring the habit met:
-
splash/directory exists at repo root -
splash/astro.config.mjshas correctsiteandbase: '/<repo>/' -
splash/README.mddocuments local dev, deploy, and where content lives -
pnpm install --ignore-workspace && pnpm buildsucceeds from a clean clone -
splash/dist/includes routes for/,/changelog/,/context-v/, plus per-entry detail routes when entries exist -
.github/workflows/pages.ymlexists, buildssplash/, and deploys viaactions/deploy-pages@v4 - GitHub Pages source is set to “GitHub Actions” in repo settings
- First deploy reaches
https://lossless-group.github.io/<repo>/and loads cleanly - (Pseudomonorepos only)
pnpm rollup:syncruns locally;splash/src/rollup/is committed; rolled-up content appears on the live site with provenance
Maintenance cadence
- On every shipped change — author a
changelog/entry in the repo’s own root; it surfaces on the splash on next deploy. (See thechangelog-conventionsskill.) - (Pseudomonorepos) when a child ships — run
pnpm rollup:sync, commitsrc/rollup/, push. - When the curated gallery drifts — edit
src/content/<thing>-highlights/. New item? Add a file. Retired? Delete its file. - Periodically (e.g. weekly) — sync rollup to catch upstream drift even without a triggering event.
Variants
- Single-project repo (no submodules): skip the rollup machinery.
content.config.tsreads only the local repo’schangelog/andcontext-v/. Nosrc/rollup/, noscripts/rollup-sync.ts, nosplash/.env. - Pseudomonorepo (children as submodules): full pattern including roll-up.
- Repo with a separate marketing site already: the splash still belongs at
splash/— it’s the source repo’s GitHub Pages presence, distinct from the marketing surface. Cross-link from the splash to the marketing site and back.
What this habit deliberately is not
- Not the eventual marketing site. When that exists it’ll live elsewhere with its own custom domain.
- Not a CMS. Editing happens in the source repo’s markdown files; the splash renders.
- Not dynamic. Pure static output. Any freshness comes from a deliberate
rollup:sync+ commit + push, never from runtime fetching.
See also
- Reference implementation:
content-farm/splash/and itsREADME.md. - Reference spec:
content-farm/context-v/specs/Github-Splash-Page-for-Content-Farm.md— the spec the reference implements. - First instance:
ai-labs/memopop-ai/apps/memopop-site/. - Sibling habits:
Maintain-a-Current-README-and-other-Docs.md— the splash is one of “those Docs.”Maintain-an-Astro-Knots-site-for-Major-Projects.md— major projects also get a custom-domain Astro Knots site beyond the splash.Maintain-Projects-Collections-on-Lossless-Site.md— splash + main-site gallery cross-link.
- Skills the agent should consult when scaffolding a new splash:
astro-knots— framework rules and prohibitions.pseudomonorepos— parent-repo patterns, search-first behavior, roll-up convention.context-vigilance— context-v directory roles, frontmatter, and versioning.theme-system— two-tier tokens, three-mode contract.changelog-conventions— changelog frontmatter and ship-note structure.