A workspace for developing and maintaining multiple Astro/Svelte content-driven websites. Started as a pattern library, evolving toward selective package sharing where it genuinely makes sense. We call this a "pseudo-monorepo" because it's not a true monorepo but it does have some monorepo-like characteristics.
Developed and maintained by The Lossless Group
Built with love using Astro & dashes of Svelte, Reveal.js, and Tailwind CSS.
Astro Knots allows for shared patterns and context documents to be shared across related projects. We sometimes attempt to create "psued-packages" (packages that exist only to be copied from) in a monorepo with @knots/* co-location. Developers actively working on a site copy from these packages, as well as pull from components and context documents from projects under the same umbrella that is openable in an IDE and referenceable by AI Code Assistants.
Do our packeages work? For most, "sort of." The pseudo-monorepo is useful for co-locating sites and seeing patterns side by side, but maintaining abstracted, style-free component packages that every site copies from proved impractical with a small team. We gave up on @knots/* as true importable packages early on.
[!ALERT] We have one true package:
@lossless-group/lfm(Lossless Flavored Markdown)This is the only package that is actually published and used across sites. It's a markdown processor framework that both extends standard markdown with custom syntax and processing, and makes it easy for developers and clients to implement their own custom syntax and processing.
What survived and works:
context-v/ documents (specs, blueprints, prompts, reminders) that guide development across all sites@context-v/*. If it will become a pattern across multiple sites, we can move it to the shared "pseudo-monorepo" location with the same directory, file, and frontmatter conventions.@lossless-group/lfm (Lossless Flavored Markdown)What didn't work as planned:
@knots/* as imported dependencies — too much abstraction overhead for the valueThe current stance: This is a pseudo-monorepo evolving toward more sharing, but only where it's justified. Don't assume everything is a shared package. Don't hard-code the workspace. Yet, don't assume everything is copy-paste. The right answer depends on the specific code: markdown processing pipelines genuinely benefit from a shared package; UI components don't.
Listted in the order of their recency and likely relevance to future projects
| Site | Repo | Status | Notes |
|---|---|---|---|
| fullstack-vc | lossless-group/fullstack-vc | Active | Team initiative |
| mpstaton-site | lossless-group/mpstaton-site | Active | Personal portfolio/CV, actively maintained without client constraints |
| banner-site | lossless-group/emblem-site | Active | Client site |
| hypernova-site | hypernova-labs/hypernova-site | Active | Client site |
| dark-matter | lossless-group/matter-site | Active | Client site |
| twf_site | lossless-group/the-water-foundation-site | Active | The Water Foundation |
| cilantro-site | lossless-group/cilantro-site | Active | Client site, strong reference implementation |
| cogs-site | In progress | ||
| coglet-shuffle | In progress | Nested astro-site |
All sites deploy independently via Vercel from their own repos.
These are real packages that sites install as dependencies:
Lossless Flavored Markdown — a shared remark/rehype pipeline for extended markdown processing.
pnpm add @lossless-group/lfm (requires .npmrc with GitHub Packages registry)packages/lfm/context-v/specs/Codifying-a-Comprehensive-Extended-Markdown-Flavor-and-Shared-Package.mdBundles unified, remark-parse, remark-gfm, remark-directive, and custom plugins into a single import:
> [!type] Title callouts into directive nodes[^a1b2c3]) into sequentially-numbered citations with structured metadata parsing (title, URL, source, dates)import { parseMarkdown } from '@lossless-group/lfm';
const tree = await parseMarkdown(markdownContent);
// Citations are attached to the tree after parsing
const citations = tree.data?.citations?.ordered ?? [];
// Each citation has: index, title, url, source, publishedDate, raw
What the citations plugin does: Authors write stable hex-code footnotes that never need renumbering when inserting/reordering. The plugin assigns sequential display numbers by order of first appearance, parses structured definitions into typed metadata, and attaches the full citation dataset to tree.data.citations for renderers to consume.
Currently used by mpstaton-site for content rendering. Being adopted by other sites (twf_site next).
@knots/*)These are not published packages. They're workspace-local pattern references — source code you look at, copy from, and adapt. They exist for co-located development convenience and as a "cookbook" of patterns.
| Package | Purpose |
|---|---|
@knots/tokens |
Design token structure (colors, scales) |
@knots/icons |
SVG icon helper pattern |
@knots/astro |
Astro component patterns (Button, AstroMarkdown, CodeBlock, Callout) |
@knots/svelte |
Svelte component patterns |
@knots/brand-config |
Brand configuration type and CSS var helper |
@knots/tailwind |
Tailwind 3 preset/plugin (needs TW4 migration) |
The @knots/astro markdown components (AstroMarkdown, CodeBlock, Callout) are particularly useful as a starting point — mpstaton-site copied and adapted these for its content rendering.
A reusable pattern for VC client sites to aggregate and display job openings across their portfolio companies. Scrapes careers pages daily via free public JSON APIs, then renders them as a filterable jobs board.
context-v/specs/Portfolio-Wide-Job-Aggregator.md--experimental-strip-types), zero extra dependenciespnpm validate:careers (build-time URL validation + provider detection) → pnpm scrape:jobs (daily fetch from provider APIs) → static Astro pagesset:html rendering, structured salary data (Pinpoint), mode-aware logo switching, configurable card variantsDesigned as a copy-and-adapt pattern per site. If 3+ clients adopt it, the scraping logic becomes a candidate for @lossless-group/portfolio-jobs.
The context-v/ directory contains project documentation organized by type:
Sites can fetch context-v documents from multiple repos using the Context-V fetcher system. mpstaton-site displays these as browsable "Rabbit Holes."
/brand-kit & /design-systemEvery Astro-Knots site ships with two internal reference pages that together replace what most teams use Storybook (or a separate Design System Manager) for. We tried those tools and found that AI assistants working inside the site's own codebase produce pages that are just as useful — often better — because components render in their real theme, mode, layout, and tokens. No drift, no parallel build.
Brand Kit (/brand-kit) |
Design System (/design-system) |
|
|---|---|---|
| Audience | Stakeholders, brand reviewers, marketing | Developers, AI assistants, contributors |
| Scope | Brand experience essentials — colors, type, marks, signature layouts | Exhaustive component catalog with variants, props, CSS contracts |
| Update cadence | Rarely — only when brand evolves | Continuously — every new component lands here |
Both pages use the standard BaseThemeLayout and surface the theme + mode toggle so reviewers can verify all three modes (light / dark / vibrant) without leaving the page. Both emit noindex, nofollow.
Maintenance motion: every new component is added to /design-system in the same PR that introduces it. Brand evolutions update /brand-kit first, before propagating elsewhere.
Full conventions: context-v/blueprints/Maintain-Design-System-and-Brandkit-Motions.md.
Canonical references:
sites/hypernova-site/src/pages/brand-kit/, sites/twf_site/src/pages/brand-kit/sites/dark-matter/src/pages/design-system/design-system-viewer/ — An older internal tool (not deployed) for visualizing tokens, icons, and components across the workspace. Currently minimal scaffolding on Astro 6 + Tailwind 4. The aspiration was a shared micro-frontend that each site could embed, but the in-site /design-system pattern (above) has largely superseded it. Kept around as a sandbox.
See the full guide: context-v/prompts/New-Site-Quickstart-Guide.md
The short version:
git submodule add <url> sites/new_sitepnpm-workspace.yamlpnpm add astro@^6 tailwindcss@^4 @tailwindcss/vite@^4 typescript@^6theme-switcher.js + mode-switcher.js from sites/hypernova-site/src/utils/. Use the two-tier token convention: BEM-ish named tokens (--color__blue-azure, --font__lato) at the top of theme.css, kebab-case semantic tokens (--color-primary, --font-heading-1) referencing them — Tailwind v4 only generates utilities for the kebab-case tier. See Themes blueprint./brand-kit/index.astro and /design-system/index.astro. See Design System & Brand Kit blueprint.packages/lfm-astro/components/ and parse-content.ts from sites/twf_site/ if the site needs LFM rendering.Reference implementations by concern:
parseContent utility)packages/lfm-astro/)The packages/lfm-astro/components/ directory is the canonical copy source for markdown rendering components. It contains five Astro components designed to render MDAST trees produced by @lossless-group/lfm:
| Component | Purpose |
|---|---|
AstroMarkdown.astro |
Recursive MDAST renderer (20+ node types, scoped list styles for Tailwind) |
Sources.astro |
Citation list with anchor links |
Callout.astro |
Styled callout boxes (tip, warning, danger, etc.) |
CodeBlock.astro |
Fenced code blocks with language label |
MarkdownImage.astro |
Image directives with float/caption/source attribution |
Copy these into your site's src/components/markdown/ and adapt to your design. They are pattern references, not runtime imports.
# Always use pnpm — npm/yarn will break workspace resolution
pnpm install
# Run a site
pnpm --filter mpstaton-site dev
pnpm --filter hypernova-site dev
pnpm --filter cilantro-site dev
# Build a site
pnpm --filter mpstaton-site build
# Run the design system viewer
pnpm --filter design-system-viewer dev
Note: @lossless-group/lfm is installed from GitHub Packages. If pnpm complains about auth, set GITHUB_TOKEN:
GITHUB_TOKEN=$(gh auth token) pnpm install
Sites are git submodules with independent version control:
# Initialize all submodules
git submodule update --init --recursive
# Update a submodule to latest
git submodule update --remote sites/cilantro-site
# Work inside a submodule (normal git workflow)
cd sites/cilantro-site
git checkout main
git pull
# ... make changes ...
git add .
git commit -m "Update site"
git push origin main
# Update parent to track submodule change
cd ../..
git add sites/cilantro-site
git commit -m "Update cilantro-site submodule reference"
See CLAUDE.md for detailed guidance. The key thing to understand: this project is in between states. It's not a true monorepo with shared packages everywhere, and it's not purely a pattern library. The answer to "should I import this or copy it?" depends:
@lossless-group/lfm)