Documentation
Neato is a static site generator written in PHP. You run it from the command line, and it reads your content, processes everything, and writes a complete static HTML site that can be deployed anywhere.
Running Neato
From the command line:
php neato.php
Neato expects to find a neato.yaml in the same directory as the main script. If it’s missing, it exits with an error and points you to where you can get one.
Directory Structure
Neato uses several paths, all configured in neato.yaml:
| Path | Purpose |
|---|---|
content/ |
Your source content files |
templates/ |
HTML templates |
published/ |
Where the generated site is written |
cache/ |
Build cache files |
power-ups/ |
Optional plugin extensions |
Neato creates any missing directories automatically (except published/, which it deletes and recreates if clear_published_directory is enabled in config).
Content Files
Neato processes files in the content/ directory with these extensions: .html, .mphp, .md, .txt, .neato. All other files (images, CSS, JS, etc.) are copied as-is to the published directory.
Frontmatter
Your content files can have YAML frontmatter at the top. For example:
---
title: My Page
color: pink
---
Page body here.
Neato automatically adds three metadata fields to any file that’s missing them, writing them back to the source file:
created: set initially from the file’s modification time and not changed againmodified: set from the file’s modification timeuuid: a generated UUID
Draft Status
Any file with status: draft in its frontmatter is skipped during generation, allowing you to work on draft content without publishing it.
Output Path Logic
By default, a content file like content/about/me.html becomes published/about/me/index.html, producing a clean URL (/about/me/).
Two ways to override this:
preserve: truein frontmatter keeps the original filename instead of wrapping it in a directory.location: some/pathin frontmatter overrides the output path entirely.
After processing all pages, Neato automatically copies published/home/index.html to published/index.html to serve as the site root.
Templates
Templates live in the templates/ directory. The default page template is set in neato.yaml. Individual content files can specify a different template with template: filename.html in their frontmatter.
Token Substitution
Templates use {token} syntax for variable substitution. Available tokens:
| Token | Value |
|---|---|
{title} |
The page title (from the key defined in config) |
{content} |
The rendered page body |
{description} |
The page description |
{uuid} |
The page UUID |
{path} |
The page path |
{unix-time} |
The current Unix timestamp |
{microtime} |
The current microtime |
{site.key} |
Any value from neato.yaml config (e.g. {site.domain}) |
{any-frontmatter-key} |
Any string value from the page’s frontmatter |
Template Includes
Templates can include other templates with {templates/partial-name} (the .html extension is optional).
Function Tags
There’s a function tag syntax {function:parameter}. For example {fa:solid/face-grin-beam}, which Power-Ups can use to handle custom tag processing.
PHP in Content
If parse_php: true is set in the config, PHP code in content files is executed before the content is passed to the template. The following variables are available inside content files:
$data: the page’s metadata and the content array$config: the full Neato config$item: the source file path
Power-Ups
Power-Ups are plugins that live in subdirectories of the power-ups/ path. Each Power-Up is a directory containing a PHP file with the same name as the directory (e.g. power-ups/my-plugin/my-plugin.php).
To disable a Power-Up without deleting it, prefix its directory name with an underscore (e.g. _my-plugin).
Hooks
Power-Ups extend Neato by registering hooks:
| Hook | When it fires |
|---|---|
init |
After config and Power-Ups load, before any pages are processed |
before_page |
Before each page is rendered into its template |
after_page |
After page data is assembled, before the file is written |
after_template |
After a page has been fully rendered |
shutdown |
After all pages are processed |
To register a hook inside a Power-Up:
add_hook('init', function() {
// runs once at startup
});
add_hook('after_page', function(&$data) {
// $data is the page data array; modify it if needed
}, priority: 10);
Hooks run in ascending priority order (lower numbers runs earlier). If a hook function returns a non-null value, it replaces the first argument passed to the hook.
Build Cache
After each build, Neato writes a JSON cache file to the cache/ directory listing every file in the published directory and its size. The filename includes the microtime of the build (e.g. neato_17834921045.cache).
Terminal Output
Neato logs everything to the terminal with a timestamp and a level label:
| Level | Meaning |
|---|---|
INFO |
General status messages |
LOADING |
Power-Up loading |
JOB |
Per-file processing |
REPORT |
Build summary (page count, time elapsed) |
ERROR |
Something went wrong |
Time is reported in the most human-readable unit (microseconds, milliseconds, or seconds) depending on how long the build took.