Reference · reference

package.wcl

11 min read · 2026-09-02 · config-weave 0.1.0

package.wcl is the WCL document under pkgs/<name>/ inside a playbook directory. It holds one package block, which declares the package's gatherers, resources, composites, tests and scenarios. The engine appends the system import <weave/package.wcl> when it opens the package, so you never write an import line. The package name qualifies every reference from a playbook: a resource file_present in package core is core.file_present. What a package is for is explained in Packages, resources and gatherers; this chapter lists every block and field.

ItemValue
Location<playbook>/pkgs/<name>/package.wcl
System import<weave/package.wcl>, appended by the engine
Top-level blockpackage "name" { … }, exactly one per file
Scripts*.ws files, referenced by path relative to the package directory
Shared helperslib/*.ws, importable with use name from this package's scripts

Every field marked required is enforced by the loader, including each block's description. The name weave is reserved for the built-in package that ships inside the binary, so a pkgs/weave/ directory is rejected. A secret() call anywhere in a package is a validation error: packages are shared through git and cannot hold a value encrypted under one playbook's password.

package

pkgs/core/package.wclwcl
package "core" {
  description = "Files, directories and OS facts"

  gatherer "os_info" { … }
  resource "file_present" { … }
  composite "site" { … }
  test "file_present_converges" { … }
  scenario "reboot_survives" { … }
}

The root block. Resources and composites share one namespace, so a package may not declare both under the same name.

FieldTypeRequiredMeaning
labelstringyesThe package name. Must match the directory name under pkgs/.
descriptionstringyesOne-line summary for the docs.
gathererblock, repeatablenoFact collectors. See gatherer.
resourceblock, repeatablenoUnits of desired state. See resource.
compositeblock, repeatablenoReusable blocks of steps. See composite.
testblock, repeatablenoConvergence tests. See The test block.
scenarioblock, repeatablenoScripted multi-machine tests. See scenario.

gatherer

wcl
gatherer "os_info" {
  description = "Operating system facts"
  script = "gatherers/os_info.ws"

  param "detail" {
    description = "How much to collect"
    type = "symbol"
    default = :basic
  }
  returns "family" {
    description = "The OS family"
    type = "string"
  }
  returns "init" {
    description = "The init system"
    type = "symbol"
    symbol "systemd" { description = "systemd" }
    symbol "openrc"  { description = "OpenRC" }
  }
}

A fact collector. Its script exports gather(params: Value) -> Value (or the Result form, see Script entry points). A playbook gather block runs it and binds the returned value to a variable. The returns blocks document the keys of the returned map. The engine does not require a gathered map to carry those keys, or only those keys, because a gathered map may hold dynamic ones. The exception is a key declared type = "symbol": its value binds into the playbook as a WCL symbol, so a playbook compares it as init.init == :systemd, and if the key enumerates symbol blocks the script's returned value must be one of them.

FieldTypeRequiredMeaning
labelstringyesThe gatherer name, referenced as package.gatherer.
descriptionstringyesOne-line summary for the docs.
scriptstringyesPath of the wscript file, relative to the package directory.
paramblock, repeatablenoDeclared parameters. See param.
returnsblock, repeatablenoDocumented keys of the returned map. See returns.

resource

wcl
resource "file_present" {
  description = "A file with the given content"
  script = "resources/file_present.ws"
  concurrency = "parallel"

  param "path" {
    description = "Absolute path of the file"
    type = "string"
    required = true
  }
  param "content" {
    description = "The file's contents"
    type = "string"
    default = ""
  }
}

A unit of desired state. Its script exports check(params: Value) -> CheckResult and apply(params: Value) -> ApplyResult, and must honour the convergence contract: check never mutates, and after a successful apply a re-check returns AlreadyConfigured. A step invokes the resource as package.resource and supplies its parameters in a properties block.

FieldTypeRequiredMeaning
labelstringyesThe resource name, referenced as package.resource.
descriptionstringyesOne-line summary for the docs.
scriptstringyesPath of the wscript file, relative to the package directory.
concurrencystringno, default "parallel"The scheduling class. See Concurrency classes.
paramblock, repeatablenoDeclared parameters. See param.

param

wcl
param "max_age" {
  description = "Refresh when the last update is older than this span"
  type = "duration"
  default = 24h
}

param "ensure" {
  description = "Whether the file should exist"
  type = "symbol"
  default = :present
  symbol "present" { description = "Create or update the file" }
  symbol "absent"  { description = "Delete the file" }
}

One declared parameter of a resource or gatherer. Validation checks each supplied value against the coarse type, applies the default when the value is absent, and rejects a missing required parameter or an undeclared name. Two types have a fixed spelling. A symbol value is written :name wherever it appears; the quoted spelling is an error, because both reach the script as the same text. A duration value is a bare WCL unit literal with suffix ns, us, ms, s, min, h or d (minutes are min, because m is metres), and the script receives a plain Int of nanoseconds.

FieldTypeRequiredMeaning
labelstringyesThe parameter name, the key in the script's params map.
descriptionstringyesOne-line summary for the docs.
typestringyesOne of string, int, float, bool, list, map, symbol, duration.
requiredboolno, default falseWhether a step or gather must supply the parameter.
defaultvalue of typenoUsed when the parameter is omitted.
symbolblock, repeatablenoFor type = "symbol" only. See symbol.

symbol

wcl
symbol "on_demand" { description = "Start when first requested" }

One legal value of a symbol parameter or returns key. Declaring any closes the set: the declared default, every step property or gather param, every value that only resolves at run time, and a test expect value are checked against it, and the generated docs list the values. Declaring none leaves the parameter open to any token. The block is an error on any other coarse type. Name a symbol in its WCL-spellable form (on_demand, not on-demand); a script that needs another spelling translates it itself.

FieldTypeRequiredMeaning
labelstringyesThe value, without the leading colon.
descriptionstringyesWhat choosing this value means.

returns

wcl
returns "init" {
  description = "The init system in use"
  type = "symbol"
  symbol "systemd" { description = "systemd" }
  symbol "openrc"  { description = "OpenRC" }
}

Documents one top-level key of the map a gatherer returns. The docs render the keys as a table. Only a key of type symbol is enforced: its returned value binds as a WCL symbol and must be one of the declared symbol values when any are declared. Only top-level keys are typed; nested maps stay plain data.

FieldTypeRequiredMeaning
labelstringyesThe key name in the returned map.
descriptionstringyesWhat the key holds.
typestringyesThe same coarse types as param.
symbolblock, repeatablenoFor type = "symbol" only: the legal values.

composite

wcl
composite "site" {
  description = "A directory with an index page"
  arg "root" {
    description = "Directory that holds the site"
    type = "string"
    required = true
  }

  step "dir" {
    description = "Site directory"
    resource = "directory"
    properties { path = args.root }
  }
  step "index" {
    description = "Index page"
    resource = "file_present"
    requires = ["dir"]
    properties { path = $"${args.root}/index.html" }
  }
}

A named, parameterised block of steps, invoked from a playbook step as package.composite. It has the same shape and rules as a playbook composite, described under composite in playbook.wcl: the loader expands each invocation into a container of ordinary steps, the body sees only its own arguments through args.name, and requires inside the body reaches only sibling steps. Inside a package body an unqualified resource names this package's own resource or composite. A body step may not carry expect; that field belongs to a test step.

FieldTypeRequiredMeaning
labelstringyesThe composite name. Shares a namespace with this package's resources.
descriptionstringyesOne-line summary for the docs.
argblock, repeatablenoDeclared arguments, with the fields of arg.
stepblock, repeatablenoThe body. Each step takes description, resource, condition, requires, concurrency and properties.

test

wcl
test "file_present_converges" {
  description = "file_present creates the file and is idempotent"
  image = "debian:12"
  step "create" { … }
  gather "os" { … }
}

An isolated convergence test, run by config-weave test inside a disposable vmlab instance with the three-run protocol. Every field, the nested step and gather blocks, and the expectation table are in The test block.

scenario

wcl
scenario "ad_matrix" {
  description = "Forest root, member join and a second DC over real reboots"
  lab = "labs/ad"
  script = "scenarios/ad_matrix.ws"
}

A scripted, multi-stage test over a declared vmlab lab, for flows the three-run protocol cannot express: a reboot in the middle of convergence, or several machines that talk to each other. The lab directory holds a vmlab.wcl declaring every VM up front. The script exports run(lab: Lab) -> bool (or Result[bool, string]) and runs on the host against the live lab through the testlab module. It compiles during validation and runs after the parallel test groups, one scenario at a time. See The testlab.

FieldTypeRequiredMeaning
labelstringyesThe scenario name.
descriptionstringyesOne-line summary for the docs.
labstringyesDirectory holding the vmlab.wcl, relative to the package directory.
scriptstringyesPath of the driver script, relative to the package directory.

Concurrency classes

wcl
concurrency = "parallel" | "exclusive" | "global"

A resource declares its class in the concurrency field. A step may tighten the class of the resource it invokes, and an invocation of a composite tightens every step of the body, but nothing may loosen a class: a step declaring a looser class than its resource fails validation. The built-in weave.execute resource is parallel for this reason; a script that touches a shared lock declares concurrency = "exclusive" on the step. How the scheduler applies the classes is in Scheduling and concurrency.

ClassMeaning
parallel (default)No restriction. Any number of steps of this resource run alongside any other step.
exclusiveAt most one step of this resource type runs at a time. Steps of other resources continue. The package-manager lock case.
globalThe step runs completely alone. The scheduler drains every in-flight step, runs this one, then resumes.