Conformance
read as.md An implementation is ggui-conformant iff it passes the conformance kit — a fixture-based test suite a candidate runs against. Opinion, intent, and prose-level reading of this site are NOT the arbiter; the kit is.
This page describes what the ggui protocol promises in exchange for the name “protocol”, what each contract inside it must satisfy, and how the kit makes those promises observable.
What conformance means
Section titled “What conformance means”Conformance for ggui means three concrete things:
- A third-party implementation can replace the first-party one — agents, hosts, and ops tools that work against the OSS
ggui servework against the third-party server too, without source-level changes. - Every named failure mode produces an observable signal — operators see violations without running a debugger.
- Every breaking change to the protocol is reproducible — “is this PR breaking?” resolves to a kit run, not a debate.
If a layer that calls itself a “protocol” can’t honor these three promises, the layer is something else (a shape, an SDK feature, an author convention) and should be named accordingly.
The Contract Bar — 4 criteria
Section titled “The Contract Bar — 4 criteria”A runtime contract in ggui MUST satisfy all four. Three of four is not a contract. Documenting a fourth in prose without mechanism is not a contract.
1. Named parties
Section titled “1. Named parties”The contract states WHO is on each side. Not “producer” and “consumer” in the abstract — the concrete roles. The ggui_runtime_submit_action handler and the consume-buffer pipe. The iframe-runtime and the render-channel server. The contract author and the platform validator. If you can’t name the parties in one sentence, there is no contract — only a data type adrift.
- ✅ “The
ggui_runtime_submit_actionhandler appends every validkind: 'dispatch'envelope to the render-keyed pending-events pipe; the agent drains it viaggui_consume.” - ❌ “Clients should respect the ordering semantics.”
2. Explicit obligations per party
Section titled “2. Explicit obligations per party”Each party has a list of MUSTs and MUST-NOTs. SHOULDs are discipline, not contract — a SHOULD belongs in a style guide. The obligations must be specific enough that a reviewer can literally check a diff against them.
- ✅ “Agent-authored
streamSpecMUST NOT declare a channel whose name starts with_ggui:.” - ❌ “Handlers should behave predictably.”
An obligation without a verifiable test is a hope, not a contract.
3. Defined failure mode per obligation
Section titled “3. Defined failure mode per obligation”When the obligation breaks, there is a named, typed, observable failure. Generic throw new Error() is not a failure mode. console.warn() is not a failure mode. “Log the outcome to telemetry and carry on” is not a failure mode.
Acceptable mechanisms:
- A canonical error-code union (
CONTRACT_VIOLATION,SESSION_NOT_FOUND,SCHEMA_MISMATCH_ERROR, the runtime-tool rejection codesINVALID_ACTION_KIND/PIPE_NOT_FOUND/CONTEXT_TOO_LARGE). - A typed rejection frame the caller receives on the call that caused it (e.g. a
CONTRACT_VIOLATIONerror frame on the live channel, or a{ok:false, code}structuredContentrejection on a runtime tool). - Boot-time refusal with a message naming the offender (e.g. mount tool-name collision).
- Compile-time impossibility (the type has no field → consumers can’t read it).
Unacceptable: silent noop, silent degradation, swallowed exception, “it’ll surface in the next call if it’s a real problem.”
4. Observable violation
Section titled “4. Observable violation”An operator can see the violation without running a debugger. Surfaces:
- An error envelope/frame the caller observes synchronously (the gold standard — a
CONTRACT_VIOLATIONerror frame on the live channel when an inbound action violates the contract). - A validation response the caller receives synchronously.
- An operator UI that reads the above.
- A structured log emitted at a known event name, documented as the contract’s telemetry point.
A contract whose violations only show up in production stack traces fails this bar — an operator who inherits the system in six months can’t tell what’s working and what’s silently degraded.
The Protocol Bar — 6 criteria
Section titled “The Protocol Bar — 6 criteria”A protocol is the emergent layer above a set of contracts. Every layer called “a protocol” MUST satisfy all six. Five of six is a protocol-in-progress; the gap MUST be flagged explicitly and the layer treated as experimental until closed.
1. Wire-format specification
Section titled “1. Wire-format specification”A canonical prose spec describing every envelope shape, every field, every value constraint, and — critically — every intentional omission and why. Not just TypeScript types. Types say the shape; the spec says the semantics.
For ggui, this lives in the site-level wire references — Envelopes, MCP Protocol, WebSocket Protocol — which document every envelope shape, field, and intentional omission.
2. Message sequencing and state
Section titled “2. Message sequencing and state”Given envelope X at time T in state S, which transitions are legal? What happens on reconnect? On resume? On concurrent emission? Crash recovery? Out-of-order delivery?
A protocol without sequencing is a data type with pretensions. ggui’s sequencing lives in the three-channel topology + the GguiSessionStreamBuffer interface + the fromSeq replay contract. Any new channel or envelope class MUST answer the sequencing question explicitly.
3. Version negotiation
Section titled “3. Version negotiation”Producer and consumer MUST be able to agree on what version they speak, or explicitly refuse. Stamping a version on every envelope is infrastructure; actually rejecting a mismatched peer is the protocol feature. Pre-launch “advisory stamp only” is acceptable IF the launch-cutover plan names the policy flip (producer-stamp + consumer-reject).
Anti-pattern: calling version-stamping “versioning” and shipping. See Version policy for the post-launch handshake semantics.
4. Conformance testability at the seam
Section titled “4. Conformance testability at the seam”A third-party implementer can verify their implementation without running the ggui server. This means:
- A public fixture table of envelopes and expected behaviors.
- An executable conformance kit (a test package a third party
pnpm adds and runs). - Coverage of every canonical failure mode — a third-party implementation that passes the kit can be used interchangeably with the first-party one.
Without this, “third party adopts the protocol” means “third party reads the spec and hopes.”
5. Named failure modes — closed, or extensibly-closed
Section titled “5. Named failure modes — closed, or extensibly-closed”Every way the protocol can fail has a name, a code, and a shape. Acceptable forms:
- Closed union — exhaustive by design. Bumping requires a major version bump. Use when the set of values is fixed by an external spec or by a pre-launch design decision the protocol owners control end-to-end.
- Extensibly-closed — e.g. the
channel_errorcode union'CHANNEL_UNKNOWN' | 'SESSION_NOT_FOUND' | 'SUBSCRIBE_UNAUTHORIZED' | 'POLL_FAILED' | (string & {}), or the opencode: stringon the WSerrorframe whose canonical literals includeCONTRACT_VIOLATIONandUPGRADE_REQUIRED. Consumers MUST handle unknown values gracefully. Adding new values does NOT bump the protocol version. Use when producer-side failure modes are expected to grow (new tool classes, new transports, new preconditions) without consumers needing a new version to render them.
Unacceptable: ad-hoc message: string as the only failure surface.
6. Vendor-neutral separation from implementation
Section titled “6. Vendor-neutral separation from implementation”The protocol package imports nothing from a specific runtime, transport, cloud vendor, or framework. @ggui-ai/protocol MUST remain consumable by a third-party implementation that has never seen @ggui-ai/mcp-server.
Violation of this criterion is the loudest signal that what you have is an SDK feature pretending to be a protocol.
The conformance kit
Section titled “The conformance kit”The kit lives at packages/protocol-conformance in the open repo — a fixture-based test suite a candidate implementation runs against to demonstrate conformance.
pnpm add -D @ggui-ai/protocol-conformanceBeyond the WS runner, the package ships pure-function catalogs for the gadget obligations — schema, registration, and resolution conformance — importable from @ggui-ai/protocol-conformance/{schema-conformance,registration-conformance,resolution-conformance}; the raw fixture catalog is also exported at @ggui-ai/protocol-conformance/fixtures.
Programmatic and CLI entry points:
import { runConformance } from "@ggui-ai/protocol-conformance";
const result = await runConformance({ serverUrl: "http://localhost:3000", auth: { kind: "bearer", token: process.env.TOKEN! },});
if (result.failed.length > 0) process.exit(1);npx ggui-protocol-conformance --url http://localhost:3000 --auth bearer:$TOKENserverUrl / --url take the implementation’s base http:// / https:// URL — the runner appends /ws and derives the ws:// / wss:// scheme itself.
Transport. v1.0 is WebSocket-only — the canonical ggui transport (see the WebSocket Protocol reference). The kit’s TransportConfig is an extensibly-closed union, so later bindings (stdio MCP, HTTP long-poll) can be added post-v1.1 without breaking the public API.
Path-A vs Path-B fixtures. The fixture catalog spans both wire-observable claims and surface-observable claims. The runner handles Path-A — behaviors a runner can assert from WS frames alone (no MCP-Apps-host adapter, no Playwright). Path-B fixtures (e.g., bootstrap-failure, props-update) require a browser-host harness driving Playwright + page.route() fault injection + DOM assertion; they are recorded as SKIP on the WS runner, not FAIL. The partition is intentional: Path-A FAILs are vendor-neutrality bugs the server owns; Path-B SKIPs are claims a different driver is responsible for.
The kit covers:
- Envelope round-trip — every fixture in the table can be emitted, observed, validated, and round-tripped.
- Reserved-channel authority — the implementation rejects agent-authored
streamSpecentries in the_ggui:namespace and validates the platform-owned shapes (_ggui:preview,_ggui:lifecycle). - Schema enforcement —
actionSpec[action].schema⊆ the hinted tool’sinputSchema, with aSCHEMA_MISMATCH_ERRORpush-time rejection on violation. - Sequencing —
seqis gap-free per-session,fromSeqreplay returns the right tail,replayTruncatedis honored when the requested cursor is unrecoverable. - Version handshake — schema-version stamping on every envelope;
UPGRADE_REQUIREDemission on mismatch (post-launch — pre-launch is advisory). - Action persistence — an action frame round-trips to an ack carrying
payload.sequence, proving the event landed on the GguiSession’s consume buffer (append-then-ack). - Contract enforcement at receipt — an action for an undeclared name is rejected with a
CONTRACT_VIOLATIONerror frame and nothing reaches the consume buffer.
A change is breaking iff at least one fixture that passed against version N now fails against version N+1 when the only change is the protocol version. See Version policy → §2 for the policy this anchors.
Pre-launch vs launch posture
Section titled “Pre-launch vs launch posture”Pre-launch (draft- versions), some protocol criteria are intentionally at ⚠️ — flagged gaps with owners and closing slices. The point is not zero gaps forever; it is zero silent gaps.
| Criterion | Pre-launch posture | Launch (v1.0) |
|---|---|---|
| Version negotiation | Envelope schemaVersion: advisory stamp; consumers MUST NOT reject on mismatch. Subscribe handshake (supportedVersions / serverVersion): server default versionPolicy: 'reject' — emits UPGRADE_REQUIRED and closes; 'advisory' is a legacy opt-out for migration windows. | Same mechanisms; envelope stamps stay advisory, the subscribe handshake stays the rejection point. Mismatched majors surface as UPGRADE_REQUIRED. |
| Conformance kit | Optional today; available for first-party servers + early third-party implementers. | Required before third-party implementers are invited to build on the protocol. |
| Schema-compat checker | Render-time + console blueprint-try (SCHEMA_MISMATCH_ERROR rejection on the ggui_render tool result); operator policy 'reject' | 'warn' | 'off' (default 'reject'). | Same; default unchanged. |
At launch, all load-bearing boundaries MUST be at 4/4 contract + 6/6 protocol for any layer described as a public interop surface. Load-bearing = any boundary a third-party implementer is expected to adopt. Internal-only boundaries may sit at lower scores if the gap is explicitly scoped to internal use.
Anti-patterns
Section titled “Anti-patterns”Things that feel contract-shaped but fail the bar:
| Looks like | Is actually | Why |
|---|---|---|
| ”TypeScript type is the contract” | Shape-only | Types say what, not who/when/what-on-violation |
| ”Docstring says MUST” | Author discipline | Prose without mechanism decays |
| ”A validator function exists” | Half-contract | Validator without observable failure path wastes the check |
| ”Error gets logged” | Not observable | Logs aren’t observability unless somebody reads them |
| ”Pre-launch advisory” | Infrastructure, not contract | Valid interim stance; MUST flag the gap + name the flip |
| ”We cover the common cases” | Denylist discipline | Rock-paper-scissors with future adversaries |
| ”Three similar implementations agree” | Folklore | Interop-by-intuition is not interop |
If a new “contract” maps to a row here, either strengthen it to meet the bar or pick a different word.
Vocabulary
Section titled “Vocabulary”Used precisely throughout this site:
- Shape — a TypeScript type with no enforcement story.
- Convention — author discipline; no mechanism.
- Contract — passes the 4-criterion bar.
- Protocol — passes the 6-criterion bar; a set of contracts with sequencing + versioning + conformance-kit.
If a doc says “this contract is enforced by convention” — that’s a category error and either the contract framing or the convention framing is wrong.
See also
Section titled “See also”- Protocol overview — three-channel topology and reference implementation.
- Version policy — semver semantics, breaking-change definition, deprecation timeline.
- Envelopes — wire shapes the conformance kit asserts on.
- Conformance kit on GitHub — the test package itself.