Primitives Overview
Grain defines 10 core primitives. Companion elements like <result>, <progress>, <warning>, <action>, and <option> round out the language contract.
The 10 Core Primitives
| Primitive | Purpose |
|---|---|
| Stream | Real-time text streaming |
| Think | AI reasoning display |
| Tool | Function/tool execution |
| Artifact | Code, images, documents |
| Input | User input collection |
| Context | Files, URLs, memory |
| State | Global AI status |
| Error | Failure handling |
| Approve | Human-in-the-loop |
| Branch | Conversation forks |
Composition
Primitives compose into complex interfaces:
grain
<message role="assistant">
<think model="chain-of-thought" visible="false">
User asks about weather. I should call the weather tool.
</think>
<stream>Let me check...</stream>
<tool name="get_weather" status="running" />
</message>
<tool name="get_weather" status="complete">
<result temperature="28" condition="sunny" />
</tool>
<message role="assistant">
<stream>28°C and sunny!</stream>
</message>This is the core Grain idea: a model or agent can move between reasoning, streaming, tool execution, and final response without leaving the same document contract.
State Machines
Every primitive has explicit states:
STREAM: IDLE → GENERATING → COMPLETE
↓
PAUSED
TOOL: PENDING → RUNNING → COMPLETE
↓
ERROR
APPROVE: PENDING → SHOWING → APPROVED/DENIEDEvents
Each primitive emits events:
stream.start,stream.chunk,stream.completetool.start,tool.progress,tool.complete,tool.errorthink.reveal,think.hideapprove.request,approve.approve,approve.deny
Companion Elements
Core primitives often carry smaller semantic companions:
<result>for structured tool output<progress>for long-running work<warning>for user-facing cautions<option>for approval choices<suggestion>for input affordances
Extending
Add custom primitives:
javascript
adapter.registerPrimitive('my-chart', {
render: (props) => `<div class="my-chart">...</div>`
});When extending Grain, keep the public contract narrow. The documented primitives should stay stable while custom behavior lives behind explicit extensions.
Next
- Stream Primitive — Real-time text
- Tool Primitive — Function calls
- G-Lang Syntax — How to write primitives