Core artifacts
- AgInput
- The input envelope — a discriminated union on kind (start, resume, tool-result, …) that carries what the client sends into a run.
- AgEvent
- The streaming event unit. Every event on the wire is an AgEvent; its type discriminant follows the dot rule (below) to say whether it's a stream event or a content block.
- AgMessage
- The persisted message object — a role plus a content record. Opened by a message.start event and sealed by message.end.
- AgReduceResult
- Messages + artifacts + state + turn records — the object graph that reduce() (below) folds an AgEvent stream into.
The containment tree
- thread
- The conversation root, identified by threadId. Every entity in AgJSON carries the root threadId so it's addressable without walking the containment chain.
- turn
- One exchange, identified by turnId. A subagent is just a nested turn — a full turn with its own turnId and a parentTurnId pointing at the enclosing turn.
- step
- One loop iteration inside a turn.
- message
- The role + content record for one AgMessage, opened by message.start.
- block
- A content unit inside a message — text, image, reasoning, and so on. A wire type with no dot is a block (see the dot rule).
- tool-call / tool-result
- A tool invocation and its result. The BLOCK is tool-result (dotless — a persisted content unit); the finalizing EVENT is tool.done (dotted — it carries the tool-result onto the wire).
- artifact
- A side-channel landing zone for turn-scoped output — deliberately not an AgBlock.
- source
- A grounding source (e.g. a citation or retrieval result) attached to a turn.
Vocabulary — one word per concept
- reasoning
- A model's chain-of-thought content. Never called "thinking" on the wire — one word, one concept.
- hitl
- The human-in-the-loop family of events — anything where a run pauses for a human decision.
- ask / answer
- The HITL request/response pair. ask materializes as the hitl.ask event; answer materializes as the AgHitlAnswer resume payload. There is no hitl.answer wire type.
- opaque
- A provider-bound verifiable blob — e.g. a reasoning signature — that a client carries but never inspects or re-derives.
- paused
- A within-run wait. The word "interrupt" is purged everywhere in AgJSON, including async-tool scheduling, which uses preempt instead.
- surface
- An A2UI / MCP-Apps / OpenAI-Apps live render target. Surfaces are ephemeral — they're never folded into AgReduceResult.
- surface-interaction
- A client→server surface message (AgSurfaceInteraction) — the un-merged, per-spec-faithful successor of the old merged AgUiAction. A different axis from the hitl pause.
Mechanics
- Normalizer
- A stateful, per-invoke object with exactly two operations: push(native) → AgEvent[] to ingest one native framework event, and flush() → AgEvent[] to close dangling state at stream end.
- reduce()
- The normative fold from an AgEvent stream into an AgReduceResult — the reference implementation of "what a client should end up holding."
- the dot rule
- A wire type containing a dot is a streaming EVENT; a wire type with no dot is a content BLOCK (with three enumerated bare-noun exceptions: error, source, handoff). This one rule tells a reader what they're looking at with no other context.
- Layer-A / Layer-B
- AgJSON is Layer-A: it carries content and interaction anchors only. Rendering is Layer-B, owned entirely by MCP Apps and A2UI — AgJSON defines zero component schema and zero render layer of its own.
- the triple-id rule
- Every entity carries three ids: its own id, its immediate parent's id, and the root threadId — so any unit is persistable and reconnectable without walking the chain.