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

Payload JSON Schema

Pulse publishes a single machine-readable JSON Schema (draft 2020-12) describing every public payload — the request envelopes and the universal --json output envelope. Use it to validate requests before sending them, to generate client types, or to drive editor autocompletion.

Where to get it

The schema is reachable three ways, all backed by the same generator (descriptor.BuildPayloadSchema):

SurfaceHow
Docs URLhttps://frankbardon.github.io/pulse/payload-schema.json — the file’s own $id.
CLIpulse schema prints it to stdout (offline; no cohort needed).
MCP resourceRead pulse://schema (MIME application/json) alongside pulse_manifest.

The CLI and MCP surfaces emit byte-identical output to the published file.

Structure

The document is a $defs bundle. The root oneOf lists the entry points:

  • Requests#/$defs/Request (process / predict), ComposedRequest (compose), ChainRequest (process-chain), FacetRequest, SampleRequest.
  • Results#/$defs/Response, ComposedResponse, ChainResponse, FacetResult.
  • Envelope#/$defs/Envelope, the universal --json wrapper. Its data slot is intentionally open: it carries whatever the operation returned (a Response, the manifest, a predict result, an inspect result, …). To validate a wrapped result strictly, validate the unwrapped data value against its own def (e.g. #/$defs/Response).

Example — validate a request body with any draft-2020-12 validator:

pulse schema > payload-schema.json
# then point your validator at  payload-schema.json#/$defs/Request

How it stays in sync

The schema is generated, never hand-maintained, so it cannot silently drift from the engine:

  1. Reflection over the Go payload structs — a new or renamed field changes the output.
  2. Registry-injected enums — the operator, overlay-kind, and regression discriminants draw their value lists from the same types.All*Types() / AllOverlayKinds() / AllRegressionTypes() registries the engine executes against, so registering a new operator changes the schema.
  3. Hand-tuned strict unions for the two shapes reflection cannot express: OverlayRef (at most one arm populated) and OverlayPayload (shape-discriminated scalar / series / matrix).

A golden test (TestPayloadSchemaGolden) pins the output and an enum-parity test (TestPayloadSchema_EnumsMatchRegistry) fails CI on drift; the schema’s format_version is held equal to the envelope’s (TestPayloadSchema_VersionMatchesEnvelope). Regenerate after an intentional payload change with:

go test ./descriptor/ -run TestPayloadSchemaGolden -update

v1 boundaries

The schema is faithful but not maximally strict in two places, by design:

  • Operator params (the json.RawMessage slot on aggregations, groupers, overlays, etc.) is an open object. There is no central declarative source for per-operator input parameters — each operator’s param schema lives alongside its processor — so encoding it here would duplicate that surface and rot. Consult the operator’s skill / manifest entry for its accepted params.
  • Small closed mode enums (OverlayScope, OverlayShape, CrosstabNormalize, CrosstabShape, LabelMode, MarginAxis) are typed as plain strings rather than enums — they have no registry helper, and a hardcoded list would drift silently.

Cross-slot validation rules that depend on more than one field (e.g. a crosstab requires at least one row and one column, mutually exclusive with top-level groups) are enforced by pulse predict at request time, not by the schema.