BlaiseBlaise
Documentation
Runner and PlugsExplanation

How sessions find a runner

Runners, instances, labels and requirements; how work is spread across instances; why work queues; and why a paused session goes back to the machine it ran on.

Blaise separates what runs from where it runs.

ConceptWhat it isLives until
AgentA preset: configuration, session policy and label requirementsArchived
RunnerOne authorization of a machine (or fleet) to take sessions for a workspaceRevoked
InstanceOne connected blaise-agent listen process of a runner, with its labelsIts connection closes

An agent does not name a runner, and a runner does not name an agent. They are coupled only through labels.

Matching

An instance's labels are a map from a key to a list of values. An agent's requirements have the same shape. An instance satisfies an agent when, for every required key, it declares every required value. Nothing else is evaluated: there are no operators beyond "includes", and no ordering between requirements.

Blaise applies the rule twice. The offer stream only lists work an instance may take, and the claim checks it again, so a modified client cannot take work it was not offered. Labels select capacity; they are not an access control between the runners of one workspace.

Queued work waits

When a session needs a run, Blaise creates an execution in the queued state. It is offered to the matching instances as described in Sharing work across instances, and one of them claims it. Only then does it become starting, and only then does the agent's startup grace period begin.

This means that queued work has no timeout. If every runner is offline, or none matches, the session shows Waiting for a runner and starts as soon as capacity appears. A user can cancel a queued run; it becomes cancelled, which is final and is not a failure.

Sharing work across instances

When several instances can take a run, Blaise prefers the one with the most free capacity.

  • Capacity. An instance may declare capacity in blaise.yml: the most runs it holds at once. An instance without one has no limit.
  • Load. An instance's load is the number of runs it has claimed that are starting or running. Blaise reads it from its own records, so it stays correct when a process dies.
  • Ranking. Matching instances are ranked by capacity minus load. An instance with no declared capacity is ranked as if it had a small fixed capacity, so an idle one is preferred over a busy one. The ranking never limits it. Ties are spread evenly and stay stable as instances come and go.
  • First choice, then everyone. The top-ranked instance is offered the run first. If it is still queued after 15 seconds, for example because that instance is stuck, it is offered to every matching instance below their capacity, so a dead instance delays work by at most that long.
  • Capacity is enforced at the claim. An instance at its capacity is not offered new runs and cannot claim them, even with a modified client. Cleanup runs are never held back by capacity.

Capacity is declared by the instance and is advisory between instances: it spreads work, it is not an access control. If every matching instance is at capacity, the session shows Waiting for a runner and starts when one finishes a run. The dashboard shows each instance's load against its capacity.

Paused sessions go back to where they ran

A paused session keeps its environment: a worktree, a container, a clone. That environment is on the machine that ran the session, so later runs of the same session are offered only to instances of the runner that ran it before. Fresh sessions have no such preference.

  • If that runner is only offline, the run waits for it.
  • If that runner was revoked, the run falls back to any matching runner and starts a fresh environment.

Instances that share one authorization

Several instances may use one runner token. Blaise treats them as one pool, so a resume can be claimed by any of them. Plan for that: either they should see the same file system (a shared volume, or an environment on a remote host that all of them reach), or the plugs should be stateless so each instance can rebuild the environment. If your instances do not share anything, give each its own authorization by running login on each machine.

Agents that pause, and runners that cannot resume

An agent whose idle policy is pause needs a runner whose plug chain can resume. At startup, listen works out whether its chain can, and tells Blaise when it connects. An instance that cannot resume is not offered sessions of pausing agents. If only such instances are online, those sessions wait; the queued notice says so. Make the plugs resumable (Make a plug resumable) or change the agent's idle policy.

Why this design

  • Registration is self-service. A runner appears when its CLI registers; there is no per-agent setup step to forget.
  • Capacity is visible. The dashboard counts registered runners and instances online, like a list of authorized devices.
  • Work is not lost. The database is the source of truth, and a queued execution is offered again on every reconnect.

See also Choose which runners an agent runs on.

On this page