Quick Start

This page runs one small scenario three ways: from the shell, from Python and from Go. An agent is booking a trip and has three plans in mind. A fare search and a disruption feed come back, a seat hold runs out, and one plan is left. Every output below is what the command really prints, with its clock fixed so the times match.

Get the multivergence command from the download page first, or install it with Go 1.24 or later:

go install github.com/multivergence/multivergence/cmd/multivergence@latest

From the Shell

The store is one file. Point the command at it once:

export MULTIVERGENCE_FILE=trip.mv

Put the shared inputs on the trunk, the state that is real now, then fork three plans. The weights are the agent’s starting guess.

$ multivergence set budget 400
$ multivergence fork plan-train -weight 0.5
$ multivergence fork plan-flight -weight 0.3
$ multivergence fork plan-bus -weight 0.2

Each plan writes to its own branch. The flight plan assumes a fare of 250 and can’t go over budget. The bus plan holds a seat for fifteen minutes.

$ multivergence set -b plan-flight fare/flight 250
$ multivergence constrain plan-flight 'fare/flight <= 400'
$ multivergence expire plan-bus -in 15m
$ multivergence branches
BRANCH       PROB   STATUS  FROM   DEADLINE              CONSTRAINTS
plan-train   50.0%  live    trunk  -                     -
plan-flight  30.0%  live    trunk  -                     fare/flight <= 400
plan-bus     20.0%  live    trunk  2026-11-02T08:15:00Z  -

The fare search comes back. Its answer is a fact, so it goes to every live plan, and the flight’s constraint breaks:

$ multivergence observe -fact fare/flight=460
killed plan-flight: violated (fare/flight <= 400)
BRANCH      PROB   STATUS  FROM   DEADLINE              CONSTRAINTS
plan-train  71.4%  live    trunk  -                     -
plan-bus    28.6%  live    trunk  2026-11-02T08:15:00Z  -

Then a disruption feed: coaches are running late, trains are on time. The agent decides how likely that news is if each plan gets there by nine, and the engine applies it:

$ multivergence observe -l plan-train=0.9 -l plan-bus=0.3
BRANCH      PROB   STATUS  FROM   DEADLINE              CONSTRAINTS
plan-train  88.2%  live    trunk  -                     -
plan-bus    11.8%  live    trunk  2026-11-02T08:15:00Z  -

That’s Bayes’ rule: 0.714 × 0.9 against 0.286 × 0.3, scaled to add up to one. Fifteen minutes later the seat hold has gone, and reads show it at once:

$ multivergence branches
BRANCH       PROB    STATUS                         FROM   DEADLINE              CONSTRAINTS
plan-train   100.0%  live                           trunk  -                     -
plan-flight  -       violated (fare/flight <= 400)  trunk  -                     fare/flight <= 400
plan-bus     -       expired                        trunk  2026-11-02T08:15:00Z  -

Promote the survivor. Its state becomes the trunk in one step, and every branch goes:

$ multivergence promote plan-train
promoted plan-train: generation 1
$ multivergence history
2026-11-02T08:00:00Z  gen 0  fork       plan-train   from trunk, weight 0.5
2026-11-02T08:00:00Z  gen 0  fork       plan-flight  from trunk, weight 0.3
2026-11-02T08:00:00Z  gen 0  fork       plan-bus     from trunk, weight 0.2
2026-11-02T08:00:00Z  gen 0  constrain  plan-flight  fare/flight <= 400
2026-11-02T08:00:00Z  gen 0  expire     plan-bus     at 2026-11-02T08:15:00Z
2026-11-02T08:02:00Z  gen 0  killed     plan-flight  violated: fare/flight <= 400
2026-11-02T08:02:00Z  gen 0  observe    -            1 fact, 0 likelihoods, 2 live after
2026-11-02T08:05:00Z  gen 0  observe    -            0 facts, 2 likelihoods, 2 live after
2026-11-02T08:20:00Z  gen 0  killed     plan-bus     expired
2026-11-02T08:20:00Z  gen 1  promote    plan-train   generation 1

Two rules worth knowing early. A fork from the trunk takes the trunk as it is, so write shared inputs before forking; a branch forked before a direct trunk write is stale, and promote refuses it. And when a write breaks a branch’s constraint, the write is kept, the branch dies, and the command exits with 4.

From Python

Add -json and every command prints one JSON value, so any language can drive it:

import json
import subprocess

def mv(*args):
    p = subprocess.run(["multivergence", "-json", *args], capture_output=True, text=True)
    return json.loads(p.stdout) if p.stdout.strip() else None

mv("fork", "plan-a", "-weight", "0.6")
mv("fork", "plan-b", "-weight", "0.4")
out = mv("observe", "-l", "plan-a=0.2", "-l", "plan-b=0.9")
for b in out["live"]:
    print(b["name"], round(b["probability"], 3))   # plan-a 0.25, plan-b 0.75
if out["settled"]:
    mv("promote", out["settled"])

Errors come back as {"error": "...", "kind": "..."}, with kinds like not_found, stale and missing_likelihood. The repository’s scripts/cross_language.py runs the whole trip this way and checks every probability against its own arithmetic.

From Go

import "github.com/multivergence/multivergence"

s, err := multivergence.Open("trip.mv", nil)
if err != nil {
	return err
}
defer s.Close()

s.Fork("plan-train", multivergence.Trunk, 0.5)
s.Fork("plan-flight", multivergence.Trunk, 0.3)
s.Set("plan-flight", "fare/flight", []byte("250"))
s.Constrain("plan-flight", multivergence.AtMost("fare/flight", 400))

out, err := s.Observe(multivergence.Evidence{
	Facts:       []multivergence.Fact{{Key: "fare/flight", Value: []byte("460")}},
	Likelihoods: map[string]float64{"plan-train": 0.9},
	Rest:        multivergence.Likelihood(1),
})
if name, ok := out.Settled(); ok {
	s.Promote(name)
}

multivergence.New(nil) gives a store in memory instead of a file. The reference lists every call and command.

The Demo

The download includes multivergence-demo, which runs the trip above with a simulated clock and checks every number it prints. From a clone of the repository, go run ./examples/agent does the same, and go run ./examples/speculate shows the other common use: preparing the likely next step in a branch before it’s asked for.