Protocol for Agentic Semantic Hypermedia — LLM-agnostic UI protocol
v1.1.0 MIT License 224 tests
The AI doesn't write markup. It sends intent. The client renders.
PASH is a token-efficient text format for transmitting UI components from LLMs to clients.
<div class="product-card"><h3>Смартфон X1</h3><p>AMOLED 120Hz</p>
<span class="price">69 990 ₽</span><button>Купить</button></div>
1|Смартфон X1|AMOLED 120Hz|69990|Купить
Your client knows 1 = ProductCard, renders it with your CSS, your locale, your design system.
npm install pash-sdk @pash/prompt
const { PromptEngine } = require('@pash/prompt');
const { SCHEMAS } = require('pash-sdk');
const engine = new PromptEngine({ schemas: SCHEMAS });
const system = engine.generate({ lang: 'ru', mode: 'pash' });
// Auto-generated from your component registry. Always in sync.
const { decodeStream, renderStream } = require('pash-sdk');
const aiResponse = `
1|Смартфон X1|AMOLED 120Hz, 256GB|69990|Купить
2|warn|Последний в наличии
`;
const decoded = decodeStream(aiResponse);
// { version: null, components: [ ProductCard, Notification ] }
document.getElementById('output').innerHTML = renderStream(decoded);
const { StreamingDecoder, renderComponent } = require('pash-sdk');
const decoder = new StreamingDecoder((component) => {
document.getElementById('output').innerHTML += renderComponent(component);
});
const response = await fetch('/api/ai');
const reader = response.body.getReader();
const utf8 = new TextDecoder();
while (true) {
const { done, value } = await reader.read();
if (done) { decoder.flush(); break; }
decoder.push(utf8.decode(value));
}
COMP_ID|field1|field2|field3|...
| — separator (1 BPE token in GPT-4, LLaMA-3)\| — escaped pipe inside a value# — nested component prefixv:1 — optional version header (first line)\n — component separator| Format | Tokens | vs HTML |
|---|---|---|
| HTML | ~52 | — |
| JSON | ~34 | −35% |
| Markdown | ~26 | −50% |
| PASH | ~11 | −79% |
| PASH+ID | ~7 | −87% |
| ID | Component | Fields |
|---|---|---|
| 1 | ProductCard | title* | desc | price[currency] | cta |
| 2 | Notification | level*(info|warn|error) | message* |
| 3 | List | title | items* |
| 4 | Hero | headline* | sub | cta |
| 5 | Article | title* | author | date | summary |
| 6 | RichBlock | content*[richtext] |
| ID | Block | Fields |
|---|---|---|
| 20 | Heading | level*(1-6) | text* |
| 21 | Paragraph | text*[richtext] |
| 22 | Code | lang | body* |
| 23 | Blockquote | author | text*[richtext] |
| 24 | Image | url* | alt | caption |
| 25 | Divider | — |
| 26 | Table | headers* | rows* |
| 27 | OrderedList | title | items* |
| 28 | BulletList | title | items* |
| 29 | Note | level*(info|tip|warn|danger) | text* |
| 30 | Spoiler | title* | body*[richtext] |
| 31 | Math | display*(block|inline) | formula* |
| 32 | Embed | type*(youtube|...) | url* | title |
* = required. ID 40+ available for custom components.
| Mode | Example | Tokens |
|---|---|---|
pash | 1|Смартфон X1|AMOLED|69990|Купить | ~11 |
pash+id | 1|102|45|69990|12 | ~7 |
events | COMP_START(1)\nTEXT(Смартфон X1)... | similar |
const { registerComponent } = require('pash-sdk');
registerComponent(40, {
name: 'UserCard',
fields: [
{ id: 0, type: 'string', label: 'name', required: true },
{ id: 1, type: 'string', label: 'email' },
],
render: (f) => `<div class="user-card"><b>${f.name}</b><span>${f.email}</span></div>`,
});
// AI can now generate: 40|Иван Петров|ivan@example.com
const { setLocale } = require('pash-sdk');
setLocale('en-US'); // price: 69990 → $69,990
setLocale('de-DE'); // price: 69990 → 69.990 €
setLocale('ru-RU'); // price: 69990 → 69 990 ₽ (default)
decodeStream parseLine encode encodeStream renderComponent renderStream StreamingDecoder EventStreamDecoder Dictionary setLocale addLocale validateStream registerComponent SCHEMAS VERSION
PASH v1.1.0 · MIT License · Copyright (c) 2026 Sergei