The core ideas and extension model behind Webifier.
Webifier is a static site generator that turns repository files into complete
HTML websites. Users define their site structure in .yml files, write content
in Markdown, notebooks, HTML, or other static files, and Webifier handles the
rendering, asset management, search indexing, and output.
The architecture is built on one small core plus extension-defined page grammar. Webifier loads config, enables extensions, walks reachable pages, and dispatches rendering. Extensions decide what most syntax means.
Three mechanisms show up everywhere:
| Axis | Mechanism | Purpose |
|---|---|---|
| Value | ${resolver:arg \| transform} |
Compute, load, and transform values |
| Node | kind: name |
Control how a YAML block is processed and rendered |
| Template | template: path |
Use a specific template file for one node |
| Everything else — labels, navigation, headers, styles, search, analytics, | ||
| themes, comments, notebook controls, PDF controls, and custom page keys — comes | ||
| from enabled extensions. |
The filesystem is the API. Users customize by placing files in conventional locations (templates, assets). No Python required for 90% of use cases.
Extension-defined page grammar.
The core knows how to load config, enable extensions, dispatch renderers,
resolve values, and write files. Keys like title, nav, header, label,
toc, or a future weather key are owned by renderers or extensions. If an
extension consumes a page key, later renderers do not see it as content.
Composition over configuration.
Sites are composed from small files (${load:}, ${glob:}), not configured
in one giant YAML. Resolvers and pipes make composition powerful.
Progressive complexity. Simple sites enable the first-party extensions and write content. Advanced users add resolvers, renderers, themes, and full Python extension packages.
webifier/
core/ # Framework — minimal, stable
base.py # RendererModule ABC, NodeContext
registry.py # Kind registry + resolution
resolvers.py # ${} resolver engine + pipe chain
loader.py # YAML loading, patch, defaults, ${} expansion
builder.py # Thin dispatch: load → resolve → render
html.py # BeautifulSoup HTML post-processing
markdown.py # Markdown → HTML conversion
io.py # File I/O utilities
interface/ # User-facing entry points
cli.py # CLI (webify command)
extensions/
webifier_extensions/
standard/ # Default page/section/content shell
markdown/ # Markdown rendering and content pages
notebook/ # Jupyter notebook conversion
search/ # Search index generation
theme/ # Light/dark/system theme plumbing
analytics/google/ # Google tag head injection
comments/ # Comment renderer
people/ # People card renderer
chapters/ # Accordion/chapter renderer
resume/ # Resume experience renderer
| I want to… | What I do | Python? |
|---|---|---|
| Change how people cards look | Drop templates/people.html in my repo |
No |
| Create a "gallery" section type | Create templates/renderers/gallery.html, use kind: gallery |
No |
| Give one page its own layout | Write a template, use template: templates/landing.html |
No |
| Override the page layout | Drop templates/page.html in my repo |
No |
| Add search, theme, notebooks, comments | Enable the matching extension under webifier.extensions |
No |
Add a custom page key such as weather |
Write an extension that consumes that key | Yes |
| Add a custom value resolver | Write an extension that registers a resolver | Yes |
| Custom data processing + rendering | Write a RendererModule subclass and expose it from an extension |
Yes |
| Share a reusable renderer | Publish a pip package with a webifier.extensions entry point |
Yes |
${} and pipes)