docs/dev/design/improved-static-site-generation.md
Foam should adopt a two-layer publishing architecture:
This keeps Foam aligned with the project's build-vs-assemble principle while still giving users a polished website for browsing their knowledge base.
Today, Foam has publishing documentation and community templates, but not a single modern architecture that:
If Foam only chooses a website framework, the framework ends up becoming the architecture. That is too brittle. Foam needs a publishing pipeline of its own.
foam-query blocks, at least where they can be resolved safely at build timeAstro and Starlight provide the polished site quickly. Foam's own publishing layer protects the project from tying note semantics directly to any one site framework.
This means Foam can:
Add a publishing layer responsible for turning a Foam workspace into publishable artifacts.
The logical module should not depend on VS Code. It should consume Foam core models and services.
For implementation, this should be phased:
packages/foam-vscode/src/publishpackages/foam-publishThe first iteration should be written as if it were already an extractable package. That means keeping it framework-agnostic, avoiding vscode imports, and giving it a clean entrypoint and module structure.
Suggested responsibilities:
foam-query output when possibleSuggested inputs:
Suggested outputs:
Add a Starlight target inside the Foam publishing layer that materializes a runnable site directory.
Responsibilities:
This target should stay thin. It is an implementation of the publishing output, not the source of truth for Foam semantics.
Expose the pipeline through a CLI entry point, likely via Foam CLI or a dedicated command.
Examples:
This matches the existing direction in the repository toward build-time transformations and automation.
The first version should follow this pipeline:
In shorthand:
Foam workspace -> foam-publish -> Markdown + JSON -> Astro/Starlight -> static HTML
This is the most practical first output format.
Advantages:
Generating only HTML would make customization harder. Generating only a raw graph JSON model would push too much work into the site layer. Markdown plus derived JSON is the right balance.
Resolve them at build time to stable site routes. The site should not need to guess how Foam resolution works.
Emit stable heading and block IDs during transformation so links and popovers can target exact content.
Handle note embeds at build time where possible. Preserve attachment embeds and image references as normal site assets.
Compute backlinks in foam-publish and expose them as page metadata or a site-wide index.
Emit graph data as JSON derived from Foam's own graph model. Render it in the site layer with a dedicated component.
foam-queryTreat query blocks as build-time features when safe and deterministic. Where execution is unsafe or unsupported, fail clearly and leave a readable placeholder in output.
Implement this in foam-publish, not in the site layer. The site should only receive already-filtered content.
Markdoc is a good integration option, but not a good center of gravity for the first version.
Reasons:
Markdoc is still useful for richer authored documentation pages outside the imported note corpus.
Quartz is close enough to Foam that it is worth studying and possibly spiking against. However, starting directly from Quartz would blur the boundary between Foam semantics and site implementation.
The project should instead:
packages/foam-vscode/src/publishvscode importsfoam-query-js be supported in published output at all, or only the declarative query language?Adopt Astro plus Starlight as the default website stack, and implement a framework-agnostic Foam publishing layer that emits transformed Markdown and derived JSON for the site to render.
Start that implementation in packages/foam-vscode/src/publish, then extract it to packages/foam-publish once the API and boundaries have stabilized.
That gives Foam the right default without collapsing publishing strategy into a single website framework.