Skip to content

Grounded Answers,
Not Guesses

Every answer traces to retrieved evidence in the assistant's memory and is cited back to its source. When the assistant can't find grounded evidence, it says so instead of guessing, and files the gap for the content team to resolve.

G

GreenHaven Assistant

Product advisor

grounded
Do you have anything for full shade?
Yes. The Hosta 'Blue Mouse Ears' is rated for full to partial shade and stays compact, which suits shaded borders and containers.
PLT-001Hosta 'Blue Mouse Ears'shop:products
4 evidence retrieved · 1 citation validated
25unit tests
42eval assertions
18/20/22Node CI matrix
0API keys to run
completion mode offline-rule-based

Real suite from the repo: node --test across chat-core, statewave-core, and server, green on every Node version in CI.

Why Statewave

Two Outcomes, Both Leave a Trace

Grounding is enforced by the memory runtime, not the prompt. Either an answer survives citation validation, or the question becomes a coverage gap the Ops Assistant can resolve.

Grounded and cited

The model answers from retrieved evidence, and at least one citation ID survives validation.

grounded: trueevidenceCount: 4
Answer returns with citation chips. Turn appended to shop:conversations.
closed loop
!

Ungrounded → coverage gap

No evidence, or no citation survives. The assistant says it doesn't know, and the route files a gap.

ops:coverage-gapsstatus: open
A new Episode is appended. The Ops Assistant reads it as evidence and resolves it under the same sourceId.

Built So Every Claim Is Checkable

Jump to the API →

Grounded answers only

The model answers strictly from retrieved evidence, and is told to say it doesn't know rather than fill the gap with a guess.

Q

Are your terracotta pots frost-proof?

A

I don't have grounded information on frost tolerance for that item.

grounded: false · no guess emitted

Every claim is citable

Citation IDs from the model are validated against the evidence actually retrieved. Unknown IDs are dropped and flagged as a warning.

✓S1→ PLT-001kept
✓S2→ FAQ-014kept
×S9→ unknowndropped

Content gaps are an object

An ungrounded question writes a Coverage gap Episode. The Ops Assistant reads gaps beside the catalog and FAQs, so the content team fixes them from the same UI.

OPENops:coverage-gaps

"Which planters suit a rooftop weight limit?"

sourceId: GAP-2381

Append-only memory

Nothing is mutated in place. Updating a product or resolving a gap appends a new Episode with the same sourceId, so facts supersede instead of editing history.

Episode v1PLT-001
Episode v2PLT-001
Episode v3current

How It Works

One Pipeline, Episode to Citation

Source content flows through ingestion into an append-only episode store, compiles into Subjects — the durable memory both assistants read — and is served over the same completion path.

EpisodecompileSubjectgetContextgrounded completionresolveCitations

Source content

catalog.json

Product data

service-content.json

FAQs and care guides

Ingestion

ingest job

Dedups by content hash, appends Episodes

StatewaveStore

Episodes → compileSubject

Newest Episode per sourceId, persisted to db.json

Subjects → Assistants

Shopper Assistant

POST /api/chat

Ops Assistant

POST /api/ops/chat

completionFn

LiteLLM · OpenRouter · offline

The closed loop. A question the shopper assistant can't ground becomes an ops:coverage-gaps Episode the Ops Assistant reads as evidence. Resolving it appends another Episode with the same sourceId, superseding the gap instead of editing history.

One chat turn, end to end   "Do you have anything for full shade?"
1Shopper → Widget
"Do you have anything for full shade?"
2Widget → Route
POST /api/chat { sessionId, message }
3Route → Store
getContext(readSubjects, query) → evidence + IDs
4Route → completionFn
system + evidence + history → { answer, grounded, citationIds }
5Route → Store
Drops IDs not in evidence, runs resolveCitations(), appends the turn

Ops Console

The Content Team Works the Gaps

Every ungrounded question shows up in the Ops console as an open coverage gap, with the shopper's exact wording. Resolving one appends an Episode under the same sourceId, so the next shopper gets a grounded answer.

  • Open gaps carry the unanswered question verbatim
  • Resolved gaps supersede, never overwrite
  • Read over GET /api/ops/gaps
Statewave Ops · Coverage gaps3 open
Overview
Subjects
Coverage gaps
Conversations
Catalog
OPENGAP-23812 shoppers

"Which planters are safe for a rooftop with a weight limit?"

OPENGAP-23791 shopper

"Do you ship bare-root roses in winter?"

RESOLVEDGAP-2361+ Episode

"What's your return window on live plants?"

Data Model

Subjects

The compiled memory both assistants query. Each is written by exactly one path and read where it makes sense.

SubjectWritten byRead by
shop:productsingestion job (catalog.json)shopper + ops assistants
faq:serviceingestion job (service-content.json)shopper + ops assistants
content:guidesingestion job (service-content.json, guide docs)shopper assistant
ops:coverage-gapsshopper route, on an ungrounded answerops assistant, /api/ops/gaps
shop:conversationsshopper route, every turnaudit trail
ops:conversationsops route, every turnaudit trail

Developer API

A Chat Turn on the Wire

POST/api/chat · request
{
  "sessionId": "optional, generated if omitted",
  "message": "Do you have anything for full shade?",
  "readSubjects": ["optional override of the default subjects"],
  "retrievalConfig": { "globalMaxTokens": 2000 }
}
200application/json · response
{
  "answer": "...",
  "grounded": true,
  "citations": [
    { "evidenceId": "S1", "subject": "shop:products",
      "sourceId": "PLT-001", "label": "Hosta 'Blue Mouse Ears'" }
  ],
  "warnings": [],
  "evidenceCount": 4
}
i

grounded is only true when the model both claims groundedness and at least one citation survives validation against the retrieved evidence.

POST

/api/chat

Shopper-facing grounded chat turn

POST

/api/ops/chat

Ops chat turn, reads coverage gaps too

GET

/api/ops/gaps

Open and resolved coverage gaps

POST

/api/ops/gaps/:sourceId/resolve

Marks a coverage gap resolved

GET

/healthz

Liveness; reports the active completion mode

Run the Whole Loop in Two Commands

Boots with a deterministic offline responder, so grounding, citations, and the coverage-gap loop all work with zero setup. Point it at any OpenAI-compatible gateway for real generated answers.

greenhaven zsh
# Requires Node.js 18+
$ npm install
$ npm run dev
→ Storefront   http://localhost:4000/
→ Ops console  http://localhost:4000/ops.html
→ completion   offline-rule-based (no API key)

FAQ

Frequently asked questions

How does the assistant avoid inventing product facts?

Grounding is enforced by the memory runtime rather than by prompt wording. The model answers strictly from evidence retrieved out of compiled Subjects, and the citation IDs it returns are validated against the evidence actually retrieved — unknown IDs are dropped and flagged as a warning. An answer ships only if at least one citation survives validation, so "sounds plausible" is not a passing grade.

What happens when the assistant cannot ground an answer?

It says it does not know, and the route writes the question to an ops:coverage-gaps Episode carrying the shopper’s exact wording. The Ops Assistant reads those gaps beside the catalog and the FAQs, so the content team resolves them from the same console. An unanswerable question becomes a tracked object with an owner, instead of a guess that reaches a customer.

How are product updates handled without rewriting history?

Nothing is mutated in place. Updating a product or resolving a gap appends a new Episode under the same sourceId, and the newest episode per sourceId supersedes the older one at compile time — so facts change while the record of what was true when stays intact. Ingestion deduplicates by content hash, so re-running the job over an unchanged catalog writes nothing.

What does this assistant run on?

The same open-source memory runtime this site documents: append-only episodes, compileSubject, and Subjects persisted through StatewaveStore, served over one completion path shared by the shopper and ops assistants. Completions route through LiteLLM or OpenRouter, and an offline mode runs the flow with no provider at all. Its test suite is node --test across chat-core, statewave-core, and server, green on every Node version in CI.

Answers last checked against the Statewave docs and repositories on .

START BUILDING

Ground your shopping assistant

Every answer traced to evidence, every gap filed automatically. Clone the repo and see the whole loop run offline in minutes.