Recipes¶
A recipe is a YAML file with four fields — name, language, archetype, and
modules. The built-in recipes are embedded in the binary,
but --recipe also accepts a file path, so you can ship your own:
keel new --recipe ./my-recipe.yaml
Writing one¶
modules is an ordered list. Each entry is either a bare string (a built-in
module by name) or a source-qualified object (an external
module):
name: go-service-lite
language: go
modules:
- base-layout
- go-mod
- taskfile-go
- lint-go
- test-go
- name: editorconfig
source: { dir: ../external-module } # relative to this recipe file
| Field | Meaning |
|---|---|
name |
The recipe's name. |
language |
go, rust, or any — the recipe's toolchain. |
archetype |
service (default), library, or cli — whether the repo produces a binary. |
modules |
Ordered module list: built-in names and/or external entries. |
Archetypes¶
archetype tells the modules whether the repo produces a binary. Omit it and you
get service, which is what every recipe before this field did.
A library recipe drops the cmd/<name> entrypoint, the Taskfile's build task
and its ldflags, the task build lines in README and CONTRIBUTING,
.goreleaser.yaml, and the goreleaser job in release.yml. It keeps
release-please, so a library is still tagged and still gets a changelog. In its
place go-mod emits doc.go, <name>.go and <name>_test.go.
cli behaves exactly like service today — a CLI is a binary. It exists so that
recipes can declare what they are.
Templates never test archetype directly. Rendering derives two more keys from
it, and those are what modules use:
| Key | Meaning |
|---|---|
is_library |
true only for archetype: library; every when: and template guard uses this |
package_name |
repo_name reduced to a legal Go package name (go-thing → gothing) |
Language consistency¶
Every module in a recipe must be language-consistent: a module's language has
to be any or match the recipe's language. A go module in a rust recipe
(or vice-versa) is rejected — this is what keeps a scaffold's toolchain coherent.
A worked example¶
keel ships a complete custom recipe at
examples/custom-recipe/recipe.yaml
— a leaner Go composition than the built-in go-service, mixing built-in module
names with a local external module. Run it against one of the example answers
files:
keel new --recipe examples/custom-recipe/recipe.yaml \
--answers examples/answers/local-only.yaml --no-input
See Modules for authoring the modules a recipe composes, and the normative Manifest schema for the exact field definitions.