A zero-dependency static site CLI. Write Markdown. Optionally templates in Latte, PHP, or plain HTML. Run leaf build. Deploy anywhere static.
One binary per platform. No PHP or Composer to install on your machine at install time. (The binary currently shells out to system php at build time; FrankenPHP static link to remove that is on the roadmap.)
curl -fsSL https://leaf.ophelios.com/install.sh | shDetects your OS/arch, downloads the matching binary from GitHub Releases, verifies the checksum, installs to /usr/local/bin/leaf. Override with LEAF_PREFIX or LEAF_VERSION.
Supported platforms: macOS (arm64, amd64), Linux (arm64, amd64), Windows (amd64).
leaf init my-docs
cd my-docs
leaf dev # live preview on http://localhost:8080
leaf build # writes dist/, ready to deployleaf init <name> Scaffold a new site
leaf dev Serve with live reload
leaf build Generate static HTML into dist/
leaf eject Convert to the Composer project path (one-way)
leaf version
leaf help
Full reference: leaf.ophelios.com/getting-started/cli-reference.
After leaf init:
my-site/
├── content/ # markdown pages, organized by section
├── templates/ # optional Latte/PHP/HTML overrides (add as needed)
├── public/ # static assets copied verbatim
├── locale/ # optional translation JSON files
├── config.yml # site configuration
└── dist/ # build output (gitignore this)
No app/, bin/, vendor/, or composer.json. The framework lives inside the binary.
Drop files under templates/ to override the bundled theme. Paths map to app/Views/<same path> internally:
templates/layouts/docs.latte— override the docs layouttemplates/partials/nav.latte— override the site navtemplates/landing.latte— if present, renders at/instead of the default redirect- Same patterns work with
.phpand.html(HTML is copied through without variable interpolation)
At build time leaf needs system PHP 8.4+ with intl, mbstring, sodium, and pdo extensions. Removing this via FrankenPHP static link is the remaining milestone before true zero-dependency.
For teams that want custom controllers, Composer packages, or full ownership of bin/build.php, use the Composer template instead:
composer create-project zephyrus-framework/leaf my-docsSame zephyrus-leaf-core under the hood.
Already started on the binary and want to switch? leaf eject converts the project (one-way).
Each leaf build runs:
- Load
config.ymlfrom the project root. - Create a tempdir, overlay-merge the embedded framework + your
content/,templates/,public/,config.ymlinto it. - Invoke PHP against
bin/build.phpinside the tempdir. - Copy the rendered
dist/back into the project root. - Clean up.
leaf dev runs the same pipeline on every file change (250 ms debounced) and pushes Server-Sent Events to open browser tabs to auto-reload.
Overlay precedence: user files win over bundled defaults. content/ and config.yml are user-exclusive (defaults don't leak through). templates/, public/, locale/ are file-level overrides.
leaf init|dev|build|ejectship and are tested on Linux, macOS, Windows on every push- Pure-Go cross-compile (no CGO) produces ~13 MB binaries per platform
- Release pipeline: tag
v*→ cross-compile all 5 targets → publish GitHub Release withchecksums.txt - FrankenPHP static link (so users don't need system PHP): roadmap
See DEVELOPMENT.md for building from source, running tests, and the release pipeline.
MIT.