| app | ||
| cli | ||
| cmd/sarten | ||
| discovery | ||
| fsx | ||
| logging | ||
| model | ||
| parser | ||
| render | ||
| serve | ||
| site | ||
| slug | ||
| stitch_recipe_index(3)/stitch_recipe_index | ||
| testdata | ||
| .gitignore | ||
| generate_and_sync.sh | ||
| go.mod | ||
| go.sum | ||
| justfile | ||
| mise.toml | ||
| README.md | ||
| robots.txt | ||
| spec.md | ||
Sarten
Sarten is a static site generator for Cooklang recipes, written in Go.
It scans a directory of .cook files, parses each recipe, and (as the project evolves) builds a static recipe website.
Current status
The MVP build pipeline is in place:
sarten buildcommand and flags- recursive discovery of
.cookfiles - Cooklang parsing and metadata mapping
- deterministic slugging and site assembly
- HTML rendering for index + recipe pages
- embedded theme assets (templates and CSS) via Go
embed - filesystem output writing to
index.html,recipes/*.html, andassets/site.css - human-readable build summary output, plus verbose mode details
sarten servefor local preview with rebuild-on-request (no output directory required)
Prerequisites
- Go
1.24.3(or compatible withgo.mod) just(optional, for convenient task shortcuts)
Development setup
-
Clone the repository.
-
Install dependencies:
go mod download -
Build the CLI binary:
just buildOr without
just:go build -o ./bin/sarten ./cmd/sarten -
Run tests:
just testOr:
go test ./...
To refresh render golden files intentionally:
SARTEN_UPDATE_GOLDEN=1 go test ./render -run 'TestRenderMatchesGoldenFiles|TestRenderBaseURLMatchesGoldenFile'
Using Sarten
Build command
./bin/sarten build --input ./recipes --output ./public
Available flags:
--input(required): directory containing.cookfiles--output(required): output directory for generated site files--base-url: optional site base URL used to render absolute links in generated pages--lang: language code for generated pages (endefault,esavailable)--site-title: optional site title for templates--head-script: optional raw<script>tag inserted into the<head>of every generated HTML page--clean: clean output before build--verbose: enable richer logging
Serve command
./bin/sarten serve --input ./recipes --port 8080
Behavior:
- serves generated pages directly from memory (no
--outputdirectory) - rebuilds by rereading
.cookfiles on every HTTP request - supports
--base-url,--site-title, and--head-scriptfor generated links, titles, and custom head scripts
Available flags:
--input(required): directory containing.cookfiles--host: host interface to bind the server (default127.0.0.1)--port: port to bind the server (default8080)--base-url: optional site base URL used to render absolute links--lang: language code for generated pages (endefault,esavailable)--site-title: optional site title for templates--head-script: optional raw<script>tag inserted into the<head>of every previewed HTML page--verbose: enable richer request/build logging
For example:
./bin/sarten build --input ./recipes --output ./public \
--head-script '<script defer src="https://example.com/analytics.js"></script>'
The tag is inserted as trusted, unescaped HTML. Only pass markup you control.
Canonical recipe example
The repository includes a canonical recipe fixture at testdata/canonical_recipe.cook.
It is used in tests and demonstrates most Cooklang capabilities and common metadata patterns:
- frontmatter metadata (
title,description,tags,servings,yield) - nested metadata blocks (
source.name,source.author,time.prep,time.cook) - sections (
== ... ==), inline comments (-- ...), and block notes (> ...) - ingredients, cookware, timers, and quantity/unit forms
- relative ingredient reference (
@./sauces/Hollandaise{...})
You can copy this file into your recipes directory to test full parsing behavior.
Additional fixture directories are available under testdata/fixtures/ for minimal, metadata, duplicate-title, full, and invalid scenarios used by end-to-end tests.
Static site output
The intended output layout is:
public/
index.html
assets/
site.css
recipes/
<recipe-slug>.html
Build output semantics
- Default build writes generated files into
--outputand leaves unrelated existing files untouched. --cleanremoves the entire output directory before writing generated files.- If parsing fails, the build stops before writing output files, and existing output is left untouched.
Project structure
cmd/sarten: binary entrypointcli: command and flag parsing (kong)app: build orchestrationdiscovery:.cookfile scanningparser: Cooklang parsing adaptermodel: internal domain models
See spec.md for the full architecture and roadmap.