Documentation

Config

Everything kirigami.yaml can hold — the kirigami:, seo:, prepros:, image:, plugins:, esbuild:, sass:, export:, scripts: and tasks: blocks.

Everything is driven by one file, kirigami.yaml, at the project root. It's loaded through @kirigami/struct-walker (so nested file references resolve), validated against kirigami.schema.json, then checked imperatively — kiri throws on any unknown key, wrong type, or missing required property. Point your editor at the schema for autocompletion:


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

kirigami

The only required top-level block.


                        kirigami:
                          project:  My Website           # site name — CLI banner, $project
                          baseurl:  https://example.com   # deployed root URL, no trailing slash
                          root:     src                   # dir holding _*.php pages
                          banner:   assets/banner.txt     # license banner stamped on exported js/css/html

                          # Any other key here is free-form project data — it becomes a PHP
                          # variable of the same name in every page, in before/after, and in
                          # prepros.includes files (also readable as PREPROS::$config->data).
                          author:      Jane Doe
                          email:       hello@example.com
                          description: A short description, handy for <meta name="description">.
                          keywords:    [static site, php]
                    
Key Required Notes
project Site name.
baseurl Deployed root URL, no trailing slash. Drives the sitemap and canonical URLs.
root Directory holding _*.php pages; every task's entry is relative to it.
banner A text file, its ### ### -tokens filled from this block, stamped on every exported .js / .css / .html. No file set → the bundled default banner is used the same way.

Loose keys are free project data. This site's own header/footer read $project, $baseurl, $author, $tagline, $description straight out of them — no separate "site config" object to keep in sync.

seo

The unified SEO surface — opt-in <head> metadata (<title>, description, Open Graph, Twitter Card, canonical, favicon) plus a nested jsonld sub-block for schema.org JSON-LD. A top-level block, sibling of kirigami:, replacing what used to be two separate blocks (meta: and jsonld:) — one place for a project's whole SEO setup. An empty seo: {} is enough to turn the <head> tags on for every page; values are then derived from the kirigami: keys above and each page's PHPDOC (@title, @description, @image, @robots, …), with a tag your layout already writes by hand detected and skipped. JSON-LD is a separate, independent opt-in nested inside the same block — a project can have one without the other.


                        seo:
                          twitter:    "@myhandle"
                          themeColor: "#0b7285"

                          jsonld:
                            type:   ProfessionalService   # @type for the main entity
                            lang:   en-CA                  # inLanguage on WebSite / WebPage
                            logo:   assets/logo.png        # absolute, or relative to baseurl
                            search: https://example.com/?q={search_term_string}
                    
Key Type Notes
auto bool Inject the <head> tags automatically. Default true once the block exists; auto: false (or seo: false) keeps the values without injecting — call META::tags() by hand instead. Independent of jsonld.auto.
titleFormat / titleFormatHome string <title> templates. Tokens {title}, {project}, {tagline}. Defaults {title} — {project} / {project} — {tagline}.
description / keywords string / string[] Fallback for pages with no @description / @keywords. Also feed jsonld's own description/keywords when those aren't set separately.
robots string | false Default index, follow.
language string BCP-47 tag → <meta name="language"> + og:locale.
generator string | false Default Kirigami.
author / designer string <meta name="author"> / a designer tag.
themeColor string <meta name="theme-color">.
image string Default og:image / twitter:image. Unset here, it falls back to jsonld.image / jsonld.logo, then the kirigami: block's own loose image / ogimage key.
ogType string Default website.
twitterCard string Default summary_large_image.
twitter string | map Handle for twitter:site / twitter:creator.
canonical bool Emit <link rel="canonical">. Default true.
favicon / appleTouchIcon / humans string | bool A path sets it; true forces the default file; omitted, the default is auto-detected on disk; false disables it.
jsonld object | bool Nested sub-block for schema.org JSON-LD, own independent opt-in — see below.

Per-page overrides live in the PHPDOC block: @meta false skips a page entirely; @meta_title, @meta_description, @meta_image, @meta_robots, @meta_type, @canonical override the generic tag. See META for the manual builders.

seo.jsonld

jsonld inside the seo: block turns on an automatic JSON-LD <script> in the page's <head>, derived from the same kirigami: keys — an empty seo: { jsonld: {} } is enough.

Key Type Notes
auto bool Same idea as seo.auto, but independent — controls JSON-LD only.
type string Organization, ProfessionalService, LocalBusiness, …
name / url / description string Default to project / baseurl / description.
logo / image string image defaults to logo.
sameAs string[] Profile URLs.
address map PostalAddress properties.
person string | map The #person node — a string is just the name.
search string Sitelinks SearchAction URL template; must contain {search_term_string}.

For anything schema.org doesn't cover from config alone, build a node by hand with LDLD::article(), LD::faqPage(), LD::breadcrumb(), or any type via LD::typeName([...]).

prepros

The PHP → HTML compiler. Present — even empty — forces the prepros task.


                        prepros:
                          before:   _layouts/header.php   # included before every page body
                          after:    _layouts/footer.php   # included after every page body
                          format:   true                  # pretty-print HTML output
                          head:     true                  # default true — see "Managed head" below
                          network:  false                 # allow outbound HTTP(S) — remote @tags, CURL, SCRAPER
                          mountext: [.svg, .webp]          # extra extensions auto-mounted into the virtual FS
                          includes: [_lib/functions.php]   # PHP include_once'd before any page renders
                    

includes is where you register custom tags, Markdown shortcodes and hooks — this site's own _lib/functions.php is exactly that. See Writing pages for the render pipeline these plug into.

image

The image autogenerator's one config block — see IMG for the three surfaces that call into it (img-asset() in Sass, IMG::asset() in PHP, <img asset> in markup).


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

plugins

Kirigami plugins, loaded via @kirigami/sdk.


                        plugins:
                          - name: "@kirigami/plugin-highlight"
                            active: true
                            options: {}   # free-form, validated against the plugin's own schema
                    

Each name must match @kirigami/plugin-*, <scope>/kirigami-plugin-*, or kirigami-plugin-*. kiri install <plugin> resolves a bare name against those conventions, installs it, and prints the entry to paste here — see kiri install.

esbuild and sass

Free-form blocks, merged into every task of that type (after Kirigami's own defaults) — anything the underlying tool accepts.


                        esbuild:
                          # minify: false
                        sass:
                          style: expanded
                          # before / after: extra .scss files compiled before/after the entry
                    

sass resolves @use / @forward through Sass's NodePackageImporter plus a custom importer that also accepts an implicit styles/ prefix (@use '@kirigami/canva/conf'@kirigami/canva/styles/conf).

export


                        export:
                          path:   dist                    # output dir for `kiri export`
                          ignore: ["*.psd", "notes/"]      # extra gitignore-style excludes
                    

kiri export copies kirigami.root into path, excluding any file/dir starting with _ or ., .scss files, .map files, and non-minified .js files, plus every ignore pattern. Token replacements happen during the copy: 2026 and 1789169496 in .html, 2026-09-11 in sitemap.xml.

scripts

Named PHP scripts, run with kiri run <name> or on a build trigger.


                        scripts:
                          - name: convert-images
                            mount: ["assets/images/**/*.jpg"]   # extra files mounted before it runs
                            trigger: before-build                # before-build | before-export | after-export
                    

Omit trigger for a script that only ever runs manually. See STD::succeed() / STD::error() in the PHP class library for ending one early with a custom result.

tasks

The ordered build pipeline, on top of the implicit prepros and dist tasks.


                        tasks:
                          - { name: js-core,   type: esbuild, entry: scripts/kirigami.core.js }
                          - { name: scss-core, type: sass,    entry: styles/kirigami.core.scss }
                    

Task types

The two you actually write into tasks: yourself — prepros and dist are internal, added automatically (see above), never declared by hand.

type Purpose Required Optional Output
esbuild Bundle + minify a JS/TS entry. Build + watch. name, type, entry force, head <entry>.min.js (+ .map outside export)
sass Compile a .scss/.sass entry, re-minified with csso on export. Build + watch. name, type, entry force, head <entry>.min.css (+ .css.map outside export)

Managed head

Unless prepros.head is false, every rendered page's <head> is auto-wired — no need to hand-write any of it in before:

  • a small theme/FOUC guard as the first child of <head> (adds a js class, applies the stored data-theme before first paint);
  • a <link rel="stylesheet"> for every sass task output;
  • a <script> (no defer, just before </body>) for every esbuild task output.

Paths are per-page-relative and carry a ?<timestamp> cache-bust, left literal at build time and only expanded on kiri export — so rebuilding never rewrites a committed page. A file already referenced in the page is left alone; skip a single task's tag with head: false on that task.