Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

crucible

The crucible mark: a vessel of molten metal.

Deterministic agent orchestration

Agents do the work. The engine selects the next task.

Crucible is a deterministic orchestrator for agent workflows. It runs agent turns in sandboxes. You declare the graph, and the engine schedules the tasks, isolates them, and records their cost.

A workflow is a graph of agent turns, commands, and checks. The executor selects the next task, not the agent. The selection rules are fixed, and you can read them before the run starts.

Deterministic

The engine runs the plan that you review

  • Workflows compile to a static plan. Loops and functions unroll at compile time.
  • The executor advances the plan. The dispatch order is stable, and the event stream is reproducible.
  • Outcomes follow fixed rules. Transport failures retry. Measured failures do not retry. If a plan cannot run in full, the engine dispatches nothing.
  • Every run has a cost limit and a time limit.

Sandboxed

The host keeps the credentials

  • Agent turns run in OpenShell sandboxes with deny-by-default egress.
  • Privileged operations go through a broker. The agent sends a request over MCP, and the host does the operation.
  • A pack declares its egress and credentials. crucible check lists them before the run starts.
  • Launch parameters go into prompts. They do not go into a command line.

Two lanes

The same engine runs two kinds of workflow.

A playbook, end to end

A pack is a directory that holds a crucible.toml, a workflow.star, and the scripts that the tasks run. This pack reads a ticket, routes it to one queue, and files it:

read = command(name = "read", run = "./classify.sh", emits = ["bucket"])

gate = route(
    name = "gate",
    depends_on = [read],
    source = read,
    questions = {
        "bucket": choice(
            ask = "Which queue owns this ticket?",
            options = ["outage", "billing", "feature"],
        ),
    },
)

oncall = command(name = "oncall", run = "./file.sh oncall", depends_on = [gate],
                 when = gate.bucket, answers = "outage")
finance = command(name = "finance", run = "./file.sh finance", depends_on = [gate],
                  when = gate.bucket, answers = "billing")
backlog = command(name = "backlog", run = "./file.sh backlog", depends_on = [gate],
                  when = gate.bucket, otherwise = True)

filed = command(name = "filed", run = "./file.sh filed",
                depends_on = [oncall, finance, backlog], join = "passed")

workflow(type = "playbook", tasks = [read, gate, oncall, finance, backlog, filed], result = filed)
$ crucible plan run --manifest crucible.toml --max-cost 1 --max-time 5m
  read                 pass       attempts=1 cost=$0.0000  out={"bucket":"billing"}
  gate                 pass       attempts=1 cost=$0.0000  out={"bucket":{"confidence":1.0,"label":"billing",...}}
  oncall               not_taken  attempts=0 cost=$0.0000  (gate.bucket resolved to billing)
  finance              pass       attempts=1 cost=$0.0000  out={}
  backlog              not_taken  attempts=0 cost=$0.0000  (gate.bucket resolved to billing)
  filed                pass       attempts=1 cost=$0.0000  out={}
plan v1: completed — spent $0.0000 of $1
verdict: valid

The branches that no answer selects settle not_taken. They do not dispatch and do not spend. If you replace source = read with min_confidence = 0.8, a decision model answers the question. The engine records a low-confidence answer as uncertain, and the otherwise task takes it.

A playbook run in the crucible control plane: the admitted task graph with a fanned-out build and measure, one failed instance, and the judge that kept the winner.
A playbook run in the control plane: a fanned-out build and measure, one failed instance, an advisory profile, and each task's cost.

Where to go next

The pieces

CrateWhat it is
crucible/The engine: the Starlark compiler, the plan executor, the autoresearch loop, agent backends, and crucible deploy.
crucible-controller/The control plane: a Postgres ledger, the reconciling daemon, the HTTP API, and the embedded UI.
crux/The CLI and MCP tools over the controller API.
crucible-broker/The broker. The host keeps the credentials, and the sandboxed agent sends requests over MCP.
forge/Image builds, registry, and deployment support.