HOLONOGRAPH / The Guide · The lessons pipeline v0.23.0 all chapters

Chapter 12

The lessons pipeline

Reflects Holonograph v0.23.0 · ~10 min read

A system's interactions contain the information that should make it better. This chapter is how Holonograph turns that information into shipped improvements: captured human overrides cluster, the drafter proposes concrete corrective artifacts for each cluster, a named human approves or rejects at the gate, and only then does anything get published. Nothing bypasses the gate.

What it is

A five-step pipeline, one endpoint per step:

  1. Override — a human corrects the system's output. Recorded as first-class ground truth: what the system produced next to what good looks like.
  2. Cluster — similar overrides group together, so one fix can address a pattern instead of a single instance.
  3. Draft — the drafter proposes a concrete corrective artifact for a cluster. Four kinds: skill, lesson, fixture, code-change-recommendation.
  4. Approve or reject — a named approver reads the draft, edits or rejects. This is the gate.
  5. Publish — an approved draft becomes substrate. Versioned, captured, and attributable in future readings like any other change.

Why it matters

Feedback in most agentic systems is either noted-and-forgotten or wired into a slow fine-tuning loop. Neither is a good fit for the operator running a real product on a real timeline. The lessons pipeline gives that operator a third path: capture the correction, cluster the pattern, ship a concrete artifact through a named gate. The artifact — a new skill, a lesson, a fixture, a code change — is the smallest unit of "the system got better," and every one of them is attributable in future drift readings.

The gate is the point Nothing published in this pipeline ships without a named approver on record. A rejected draft leaves an audit trail; an approved one does too. The gate is what makes this pipeline safe to run against production behavior.

How to use it

1. Record an override

When a human corrects the system, capture both sides:

POST /hil/override
x-holonograph-run-mode: production
Content-Type: application/json

{
  "agentId": "billing-triage",
  "surfaceId": "classify-intent",
  "correlationId": "corr_01H...",
  "originalOutput": { /* what the system produced */ },
  "correctedOutput": { /* what the human sent instead */ },
  "rationale": "Refund lookup wasn't invoked; agent guessed.",
  "tags": ["fix_tier=tool-input-schema"]
}

Response: an eventId. The override is now in the substrate, tagged and correlated with the original call.

2. Cluster overrides over a window

Run the clustering endpoint to group similar overrides — usually on a schedule (nightly), sometimes on-demand when an operator wants to see what's been building up.

POST /lessons/cluster
x-holonograph-run-mode: production
Content-Type: application/json

{
  "surfaceId": "classify-intent",
  "since": "2026-07-01T00:00:00Z",
  "until": "2026-07-05T00:00:00Z"
}

Response: clusters[] plus a total eventCount. Each cluster carries its member override ids and a summary shape the drafter can consume.

3. Draft a corrective artifact

Ask the drafter to propose an artifact for a cluster. Pick the kind that fits:

KindWhen it fits
skillThe agent needs a new capability it doesn't currently have.
lessonThe agent has the capability but keeps using it wrong. A prompt-level correction is enough.
fixtureThe correction should be a reproducible check, so future regressions get caught before shipping.
code-change-recommendationThe problem lives in code (tool schema, dispatch logic) and needs a developer to fix.
POST /lessons/draft
x-holonograph-run-mode: production
Content-Type: application/json

{
  "kind": "fixture",
  "cluster": { /* cluster payload from the previous step */ },
  "parentSurfaceId": "classify-intent",
  "seedEventId": "evt_01H..."
}

For fixture drafts, provide either a seedEventId (a real event to base the fixture on) or a seedRawRequest (a hand-authored request shape). Optionally supply a parentFixtureId if this fixture should stack on an existing one.

Response: a draft object, an optional classification label the drafter applied, and an enqueued flag reflecting whether the draft was queued for the gate.

4. Approve or reject at the gate

Approve:

POST /hil/approve
Content-Type: application/json

{
  "draftId": "draft_01H...",
  "approverId": "brian",
  "comment": "Correction verified against the surface's rules. Approving."
}

Reject (a comment is required — the record of why matters):

POST /hil/reject
Content-Type: application/json

{
  "draftId": "draft_01H...",
  "approverId": "brian",
  "comment": "This one's not a pattern — the customer was testing us. Discarding."
}

Both endpoints return the current status and a history[] of the actions taken on this draft so far.

5. Publish

Once approved, publish the draft to make it live. Provide any existing lessons the publisher should consider superseding — the publisher will merge/replace/link as appropriate.

POST /lessons/publish
Content-Type: application/json

{
  "draftId": "draft_01H...",
  "candidateExistingLessonIds": ["lesson_01G..."]
}

Response: a publish report naming the new artifact id, any superseded artifacts, and the substrate event the publish itself produced.

Re-run a published fixture

Once a fixture is live, you can re-run it any time against its parent surface:

POST /fixtures/rerun
Content-Type: application/json

{ "fixtureId": "fx_01H..." }

Response includes the actual result the run produced and the expected[] assertions the fixture carries — the diff between the two is your regression signal.

Reading the output

Published artifacts become substrate. That means they show up as their own events, they get versioned, and — crucially — future drift readings can point at "this artifact was published on Tuesday" as a candidate explanation for a movement in the numbers.

The pipeline is recursive by construction. The drafter's own model call passes through the lens, so the act of proposing a correction is itself observed. Getting better is a measured event.

Reference

Endpoints

Method & pathPurpose
POST /hil/overrideRecord a human override on a captured event.
POST /lessons/clusterCluster overrides in a window.
POST /lessons/draftAsk the drafter to propose a corrective artifact for a cluster.
POST /hil/approveApprove a draft at the gate.
POST /hil/rejectReject a draft at the gate (comment required).
POST /lessons/publishPublish an approved draft as substrate.
POST /fixtures/rerunRe-run a published fixture against its parent surface.

POST /hil/override — request

FieldShapeNotes
agentIdstring (req)The agent this override applies to.
surfaceIdstring (opt)The surface, when known.
correlationIdstring (opt)Ties the override to the original call.
tagsstring[] (opt)Cohort tags — fix_tier=…, severity=…, and any other identifiers that will help clustering later.
originalOutputobject (req)What the system produced.
correctedOutputobject (req)What the human sent instead.
rationalestring (opt)Human explanation of the correction.
activeArtifactsarray (opt)Which lessons / fixtures were active at the time of the original call.

POST /lessons/draft — request

FieldShapeNotes
kindenum (req)skill, lesson, fixture, or code-change-recommendation.
clusterobject (req)Payload from /lessons/cluster.
enqueueboolean (opt)Queue the draft for the gate immediately. Default true.
parentSurfaceIdstringRequired for fixture drafts.
seedEventIdstring (opt)For fixture: base the fixture on a real event.
seedRawRequestobject (opt)For fixture: hand-authored request shape when there's no seed event.
parentFixtureIdstring (opt)For fixture: stack this fixture on an existing one.