Feature

Data files

Point a PHPDOC annotation at a YAML or JSON file and get structured data back.

When an annotation value ends in .yaml, .yml, .json or .md and resolves to a file next to the page, it is parsed and injected as data instead of a string. @stats _stats.json here became a decoded object:

0
Runtime dependencies
1
Config files
static HTML
Build output
none
Server processes

And @articles _articles.yaml — a YAML sequence — arrived as an array of objects to loop over:

Finally, @readme https://…/README.md was fetched over the network at build time and converted from Markdown:

Kirigami README (fetched at build)
Kirigami

Kirigami

A static site generator that turns PHP into fast, dependency-free HTML — no server required.

License: MIT Node


Overview

Kirigami lets you build static websites using a language you already know — PHP — and compiles them straight into clean, production-ready HTML. There's no server to provision, no runtime to patch, and no infrastructure to maintain: the PHP engine runs entirely in WebAssembly (via @kirigami/php-wasm), directly inside the Node.js process. You get the full expressiveness of PHP templating with the simplicity, speed, and portability of a static site.

Here's what Kirigami brings to your workflow:

  • Real PHP templating — includes, loops, Markdown, YAML — compiled directly to clean HTML, no server needed at runtime.
  • Integrated asset pipeline with esbuild for JS and Sass for styles, wired in from the start.
  • A watch mode with hot-reload, so changes show up instantly during development.
  • A single-command production export — a fully static site ready to deploy anywhere (GitHub Pages, Netlify, any static host), complete with a license banner and an auto-generated sitemap.
  • Instant project scaffolding from official templates via kiri create.
  • Scriptable automation, running PHP scripts on demand or as build-pipeline hooks with kiri run.

Every project is driven by a single configuration file, kirigami.yaml, at the project root.


Table of contents


Monorepo structure

This repository is an npm workspaces monorepo, organized as follows:

Package Description
packages/kirigami The heart of the project: the kiri CLI (build, export, watch, run, create, phpinfo).
packages/php-prepros The PHP → HTML compiler that powers the CLI (template rendering, sitemap generation, and more).
packages/php-wasm A custom PHP WebAssembly build for Node.js (JSPI only, no browser support).
packages/struct-walker Recursively walks YAML/JSON structures, resolving relative file references and converting assets to data URIs.
packages/sdk Shared runtime for plugins: the hook registry and the on-disk Cache.
packages/canva Shared Sass/JS design system reused across Kirigami projects.
packages/plugin-highlight Official plugin: build-time syntax highlighting (highlight.js), 0 runtime JS.
packages/plugin-extlink Official plugin: external link preview cards, SCRAPER-backed, cached to disk.
packages/plugin-embed Official plugin: YouTube/Vimeo oEmbed video cards, resolved client-side.

Requirements

  • Node.js >= 24.0.0
  • npm >= 10.2.3

Installation

Get the CLI via the @kirigami/kirigami package:


                            npm install -D @kirigami/kirigami
                        

That's it — the kiri command is ready to go (via npx kiri or an npm script).


Quick start

  1. Drop a kirigami.yaml at the root of your project:

                            kirigami:
                              project: "My Site"
                              baseurl: "https://mysite.com"
                              root: "src"

                            prepros:
                              before: "_layouts/header.php"
                              after: "_layouts/footer.php"
                              format: true
                        
  1. Write your _*.php pages inside the src/ folder (or wherever root points).
  2. Fire up dev mode and watch it come alive:

                            npx kiri watch
                        
  1. Ship it! Export the fully static site for production:

                            npx kiri export
                        

CLI commands

Command Description
kiri build Compiles the project for development (runs every configured task once, no minification/export step).
kiri export Compiles and exports the project for production (forces every task + copies static files).
kiri watch Starts dev mode: watches project files and rebuilds automatically on change.
kiri serve Same as kiri watch, plus a local server and browser hot-reload (Server-Sent Events, no server framework).
kiri run <script> Runs a PHP command script from the scripts/ folder inside the Kirigami runtime.
kiri create <template> Creates a new project from an official template — ships its own CLAUDE.md, Claude Ready out of the box.
kiri install <plugin...> Installs a plugin and prints the plugins: entry to paste into kirigami.yaml.
kiri cache purge [mask] Purges the local .node.db / .cache.db / .cookie.txt caches (or just the keys matching mask).
kiri phpinfo Prints phpinfo() from the embedded PHP-WASM runtime.

Every command comes with its own detailed help: kiri <command> --help.


Configuration (kirigami.yaml)

The whole project is configured through a single kirigami.yaml file at the project root, validated against a JSON schema. Point your editor at it and enjoy full autocompletion:


                            # yaml-language-server: $schema=https://cdn.jsdelivr.net/gh/php-kirigami/kirigami@main/packages/kirigami/kirigami.schema.json
                        

Here's a real-world example, showing most of the available sections:


                            kirigami:
                              project:     My Website
                              baseurl:     https://example.com
                              banner:      assets/banner.txt
                              root:        src

                              # Any extra key becomes a PHP variable available in every template

                              author:      Jane Doe
                              person:      John Smith
                              jobtitle:    Founder
                              email:       hello@example.com
                              facebook:    https://www.facebook.com/example
                              area:        Somewhere, Country
                              gtag:        G-XXXXXXXXXX

                              description: >
                                A short description of the site, also exposed as $description.
                            
                              knowsabout:
                                - Topic one
                                - Topic two
                              keywords:
                                - keyword one
                                - keyword two


                            prepros:
                              format: true
                              network: true
                              # mountext: ['.webp']
                              includes: [_lib/functions.php]
                              before: _layouts/header.php
                              after:  _layouts/footer.php


                            image:
                              # format: avif        # webp | avif (default: webp)
                              source: assets/images  # relative to cwd()          (default: assets/images)
                              dest:   images         # relative to kirigami.root  (default: images)


                            plugins:
                              - name: "@kirigami/plugin-highlight"
                                active: true
                                options: {}


                            esbuild:
                            #   minify: false

                            sass:
                            #   style: expanded


                            scripts:
                              - name: convert-images-to-webp
                                mount: ["assets/images/**/*.jpg"]
                                trigger: before-build # before-build, before-export or after-export


                            tasks:
                              - name:  js-core
                                type:  esbuild
                                entry: scripts/kirigami.core.js

                              - name:  scss-core
                                type:  sass
                                entry: styles/kirigami.core.scss
                        

kirigami: — core project settings

Key Required Description
project Human-readable project/site name. Printed in the CLI banner and available as $project in every template.
baseurl Root URL of the deployed site, no trailing slash. Used to build absolute <loc> entries in sitemap.xml and available as $baseurl.
root Path (relative to the project root) to the directory holding your _*.php source pages. All task entry paths and prepros rendering are relative to it.
banner Path to a text file used as the license/copyright banner stamped on every exported .js/.css/.html file. May contain the ###DATE### token, replaced at load time. Falls back to an auto-generated banner if omitted.
(anything else) Free-form project data (string, number, boolean, list, or nested map). Every extra key is exposed as a PHP variable of the same name (author$author, etc.) in page templates, before/after includes, and prepros.includes files.

prepros: — the PHP → HTML compiler

Just declaring this block (even empty) automatically prepends a forced prepros task that renders every page and regenerates sitemap.xml.

Key Description
before PHP file (relative to root) included before every page's body — typically your <head>/layout opening.
after PHP file included after every page's body — typically your layout closing.
format Pretty-print the compiled HTML output (4-space indentation). Defaults to false.
network Enable outbound HTTP(S) requests inside the sandboxed WASM runtime (needed for remote @tag fetches and cURL/scraper classes). Defaults to false.
mountext Extra file extensions auto-mounted into the virtual filesystem, in addition to the built-in defaults (.php, .json, .yaml, .yml, .md, .db, .txt).
includes PHP files include_once'd right after config load, before any page renders — the natural place to register tags/hooks/Markdown plugins.

image: — image autogenerator

Options for the built-in image autogenerator. One feature, four entry points that share this config, one engine and the same output files: the img-asset() and colors() Sass functions, the PHP IMG::asset() / IMG::palette() helpers, and the <img asset="…"> tag in page templates — all resize/encode through the IMG class (GD/Imagick) in the WASM runtime, so there is no native image dependency. Optional — the defaults below apply even when the block is absent.

Key Description
format Output format for generated images: webp or avif. Defaults to webp.
source Folder holding the source images, relative to cwd(). Defaults to assets/images.
dest Destination folder for generated images, relative to kirigami.root. Defaults to images.

plugins: — Kirigami plugins

A list of plugins loaded through @kirigami/sdk. Each entry's package name must match @kirigami/plugin-*, <scope>/kirigami-plugin-*, or kirigami-plugin-*.

Key Description
name Plugin package name (following one of the naming conventions above).
active Whether the plugin is loaded.
options Free-form object passed to the plugin; its shape depends on the plugin.

esbuild: / sass: — global build options

Both are free-form objects passed straight through to the underlying build call, after Kirigami's own defaults (so they can override them): esbuild: maps to esbuild's own BuildOptions, sass: to Dart Sass's own Options. sass: also accepts before / after — arrays of extra .scss files compiled respectively before and after the entry (paths relative to cwd()). Leaving a block empty (as in the example above) is equivalent to omitting it entirely.

export: — production export options

Key Description
path Output directory for kiri export, relative to the project root. Defaults to dist.
ignore Extra gitignore-style patterns of files/directories to exclude from the export copy.

scripts: — named PHP scripts

Each entry maps to a PHP file at scripts/<name>.php, runnable manually with kiri run <name> [args...] or fired automatically at a pipeline checkpoint.

Key Description
name Script identifier — must match an existing scripts/<name>.php file.
mount Glob patterns (relative to the project root) of extra local files to mount into the sandbox before the script runs.
trigger Fires the script automatically: before-build (start of both build and export), before-export (very start of export), or after-export (once export has finished writing every task's output).

tasks: — the build pipeline

An ordered list of build tasks, run in array order — on top of the implicit prepros task (added automatically whenever the prepros block is present) and the implicit dist task (added automatically during kiri export).

type Purpose Required fields
esbuild Bundles/minifies a JS or TS entry point. Supports build & watch. name, entry
sass Compiles a .scss/.sass entry point, minified with csso on export. Supports build & watch. name, entry
prepros Renders pages + sitemap.xml. Watch only on a plain kiri build/watch — the implicit task added by the prepros: block is always forced. name
dist Copies kirigami.root into the export output dir. Implicit/forced only, added automatically by kiri export. name, path

Continuous deployment

Kirigami ships an official reusable GitHub Action, php-kirigami/kiribuild (v2) — published on the GitHub Marketplace, installable straight from a workflow file's Actions sidebar. The action itself only installs Node + kiri and runs kiri export — checkout, committing back whatever the build regenerated, and the actual Pages upload/deploy are wired by the caller's own workflow steps, so the full flow stays explicit:


                            # .github/workflows/page.yml
                            name: Build & Deploy
                            on:
                              push: { branches: [main] }
                            permissions: { contents: write, pages: write, id-token: write }
                            concurrency: { group: pages, cancel-in-progress: true }
                            jobs:
                              build-and-deploy:
                                runs-on: ubuntu-latest
                                environment: { name: github-pages, url: ${{ steps.deployment.outputs.page_url }} }
                                steps:
                                  - uses: actions/checkout@v7

                                  - uses: php-kirigami/kiribuild@v2
                                    with:
                                      node-version: "24"

                                  - name: Commit regenerated files
                                    run: |
                                      if [ -n "$(git status --porcelain)" ]; then
                                        git config user.name  "kirigami[bot]"
                                        git config user.email "kirigami-bot@users.noreply.github.com"
                                        git add -A && git commit -m "chore: update generated files [skip ci]" && git push
                                      fi
                            
                                  - uses: actions/upload-pages-artifact@v5
                                    with: { path: dist }

                                  - id: deployment
                                    uses: actions/deploy-pages@v5
                        

Every official template (kiri create) already ships this workflow at .github/workflows/page.yml — copy it from there. Check the action's own documentation for its inputs.


License

This project is distributed under the MIT license, except for the @kirigami/php-wasm package, which is distributed under GPL-2.0-or-later (see its README).


Author

MIT © Maxime Larrivée-Roy, 2026