HOLONOGRAPH / The Guide · SDK reference v0.23.0 all chapters

Chapter 05

SDK reference

Reflects Holonograph v0.23.0 · @holonograph/client · ~10 min read

The HolonographClient is the operator-facing surface end-to-end: one class you construct, one call flow — messages.create → handle → reportOutcome — and two auxiliary namespaces (contract, availability) for shape and gap declarations. This chapter documents every method.

Install

npm install @holonograph/client
# or
pnpm add @holonograph/client
# or
yarn add @holonograph/client

Single self-contained ES module, no runtime dependencies. Targets Node 18+ and any runtime with a global fetch. Fully typed — the package ships its own type declarations.

Construct a client

import { HolonographClient } from "@holonograph/client";

const client = new HolonographClient({
  endpoint: "http://127.0.0.1:8080",
  token: process.env.HOLONOGRAPH_TOKEN,
  runMode: "production",
  lensVersion: "lv_2026_07_01",
  substrate: {
    lensVersion: "lv_2026_07_01",
    lightSourceIdentifier: "anthropic/claude/4",
    runMode: "production",
    provenance: "production",
    operatorColumns: {}
  }
});

Constructor options

OptionShapeNotes
endpointstringURL where your running Holonograph lens is reachable. The README ships with http://127.0.0.1:8080 as its example host.
tokenstring (opt)Bearer token, when the lens requires one.
runModeenum (opt)One of the canonical modes (production, test, eval, replay, local_dev). Sent as x-holonograph-run-mode on every request. Can be resolved per-call at request time — see Run modes.
lensVersionstringIdentifier of the lens configuration this client should call under. Pinned into every evaluation event this client produces.
substrateobjectThe SubstrateSnapshot attached to every event. Carries lensVersion, lightSourceIdentifier, runMode, provenance, and operatorColumns — see below.

The substrate object

FieldShapeNotes
lensVersionstringWhich lens configuration was in effect.
lightSourceIdentifierstringWhich model produced the output, as vendor/model/version.
runModeenumWhich run mode the evaluation ran under.
provenancestringOrigin category of the run — see Substrate columns.
operatorColumnsobjectThe operator-declared deployment-state columns, keyed by column id. For example: { prompt_hash: "v2-sha256-…", tool_schema_version: "3.1.0" }.

The call flow

One evaluation is three calls: messages.create, then use .result, then .reportOutcome(...).

const handle = await client.messages.create({
  surfaceId: "classify-intent",
  messages: [{ role: "user", content: "why was I charged twice?" }],
  tools: [ /* ... */ ]
});

const answer = handle.result;             // read/act on the model's response
const isCorrect = grade(answer);          // your evaluation logic

await handle.reportOutcome({
  dimensions: [{
    dimensionId: "correctness",
    passed: isCorrect,
    expected: "a correct answer to the user's question",
    actual: summarize(answer)
  }],
  cohortTags: ["customer-tier=enterprise"]
});

messages.create() mediates the model call and returns a handle. handle.result is the response you use in your agent. handle.reportOutcome() closes the loop — it persists the evaluation event that binds this call into your history.

messages.create(req)

Every field on the request is optional except surfaceId and messages. The rest are passed through to the model when relevant, or interpreted by the lens.

FieldShapeNotes
surfaceIdstring (req)The surface this call belongs to. Must exist on the active contract.
messages[]array (req)The conversation turns.
systemstring (opt)System prompt.
systemOverridestring (opt)Overrides the system prompt for this call only.
additionalSkillsstring[] (opt)Extra skills to inject for this call.
additionalContextTagsstring[] (opt)Extra context tags this call should carry.
lightSourceIdOverridestring (opt)Overrides the surface's default routing to a specific vendor.
maxOutputTokensnumber (opt)Cap on the model's output length.
temperaturenumber (opt)Model sampling temperature.
toolsarray (opt)Tool declarations for the model to invoke.
toolChoiceobject (opt)Which tool the model must invoke, if any.
cacheControlobject (opt)Caching hints for the model provider.
correlationIdstring (opt)Pass one in to bind this call to a prior call's correlation. Otherwise generated.

The call handle

The object returned by messages.create().

MemberShapeNotes
.resultobjectThe primary model's response. Use this as the answer in your agent.
.observerRecords[]arrayUnder multiplex routing, the observer vendors' captured records. Empty when not multiplexing.
.reportOutcome(outcome)methodPersist the evaluation event that closes this call.
.gradeObserver(recordOrId, outcome)methodAttach grades to a cross-vendor observer call before reporting, when the lens returned observer records. Call this before reportOutcome.

reportOutcome(outcome)

FieldShapeNotes
dimensions[]array (req)One entry per dimension declared on the surface. Each entry: { dimensionId, passed, expected, actual }.
cohortTags[]string[] (opt)Discrete labels to slice on later. For diagnostic substrate columns, use the <column.id>=<value> form.
sideEffects[]array (opt)Any downstream actions this call triggered — useful for correlated fixtures and lessons later.
fixtureIdstring (opt)The fixture this call satisfied, when the call was run as part of a conformance check.

Dimension entry shape

FieldShapeNotes
dimensionIdstringMust match a dimension declared on the surface's contract.
passedbooleanWhether the dimension passed the evaluation.
expectedstringWhat good looked like — the expected shape of the response.
actualstringWhat the model actually produced (or a short summary).

Calling reportOutcome persists the evaluation event to Holonograph's substrate — one row, four layers bound (see The four-layer snapshot). What Holonograph does with that event afterwards is the subject of the analysis chapters.

Multiplex: grade the observers

When the surface's contract routes to more than one vendor, the primary's response comes back as handle.result and the observers' captured records come back as handle.observerRecords[]. Grade the observers before reportOutcome so all vendors' outcomes land in the same evaluation.

for (const rec of handle.observerRecords) {
  await handle.gradeObserver(rec, {
    dimensions: [{
      dimensionId: "correctness",
      passed: isCorrect(rec.result),
      expected: "a correct answer to the user's question",
      actual: summarize(rec.result)
    }]
  });
}
await handle.reportOutcome({
  dimensions: [{
    dimensionId: "correctness",
    passed: isCorrect(handle.result),
    expected: "a correct answer to the user's question",
    actual: summarize(handle.result)
  }]
});

See The multiplexer for how routings are declared.

Contract

contract.register(contract)

Registers or replaces the surface contract for this agent. Returns a ContractSummary reflecting the newly-active shape. See Surface contracts for the full contract shape and the summary fields.

const summary = await client.contract.register({
  agentId: "billing-triage",
  surfaces: [ /* ... */ ]
});
console.log(summary.surfaces[0].dimensionCount);

Availability

availability.mark(req, opts?)

Records that a surface is (or is not) available for evaluation over a given interval. Two modes:

  • Single — one transition event: "this surface just became unavailable" or "…just came back." Pass mode: "single" with a transition.
  • Paired — bound an interval you already know the extent of. Pass mode: "paired" with unreachableFrom and unreachableUntil. The response includes a pairing reference so downstream analyses can bracket the interval cleanly.
await client.availability.mark({
  mode: "single",
  surfaceId: "classify-intent",
  transition: "unavailable",
  reason: "vendor-outage"
});

Response:

{ "eventIds": ["evt_..."], "pairing": null }

Headers & run mode resolution

The client sends two headers on every request:

  • Authorization: Bearer <token> — when the client was constructed with a token.
  • x-holonograph-run-mode: <mode> — from the client's runMode, unless resolved per-call. A missing mode is rejected by the daemon by design (fail-closed).

For scenarios where the run mode is determined at request time (Express middleware, async work, custom resolution), see Run modes.

Escape hatch: callDirectly

For scenarios that need the full request shape — a bespoke bridge, a replay tool, or an integration test that wants to prod an edge of the wire — the client exposes a lower-level callDirectly method that skips the messages.create ergonomics and forwards the request as-authored.

const result = await client.callDirectly(rawRequest);

Prefer messages.create for anything user-facing. callDirectly is an escape hatch, not the everyday path.

Errors

Errors from the lens surface as HolonographHttpError, which carries the HTTP status, an error code, and any details the lens returned. There are additional typed error classes for the grading and availability flows so a catch block can discriminate on class.

import { HolonographClient, HolonographHttpError } from "@holonograph/client";

try {
  await handle.reportOutcome(outcome);
} catch (err) {
  if (err instanceof HolonographHttpError) {
    console.error(err.status, err.code, err.details);
  } else {
    throw err;
  }
}

The underlying wire shape every error carries:

{
  "error": "human message",
  "code": "error_code",
  "details": { }
}

4xx covers validation, auth, and not-found. 5xx is internal. 501 means the feature isn't wired on the given deployment.

Advanced: HttpTransport

The client is built on an HttpTransport primitive that's exported for advanced use — swapping in a custom fetch, adding request interceptors, or running the transport under a different runtime harness. Most integrations never touch it. If yours does, the transport surface is fully typed; the tests in the package are the working reference.