Skip to content

v0.36.0 — a recipe can sweep

Choose a tag to compare

@keparlak keparlak released this 21 Aug 17:48
· 30 commits to main since this release
27c9b1e

Baron's claim is that a workflow is enforced by the engine, not by an agent behaving well. This
release closes the hole in it.

A recipe can walk a list

The grammar was ask / do / require / message — every one single-shot. So a workflow that
sweeps N items could not be written at all, and the one sweeping workflow Baron ships (task-sync)
lived as prose in a skill, improvising primitive calls.

On an installation that sets policy.mutations.channel to recipe-only that prose could fix
nothing: every mutation it prescribed was refused, and the refusal told the caller to "find the
recipe that covers this"
— which did not exist.

  - for_each: ${inProgress}
    as: item
    collect:
      as: mergedButOpen
      from: "${item.key}"
      when: { truthy: "${merged.id}" }      # collect the ITEM, decide on what the PROVIDER answered
    steps:
      - do: scm.pr.find
        as: merged
        with: { sourceBranch: "${item.branchName}", state: merged }

Three refusals came with it, each a closed footgun rather than a preference:

  • Iteration bindings do not leak. Reading ${merged} after the loop gets nothing, not whichever
    element happened to be last — a bug that reads as data, since the value is real and merely wrong.
  • A non-list is an error, not an empty run. Quietly doing nothing is how a sweep reports "all
    clear" for a board it never read.
  • No ask inside a loop, no loop inside a loop. Asks are hoisted so a caller can supply them
    upfront, which is what makes a recipe runnable in one shot; an ask in a loop is invisible to that
    and asked once per element.

task-sync has recipes to run

Reading what the skill actually needed changed the shape of the fix. It detects, shows a table, asks
for a batch confirmation, then applies — and a recipe runs one-shot with its inputs supplied upfront,
so a confirmation that depends on what the sweep found cannot be a recipe step at all.

The split that does work is the one the architecture already wanted: the drift rule goes in YAML,
where the engine enforces it; asking a human stays in the skill, which is the part only an agent can
do.

  • task-sync-report — sweeps and reports. Read-only by construction, not by promise: there is no
    mutating step in it. Reports items still in_progress whose branch has a merged PR, and items
    in_review with no PR at all.
  • task-reconcile — clears a role label the provider's own state contradicts. One step, with the
    guard that matters: reconcile follows the provider while transition commands it, so it
    refuses on an item the provider never closed rather than clearing a label on the strength of
    nothing.
  • The class-A fix needed no new recipe: it is a forward move, which task-move has always done.

Class B — in review with no pull request — is reported and never fixed. A wrong branch, a force-push
and a hand-moved card look identical there and want different answers.

Verified against a live Linear install under recipe-only, the exact policy that used to make this
dead. That run also caught a wording bug before release: the "no drift" line fired over six drifted
items, because a condition holds one key and cannot AND two findings. It now says which finding it
speaks for.


Install: npx -y @lonca/baron-cli@latest · npx -y @lonca/baron-mcp-server@latest
Claude Code: /plugin marketplace add loncadev/baron then /plugin install baron@baron

The skills ship through the marketplace and the recipes through npm. Update both — a plugin newer
than its server holds skills calling recipes the server does not have yet.

Full diff: v0.35.0...v0.36.0