Skip to content
WIP

This guide is a work in progress. Barry is also a work in progress.

Schedule and distribute work

Use this when you want work to run without you watching: on a schedule, backed by a durable engine, and spread across more than one machine.

  • Build a Barry. These commands act as the bonanza identity from that guide; use your own identity’s command in its place.
  • Have a bag you own, with the action you want to run.
  • To run work on another machine, install Barry on that machine too.

A schedule fires an action on a trigger. A bag declares its schedules in bag.yaml, each naming a trigger and what to run:

schedules:
nightly-triage:
every: 1d
action: triage-alert
traits: [debug]

A schedule needs exactly one trigger and exactly one thing to run. The triggers are:

Trigger Fires Example
every On an interval, one of 1m, 5m, 15m, 30m, 1h, 1d every: 1h
cron On a five-field cron expression, read in UTC unless you set timezone cron: "0 9 * * 1"
at At one ISO-8601 time with an explicit offset, or once per login with at: login at: "2026-11-02T09:00:00-05:00"

What runs is one of action (a reference such as slack:weekly-digest, or an inline action body), job (one of the bag’s jobs), or entry (a script).

A schedule receives only what it names. Set identity to choose whose keys and default harness an agent action uses, and traits and bounds to choose what it can do; a schedule with no identity must name its traits. You can also set inputs, overlap (skip or queue), catch_up (once, the default, runs a fire missed while the machine was off on return; none skips it), and enabled: false to keep a schedule declared but off. timeout belongs to a script entry alone; an action or a job sets its own.

Terminal
bonanza schedule list
bonanza schedule show sessions/reaper

list shows each schedule with its next and last fire and whether the scheduler is alive. A schedule’s ID is <bag>/<name>. To act on one:

Command Effect
bonanza schedule run <id> Run its action now, outside the trigger
bonanza schedule pause <id> Stop it firing until resumed
bonanza schedule resume <id> Resume it; its next fire counts from now
bonanza schedule logs <id> Print the latest run’s log (-f to follow)

Barry’s durable workflow runtime backs every scheduled run, so it survives interruptions:

  • State, history, and timers commit together, so a run that a restart interrupts resumes where it left off rather than starting over.
  • Wall-clock deadlines stay authoritative across restarts.
  • Delivery is at least once: a step whose worker crashes or loses its lease is retried, by default up to three times with a growing delay.

You do not configure any of this per schedule; it is how the runtime executes every run.

When your Mac is busy, link another machine as a worker and Barry hands it the jobs. The owner is also its own worker, so steps that can run locally never leave your machine.

  1. On the machine that owns the work, invite a worker. Barry prints a join token, shown once:

    Terminal
    barry workers invite laptop
  2. On the worker machine, join with that token:

    Terminal
    barry workers join <token>
  3. If a job requires a label, such as a local model, add it to the worker’s barry.yaml under services.workflows.runtime.env, then restart the runtime and check what the worker now offers:

    services:
    workflows.runtime:
    env:
    - BARRY_WORKFLOW_LABELS=model=local
    Terminal
    barry service restart workflows.runtime
    barry workers status

    Only claim labels the machine can satisfy: a label does not install the model software.

The worker advertises what it can run (its jobs, labels, and capacity, default four concurrent). Barry fans jobs out across connected workers and retries a job elsewhere if a worker dies. barry workers list shows the workers you invited and the owners you joined, and barry workers status explains why a job is or is not offered to a machine.

Trust is one-way and revocable. The owner stores only a hashed credential; the worker’s credential opens exactly one route and nothing else. Rotate a worker’s credential with barry workers rotate <worker> (the old one keeps working for five minutes), or cut it off with barry workers revoke <worker>.

To confirm the scheduler is alive and sees your schedules, run:

Terminal
bonanza schedule list

With no schedules declared, schedule list reports the scheduler’s heartbeat. The output is similar to the following:

Output
● scheduler running (beat 4s ago)
No schedules. Declare them under schedules: in a bag.yaml.

Once you install a bag that declares schedules, each one appears by its ID, with its trigger, its action, and its last and next fire. For a worker, run barry workers status on it: it lists the worker’s labels and the jobs it can run for an owner.

  • The first line reads scheduler down or scheduler degraded. The reason follows on the same line. Check the scheduler’s service, and see See what is running.
  • A line starts with !. Barry could not load a bag’s schedules; the line names the error. Fix the schedules: block and install the bag again.
  • A schedule shows failing. Read its latest run with bonanza schedule logs <id>.
  • A worker never gets a job. barry workers status names the reason, such as a label the job needs that the worker does not offer.