Skip to main content

Architecture

This page explains how Pycora Pro works internally. Read this first if you plan to modify or extend the engine.


Overview​

Pycora Pro is a static site generator. It reads Markdown, YAML, and templates, and produces static HTML.

The entire process is one command:

python ssg.py

That command runs a pipeline:

content/ ──┐
templates/ ──┤
static/ ──┤──► ssg.py ──► output/
_data/ ──┘

The Build Pipeline​

Here is the exact order of operations inside ssg.py:

1. Load Configuration​

Reads every YAML file inside _data/ and merges them into a single config dictionary.

  • _data/site.yaml — global site settings
  • Any other .yaml or .yml file in _data/ — merged under its filename

Legacy support: if config.yaml exists at the project root, it is also merged.

2. Set Up Directories​

Ensures these folders exist:

  • content/
  • templates/
  • templates/layouts/
  • templates/partials/
  • static/
  • output/
  • _data/

3. Scan Content​

Walks content/ recursively and parses every .md file:

  • Extracts YAML frontmatter
  • Renders the body to HTML
  • Stores metadata (title, date, tags, etc.)
  • Builds collections based on the file path

4. Detect Controllers​

A controller is a Markdown file with a collection: key in its frontmatter. Controllers do not become pages — they generate listing pages.

Example: content/journal.md has collection: posts. It lists all posts.

5. Build Collections​

For every folder under content/, a collection is created. Nested folders create nested collections with subs.

Example:

content/posts/my-post.md → collection "posts"
content/projects/project-01.md → collection "projects"

6. Generate Pages​

For each Markdown file (except controllers), the engine:

  1. Renders the body to HTML
  2. Finds the template from the layout: key
  3. Renders the template with the page's data
  4. Writes to output/<slug>/index.html

7. Generate Controllers​

For each controller, the engine:

  1. Loads the linked collection
  2. Applies filters, sorting, and pagination
  3. Renders the listing template
  4. Writes to output/<output-name>/index.html

8. Generate Tag Pages​

For every tag used in posts or projects:

  1. Creates output/tags/<tag>/index.html
  2. Also creates output/tags/index.html

9. Generate Feeds and Sitemap​

  • output/feed.xml — RSS 2.0
  • output/atom.xml — Atom
  • output/feed.json — JSON Feed 1.0
  • output/sitemap.xml — XML sitemap
  • output/robots.txt — robots file
  • output/404.html — custom 404

10. Copy Static Assets​

Copies everything from static/ into output/, preserving structure.


The Template Engine​

Pycora Pro uses Jinja2 with a custom loader called PAXLoader.

The PAXLoader does three things:

  1. Template discovery — looks for .pax and .html files in templates/
  2. Extension fallback — if .pax is missing, falls back to .html (and vice versa)
  3. Jinja slice fix — rewrites [:3] syntax into a | limit(3) filter for backwards compatibility

Example:

{{ posts[:3] }} → {{ posts | limit(3) }}
{{ posts[1:3] }} → {{ posts | slice(1, 3) }}

This lets older templates written for a Liquid-style engine keep working.


Filters Available​

FilterDescription
limit(n)Take the first n items
slice(start, end)Take a range
where(key, value)Filter by a metadata key
filter_tag(tag)Filter by tag
sort_by(field)Sort by a metadata field
reverseReverse a list
firstFirst item
lastLast item
slugifyConvert text to a URL slug

The Data Model​

Every piece of content is a PostObj — a Python object with two layers:

  1. metadata — the parsed YAML frontmatter
  2. content — the rendered HTML body

Templates access them like this:

{{ post.title }}
{{ post.metadata.date }}
{{ post.content }}

If a field is missing, the engine returns a ChainableUndefined — a placeholder that never crashes. This means templates do not fail on missing data.


Output Structure​

The final output/ folder contains only static files:

output/
├── index.html
├── 404.html
├── robots.txt
├── sitemap.xml
├── feed.xml
├── rss.xml
├── atom.xml
├── feed.json
├── <slug>/
│ └── index.html
├── tags/
│ ├── index.html
│ └── <tag>/
│ └── index.html
├── css/
├── js/
├── img/
└── admin/
└── config.yml

No runtime. No server. No database.


Build Speed​

Pycora Pro builds thousands of pages in milliseconds.

On a typical machine:

FilesTime
10< 0.3s
100< 1s
1000< 3s

What's Next?​