v0.4.0 — Manager tier (3-level hierarchy)
Manager tier — 3-level hierarchy
The mission engine grows a middle tier: supervisor → manager → worker. Previously every plan step dispatched directly to a worker; now a step can carry a list of sub-steps and be delegated to a manager that decomposes and aggregates them.
How it works
A mission.Step can now carry a SubSteps []Step list, marking it a grouped step. When the supervisor encounters one:
- It routes the grouped step to the mission's new
manager_dispatchtopic (instead of the worker dispatch topic), with the sub-step list JSON-encoded in the dispatch payload. - A Manager consumes it, decomposes the sub-step list, and dispatches each sub-step to the same worker pool the supervisor uses.
- The Manager awaits each sub-step result (sequentially), then aggregates the outputs — one
sub_id: outputline each — into a single parent-levelResult. - The supervisor sees one "group complete" result for the parent step and continues, exactly as if a worker had handled it.
A single failing sub-step terminates the group with a parent-level error, which the supervisor treats like any other step failure (fail the mission, or replan if a Replanner is configured).
What's new
mission.Step.SubSteps []Step— rides inPlanJSON, no schema migration.omitemptykeeps existing plans parsing identically.internal/agent/manager— new package implementing the Manager role (competing-consumer subscription, decomposition, sequential sub-step execution, output aggregation).- Supervisor routing —
runStepand the parallel dispatch loop route grouped steps to the manager; ahydrateSubStepshelper mergesSubStepsfromPlanJSONonto runtime steps by ID. missionruntimespawns one Manager per mission alongside the supervisor + worker. It parks idle (one goroutine) for plans with no grouped steps.
Fixed
mission.Manager.setPlannow allocates step IDs before marshalingPlanJSON. Previously IDs were allocated after serialisation, so a caller passing empty IDs got aPlanJSONwhose parent IDs didn't match the allocatedmission_stepsrows — harmless for leaf-only plans, but it would have silently broken the manager tier's by-IDhydrateSubStepsmatch. Sub-steps now get IDs allocated too.- Toolchain bumped to go1.26.4 — resolves two stdlib CVEs (GO-2026-5039 net/textproto, GO-2026-5037 crypto/x509) flagged by govulncheck against go1.26.3.
govulncheck ./...now reports no vulnerabilities.
Scope (deliberately deferred)
- One level of delegation only (supervisor → manager → worker). A sub-step cannot itself carry
SubSteps— no recursive manager nesting. - Sub-step execution within a group is sequential. Parallel sub-step dispatch is a follow-up.
Compatibility
Fully backwards compatible. Plans with no grouped steps dispatch every step directly to a worker, exactly as in v0.3.x. No config flag, no migration, no wire-format change.
Tests
5 new manager-package tests (delegate-and-aggregate, sub-step failure, malformed/empty sub-step lists, two managers competing) + 3 new supervisor e2e tests (full 3-tier delegation, leaf-only-needs-no-manager backwards compat, group failure fails the mission). Full repo go test -race -count=1 ./... passes across all 128 packages; cross-compiles clean for linux/arm64 + windows/amd64 under CGO_ENABLED=0.
Full changelog: https://github.com/LumabyteCo/aibutler/blob/main/CHANGELOG.md