Repository navigation
v0.10.0
Release v0.10.0
Release Notes
Overview
This release focuses on making fleet-based configuration simpler and more idiomatic. If your recipes manage multiple hosts, you no longer need to thread host lists and parallel value maps through your code manually. You can now attach arbitrary typed values directly to hosts in your inventory, associate a fleet with your task methods once, and iterate over that fleet's hosts cleanly from within your recipe bodies.
Features
Per-host recipe values
You can now store arbitrary typed values on individual hosts at inventory time:
Host("web", WithSSHHost("web.example"),
WithValue("cron", [2]string{"6", "7"}),
)Values are retrieved inside task bodies with a type-safe accessor:
window := MustHostValue[[2]string](host, "cron")Why this is useful: Previously, you'd maintain a separate map[string]T alongside your host registry and use MustMapValue to look entries up, risking drift between the fleet membership and the value map. Now the value lives on the host record itself, so a host is registered or isn't — there's no second source of truth to keep in sync. Missing keys and type mismatches fail fast with clear error messages, the same contract as MustHost / MustFleet.
FleetHosts() — iterate the current task's fleet from inside a task body
func (MyTasks) Cron() {
for _, host := range FleetHosts() {
w := MustHostValue[[2]string](host, "cron")
WhenHostname(host, func() { /* … */ })
}
}FleetHosts() returns the list of inventory names for the fleet associated with the currently running task. It fails fast if called outside a fleet-scoped task.
Why this is useful: Previously you'd need to pass the fleet name or host list around explicitly to know which hosts the current task operates on. Now the association is implicit — set once at registration, available anywhere in the body.
WithFleet on RegisterMethods and WithTaskFleet on Task
RegisterMethods(MyTasks{}, WithPrefix("edge_"), WithFleet("edge"))associates a fleet with every method on a struct in one declaration.Task("name", "desc", fn, WithTaskFleet("edge"))does the same for a single task.
Why this is useful: For a struct with many methods that all target the same fleet, you declare the association once rather than repeating it per method. Nested task execution is handled correctly — an inner Aggregate calling a child task pushes its own fleet frame, so each task body always sees its own fleet.
Improvements
List(...) promoted to the canonical DSL alias for []string
List("a", "b", "c") is now documented and recommended everywhere you'd otherwise write []string{"a", "b", "c"} — in multi-path resources, Command args, WhenHostname hosts, EachKV pairs, and similar.
Why this is useful: A single, discoverable spelling for "a list of strings" across the DSL reduces cognitive load and makes recipes more uniform. Docs and examples have been updated to prefer List(...) throughout.
MustMapValue replaced by MustHostValue
The old generic MustMapValue[K, V] helper has been removed in favor of MustHostValue[T], which reads from the host registry directly.
Why this is useful: The old helper required you to carry a map around and explain what it was for. The new one is self-contained — you name the host and the key, and it fetches from the inventory.
Documentation
- New "Fleet hosts and per-host values" section in
helpers.mdwith a complete worked example. WhenHostnamedocs and examples updated to showList(...)instead of[]string{...}.plan.mdandtasks.mdtables updated to reflect theList(...)spelling.
Migration Notes
| Old | New |
|---|---|
MustMapValue(m, key, what) |
MustHostValue[T](host, key) |
[]string{"a", "b"} in DSL recipes |
List("a", "b") |
| Manual fleet-name threading in task bodies | WithFleet / WithTaskFleet + FleetHosts() |
If you have existing recipes using MustMapValue, replace the parallel map with WithValue / SetValue on each host and switch the lookups to MustHostValue. The List(...) change is cosmetic — []string{...} still works, but List(...) is now preferred in docs and examples.