HOLONOGRAPH / The Guide · Run modes v0.23.0 all chapters

Chapter 07

Run modes

Reflects Holonograph v0.23.0 · ~7 min read

Every call to the lens declares which run mode it belongs to. The mode gates side effects, decides which events count as production history, and — most importantly — keeps test and evaluation traffic from silently polluting your production substrate. Modes are enforced fail-closed: a missing or unknown mode is rejected at the door.

What it is

A run mode is a single-string label attached to every call. Holonograph's canonical set has five values:

ModeMeaningSide-effect behavior
productionA real user's request through the real system.Full side effects. Persists to production-state provenance.
testAn automated test exercising the agent.Side effects are suppressed or replaced with fixtures. Persists to exploratory-state.
evalA deliberate evaluation run — an operator asking "how is the system doing?"Side effects suppressed. Persists to exploratory-state. Eligible for cohort-tag-driven grading pipelines.
replayReplaying prior traffic against a specific lens version or model.Side effects suppressed. Persists to exploratory-state. Tagged so replays don't co-mingle with live evaluation.
local_devA developer poking the system on their laptop.Side effects suppressed. Persists to exploratory-state. The permissive mode you use during integration work.
There is no debug mode The canonical set is exactly the five above. If you see debug anywhere in code or a sample, treat it as an error to correct — not a sixth mode.

Why it matters

Two properties fall out of enforcing modes at the wire:

  • Substrate integrity. Your production history stays production. A test that forgot its mode doesn't quietly become a production event when you read it back a month later.
  • Side-effect discipline. An eval run that touches a downstream system by accident is a serious incident. Fail-closed makes that failure loud instead of silent — the daemon rejects a call with no mode, and modes other than production suppress the side-effect channel.

How to use it

Set once, on the client

The simplest wiring: pass runMode once at client construction. Every call the client makes carries it.

const client = new HolonographClient({
  endpoint: "http://127.0.0.1:8080",
  runMode: process.env.NODE_ENV === "production" ? "production" : "local_dev",
  lensVersion: "billing-lens/v14",
  substrate: { /* ... */ }
});

Set at the wire

If you're calling POST /holonograph/messages directly, send the mode as a header on every request:

x-holonograph-run-mode: production

A missing header is rejected with a 400. This is by design — Holonograph does not guess.

Resolve per-request in a web framework

Web applications often need to resolve the mode from the incoming request — e.g. a header set by a shadow-traffic proxy, or a query flag distinguishing an internal QA session. Wire this at your framework's middleware layer, before any code path that constructs an HolonographClient:

// Express example
app.use((req, _res, next) => {
  const shadow = req.header("x-shadow-traffic") === "1";
  req.holonographRunMode = shadow ? "test" : "production";
  next();
});

app.post("/agent", async (req, res) => {
  const client = new HolonographClient({
    endpoint: "http://127.0.0.1:8080",
    runMode: req.holonographRunMode,
    lensVersion: "billing-lens/v14",
    substrate: { /* ... */ }
  });
  // …
});

Propagate across async and process boundaries

When work crosses a boundary the client can't reach — a queue, a background job, a message bus — carry the mode as W3C Baggage so the receiver can reconstruct it. Two keys:

Baggage keyCarries
holonograph.runmodeThe run mode of the originating request.
holonograph.correlation-idThe correlation id, so calls on the other side of the boundary bind into the same evaluation.

The receiver extracts both keys from Baggage and constructs its HolonographClient with the run mode it inherited, then passes the correlation id through to messages.create(). See Sidecar / OTel integration for the propagation mechanism.

Reading the output

run_mode is one of the mandatory substrate columns on every event (see Substrate columns) — so every reading you do downstream is already sliceable by mode without any extra work.

Two default habits keep your reads honest:

  • provenance defaults to production-state. That's what filters non-production modes out of dashboards. If you need them, pass provenance=exploratory-state or provenance=all.
  • Never rely on run_mode as a substitute for side-effect gating. Modes shape which channel side effects go through, but the guarantee is Holonograph-side. Your agent code should still respect the mode when it exists in scope.

Reference

Fail-closed behavior

The daemon rejects any request that arrives without a valid mode. Concretely:

  • Missing x-holonograph-run-mode header → 400 with an error message indicating the run mode is required.
  • Unknown value (anything outside the five canonical modes) → 400 with an error message indicating the value is not one of the accepted modes.

This is not something you can turn off. It's a property of the daemon, not a policy on top of it.

Header

  • x-holonograph-run-mode: production | test | eval | replay | local_dev

Baggage keys

  • holonograph.runmode — the run mode.
  • holonograph.correlation-id — the correlation id binding calls across the boundary.