diff --git a/astro.config.mjs b/astro.config.mjs
index 48cb578..eaeee30 100644
--- a/astro.config.mjs
+++ b/astro.config.mjs
@@ -172,6 +172,9 @@ export default defineConfig({
label: 'Reference',
items: [
{ label: 'Flow YAML Schema', slug: 'reference/flow-schema' },
+ { label: 'Flow Node Kinds', slug: 'reference/flow-node-kinds' },
+ { label: 'Channel Data Access', slug: 'reference/channel-data-access' },
+ { label: 'Secret Seeding', slug: 'reference/secret-seeding' },
{ label: 'Pack Format', slug: 'reference/pack-format' },
{ label: 'WIT Interfaces', slug: 'reference/wit-interfaces' },
{ label: 'Configuration', slug: 'reference/configuration' },
diff --git a/src/content/docs/components/cards2pack.mdx b/src/content/docs/components/cards2pack.mdx
index 1900c29..d03cbd1 100644
--- a/src/content/docs/components/cards2pack.mdx
+++ b/src/content/docs/components/cards2pack.mdx
@@ -14,6 +14,18 @@ import { Aside, Steps } from '@astrojs/starlight/components';
- Auto-translates cards via `greentic-i18n-translator`
- Packages everything into a deployable `.gtpack`
+
+
## Installation
```bash
diff --git a/src/content/docs/de/components/cards2pack.mdx b/src/content/docs/de/components/cards2pack.mdx
index 89284f4..d03cbd1 100644
--- a/src/content/docs/de/components/cards2pack.mdx
+++ b/src/content/docs/de/components/cards2pack.mdx
@@ -1,18 +1,30 @@
---
title: cards2pack
-description: Adaptive Cards in Greentic-Packs umwandeln
+description: Convert Adaptive Cards to Greentic packs
---
import { Aside, Steps } from '@astrojs/starlight/components';
-## Überblick
+## Overview
-**cards2pack** ist ein CLI-Tool, das Adaptive-Card-JSON-Dateien in Greentic-Packs umwandelt. Es:
+**cards2pack** is a CLI tool that converts Adaptive Card JSON files into Greentic packs. It:
-- Scannt Karten, erstellt einen Abhängigkeitsgraphen und generiert `.ygtc`-Flows
-- Extrahiert übersetzbare Zeichenketten für i18n
-- Übersetzt Karten automatisch über `greentic-i18n-translator`
-- Verpackt alles in ein bereitstellbares `.gtpack`
+- Scans cards, builds a dependency graph, generates `.ygtc` flows
+- Extracts translatable strings for i18n
+- Auto-translates cards via `greentic-i18n-translator`
+- Packages everything into a deployable `.gtpack`
+
+
## Installation
@@ -20,18 +32,18 @@ import { Aside, Steps } from '@astrojs/starlight/components';
cargo install greentic-cards2pack
```
-Erforderliche Tools:
+Required tools:
```bash
cargo install greentic-flow greentic-pack
cargo install greentic-i18n-translator # optional, for --auto-translate
```
-## Schnellstart
+## Quick Start
-1. **Adaptive Cards erstellen**
+1. **Create Adaptive Cards**
```json title="cards/welcome.json"
{
@@ -51,7 +63,7 @@ cargo install greentic-i18n-translator # optional, for --auto-translate
}
```
-2. **Pack generieren**
+2. **Generate pack**
```bash
greentic-cards2pack generate \
@@ -60,7 +72,7 @@ cargo install greentic-i18n-translator # optional, for --auto-translate
--name my-pack
```
-3. **Ausgabe**
+3. **Output**
```
my-pack/
@@ -73,61 +85,61 @@ cargo install greentic-i18n-translator # optional, for --auto-translate
-## CLI-Referenz
+## CLI Reference
### `generate`
-Hauptbefehl: Karten scannen, Flows generieren, Pack bauen.
+Main command — scan cards, generate flows, build pack.
```bash
greentic-cards2pack generate [OPTIONS]
```
-| Flag | Beschreibung |
+| Flag | Description |
|------|-------------|
-| `--cards
` | Verzeichnis mit Adaptive-Card-JSON-Dateien (erforderlich) |
-| `--out ` | Ausgabeverzeichnis für den Workspace (erforderlich) |
-| `--name ` | Pack-Name (erforderlich) |
-| `--strict` | Fehler bei fehlenden Zielen, Duplikaten und ungültigem JSON |
-| `--group-by ` | Flow-Gruppierung: `folder` oder `flow-field` |
-| `--default-flow ` | Standard-Flow-Name für nicht gruppierte Karten |
-| `--prompt` | Prompt-basierte Weiterleitung aktivieren (fügt `prompt2flow`-Knoten hinzu) |
-| `--prompt-json ` | Answers-JSON für Prompt-Weiterleitung (erfordert `--prompt`) |
-| `--auto-translate` | Karten automatisch mit bis zu 8 parallelen Threads übersetzen (erfordert `greentic-i18n-translator`) |
-| `--langs ` | Kommagetrennte Sprachcodes; weglassen, um in alle über 65 unterstützten Locale-Varianten zu übersetzen |
-| `--glossary ` | Glossar-JSON für konsistente Übersetzungen |
-| `--verbose` | Detaillierte Ausgabe ausgeben |
+| `--cards ` | Directory of Adaptive Card JSON files (required) |
+| `--out ` | Output workspace directory (required) |
+| `--name ` | Pack name (required) |
+| `--strict` | Errors on missing targets, duplicates, invalid JSON |
+| `--group-by ` | Flow grouping: `folder` or `flow-field` |
+| `--default-flow ` | Default flow name for ungrouped cards |
+| `--prompt` | Enable prompt-based routing (adds `prompt2flow` node) |
+| `--prompt-json ` | Answers JSON for prompt routing (requires `--prompt`) |
+| `--auto-translate` | Auto-translate cards with up to 8 parallel threads (requires `greentic-i18n-translator`) |
+| `--langs ` | Comma-separated language codes; omit to translate to all 65+ supported locales |
+| `--glossary ` | Glossary JSON for consistent translations |
+| `--verbose` | Print detailed output |
### `extract-i18n`
-Übersetzbare Zeichenketten aus Karten in ein JSON-Bundle extrahieren.
+Extract translatable strings from cards into a JSON bundle.
```bash
greentic-cards2pack extract-i18n [OPTIONS]
```
-| Flag | Beschreibung |
+| Flag | Description |
|------|-------------|
-| `--input ` | Verzeichnis mit Karten-JSON-Dateien (erforderlich) |
-| `--output ` | Ausgabe-JSON-Pfad (Standard: `i18n/en.json`) |
-| `--prefix ` | Schlüsselpräfix (Standard: `card`) |
-| `--include-existing` | Zeichenketten einschließen, die bereits `$t()`-Muster enthalten |
-| `--verbose` | Extraktionsbericht ausgeben |
+| `--input ` | Directory of card JSON files (required) |
+| `--output ` | Output JSON path (default: `i18n/en.json`) |
+| `--prefix ` | Key prefix (default: `card`) |
+| `--include-existing` | Include strings that already contain `$t()` patterns |
+| `--verbose` | Print extraction report |
-## Kartenidentifikation
+## Card Identification
-Karten werden identifiziert über (in dieser Prioritätsreihenfolge):
-1. Das Feld `greentic.cardId` im Karten-JSON
-2. Den Dateinamen ohne Endung (z. B. `welcome.json` → `welcome`)
+Cards are identified by (in order of priority):
+1. `greentic.cardId` field in the card JSON
+2. Filename stem (e.g., `welcome.json` → `welcome`)
-Karten werden gruppiert in Flows über:
-- Das Feld `flow` in den Aktionsdaten
-- `--group-by folder` (Verzeichnisstruktur)
-- Den Fallback `--default-flow`
+Cards are grouped into flows by:
+- `flow` field in action data
+- `--group-by folder` (directory structure)
+- `--default-flow` fallback
-## i18n und Auto-Übersetzung
+## i18n & Auto-Translation
-### Zeichenketten extrahieren
+### Extract strings
```bash
greentic-cards2pack extract-i18n \
@@ -136,7 +148,7 @@ greentic-cards2pack extract-i18n \
--verbose
```
-Ausgabe:
+Output:
```json title="i18n/en.json"
{
@@ -147,28 +159,28 @@ Ausgabe:
```
-### Extrahierte Feldtypen
+### Extracted field types
-| Feld | Quelle |
+| Field | Source |
|-------|--------|
-| `text` | Inhalt von TextBlock |
-| `title` | Aktionstitel, Kartentitel, Toggle-Titel |
-| `label` | Labels von Eingaben |
-| `placeholder` | Platzhalter von Eingaben |
-| `errorMessage` | Validierungsfehler |
-| `altText` | Alternativtext für Bilder |
-| `fallbackText` | Fallback-Inhalt |
-| FactSet `title`/`value` | Fact-Einträge |
-| ChoiceSet `title` | Auswahloptionen |
-
-### Auto-übersetzen (ein Befehl)
+| `text` | TextBlock content |
+| `title` | Action titles, card titles, toggle titles |
+| `label` | Input labels |
+| `placeholder` | Input placeholders |
+| `errorMessage` | Validation errors |
+| `altText` | Image alt text |
+| `fallbackText` | Fallback content |
+| FactSet `title`/`value` | Fact entries |
+| ChoiceSet `title` | Choice options |
+
+### Auto-translate (one command)
```bash
greentic-cards2pack generate \
@@ -179,7 +191,7 @@ greentic-cards2pack generate \
--langs fr,de
```
-Dies extrahiert Zeichenketten aus den ursprünglichen Kartendateien, übersetzt sie über `greentic-i18n-translator` mit bis zu 8 parallelen Threads und bündelt alles:
+This extracts strings from the original card files, translates via `greentic-i18n-translator` using up to 8 concurrent threads, and bundles everything:
```
my-pack/assets/i18n/
@@ -189,12 +201,12 @@ my-pack/assets/i18n/
```
-### Glossar
+### Glossary
-Verwende ein Glossar, um Markennamen und technische Begriffe konsistent zu halten:
+Use a glossary to keep brand names and technical terms consistent:
```json title="glossary.json"
{
@@ -210,9 +222,9 @@ greentic-cards2pack generate \
--glossary glossary.json
```
-## Flow-Generierung
+## Flow Generation
-Generierte Flow-Abschnitte werden in Marker eingeschlossen:
+Generated flow sections are wrapped in markers:
```yaml
# BEGIN GENERATED (cards2pack)
@@ -222,18 +234,18 @@ Generierte Flow-Abschnitte werden in Marker eingeschlossen:
# Developer space below (preserved on regen)
```
-Inhalte außerhalb der Marker bleiben erhalten, wenn du erneut generierst.
+Content outside the markers is preserved when you regenerate.
-### Strikter Modus
+### Strict mode
-Mit `--strict`:
-- Verursachen fehlende Routing-Ziele Fehler (statt Stub-Knoten)
-- Verursachen doppelte `cardId`-Werte Fehler
-- Verursacht ungültiges JSON Fehler
+With `--strict`:
+- Missing route targets cause errors (instead of stub nodes)
+- Duplicate `cardId` values cause errors
+- Invalid JSON causes errors
-## Template-Variablen
+## Template Variables
-Verwende Handlebars-Syntax für dynamische Inhalte:
+Use Handlebars syntax for dynamic content:
```json
{
@@ -243,10 +255,10 @@ Verwende Handlebars-Syntax für dynamische Inhalte:
```
-## Beispiel: Mehrstufiges Formular mit Übersetzung
+## Example: Multi-Step Form with Translation
```bash
# Create cards in cards/ directory, then:
@@ -260,11 +272,11 @@ greentic-cards2pack generate \
--strict
```
-Siehe das [translate-demo-Beispiel](https://github.com/greentic-ai/greentic-cards2pack/tree/master/examples/translate-demo) für eine vollständige Schritt-für-Schritt-Anleitung.
+See the [translate-demo example](https://github.com/greentic-ai/greentic-cards2pack/tree/master/examples/translate-demo) for a complete walkthrough.
-## Nächste Schritte
+## Next Steps
-- [Leitfaden zur Kartenübersetzung](/de/i18n/cards-translation/)
-- [i18n Überblick](/de/i18n/overview/)
-- [Flows-Leitfaden](/de/concepts/flows/)
+- [Cards Translation Guide](/i18n/cards-translation/)
+- [i18n Overview](/i18n/overview/)
+- [Flows Guide](/concepts/flows/)
- [Adaptive Cards Designer](https://adaptivecards.io/designer/)
diff --git a/src/content/docs/es/components/cards2pack.mdx b/src/content/docs/es/components/cards2pack.mdx
index c006b36..d03cbd1 100644
--- a/src/content/docs/es/components/cards2pack.mdx
+++ b/src/content/docs/es/components/cards2pack.mdx
@@ -1,37 +1,49 @@
---
title: cards2pack
-description: Convierte Adaptive Cards en packs de Greentic
+description: Convert Adaptive Cards to Greentic packs
---
import { Aside, Steps } from '@astrojs/starlight/components';
-## Resumen
+## Overview
-**cards2pack** es una herramienta CLI que convierte archivos JSON de Adaptive Card en packs de Greentic. Hace lo siguiente:
+**cards2pack** is a CLI tool that converts Adaptive Card JSON files into Greentic packs. It:
-- Escanea cards, construye un grafo de dependencias y genera flows `.ygtc`
-- Extrae cadenas traducibles para i18n
-- Traduce automáticamente cards mediante `greentic-i18n-translator`
-- Empaqueta todo en un `.gtpack` listo para desplegar
+- Scans cards, builds a dependency graph, generates `.ygtc` flows
+- Extracts translatable strings for i18n
+- Auto-translates cards via `greentic-i18n-translator`
+- Packages everything into a deployable `.gtpack`
-## Instalación
+
+
+## Installation
```bash
cargo install greentic-cards2pack
```
-Herramientas requeridas:
+Required tools:
```bash
cargo install greentic-flow greentic-pack
cargo install greentic-i18n-translator # optional, for --auto-translate
```
-## Inicio rápido
+## Quick Start
-1. **Crear Adaptive Cards**
+1. **Create Adaptive Cards**
```json title="cards/welcome.json"
{
@@ -51,7 +63,7 @@ cargo install greentic-i18n-translator # optional, for --auto-translate
}
```
-2. **Generar el pack**
+2. **Generate pack**
```bash
greentic-cards2pack generate \
@@ -60,7 +72,7 @@ cargo install greentic-i18n-translator # optional, for --auto-translate
--name my-pack
```
-3. **Salida**
+3. **Output**
```
my-pack/
@@ -73,61 +85,61 @@ cargo install greentic-i18n-translator # optional, for --auto-translate
-## Referencia CLI
+## CLI Reference
### `generate`
-Comando principal: escanea cards, genera flows y construye el pack.
+Main command — scan cards, generate flows, build pack.
```bash
greentic-cards2pack generate [OPTIONS]
```
-| Flag | Descripción |
+| Flag | Description |
|------|-------------|
-| `--cards ` | Directorio con archivos JSON de Adaptive Card (requerido) |
-| `--out ` | Directorio de workspace de salida (requerido) |
-| `--name ` | Nombre del pack (requerido) |
-| `--strict` | Produce errores por destinos faltantes, duplicados o JSON no válido |
-| `--group-by ` | Agrupación de flows: `folder` o `flow-field` |
-| `--default-flow ` | Nombre del flow por defecto para cards sin agrupar |
-| `--prompt` | Habilita enrutamiento basado en prompt (agrega nodo `prompt2flow`) |
-| `--prompt-json ` | JSON de respuestas para enrutamiento por prompt (requiere `--prompt`) |
-| `--auto-translate` | Traduce cards automáticamente con hasta 8 hilos en paralelo (requiere `greentic-i18n-translator`) |
-| `--langs ` | Códigos de idioma separados por comas; si se omite, traduce a los más de 65 locales compatibles |
-| `--glossary ` | JSON de glosario para traducciones consistentes |
-| `--verbose` | Imprime salida detallada |
+| `--cards ` | Directory of Adaptive Card JSON files (required) |
+| `--out ` | Output workspace directory (required) |
+| `--name ` | Pack name (required) |
+| `--strict` | Errors on missing targets, duplicates, invalid JSON |
+| `--group-by ` | Flow grouping: `folder` or `flow-field` |
+| `--default-flow ` | Default flow name for ungrouped cards |
+| `--prompt` | Enable prompt-based routing (adds `prompt2flow` node) |
+| `--prompt-json ` | Answers JSON for prompt routing (requires `--prompt`) |
+| `--auto-translate` | Auto-translate cards with up to 8 parallel threads (requires `greentic-i18n-translator`) |
+| `--langs ` | Comma-separated language codes; omit to translate to all 65+ supported locales |
+| `--glossary ` | Glossary JSON for consistent translations |
+| `--verbose` | Print detailed output |
### `extract-i18n`
-Extrae cadenas traducibles de las cards en un bundle JSON.
+Extract translatable strings from cards into a JSON bundle.
```bash
greentic-cards2pack extract-i18n [OPTIONS]
```
-| Flag | Descripción |
+| Flag | Description |
|------|-------------|
-| `--input ` | Directorio de archivos JSON de cards (requerido) |
-| `--output ` | Ruta del JSON de salida (por defecto: `i18n/en.json`) |
-| `--prefix ` | Prefijo de clave (por defecto: `card`) |
-| `--include-existing` | Incluye cadenas que ya contienen patrones `$t()` |
-| `--verbose` | Imprime el informe de extracción |
+| `--input ` | Directory of card JSON files (required) |
+| `--output ` | Output JSON path (default: `i18n/en.json`) |
+| `--prefix ` | Key prefix (default: `card`) |
+| `--include-existing` | Include strings that already contain `$t()` patterns |
+| `--verbose` | Print extraction report |
-## Identificación de Cards
+## Card Identification
-Las cards se identifican por (en orden de prioridad):
-1. El campo `greentic.cardId` en el JSON de la card
-2. El nombre base del archivo (por ejemplo, `welcome.json` → `welcome`)
+Cards are identified by (in order of priority):
+1. `greentic.cardId` field in the card JSON
+2. Filename stem (e.g., `welcome.json` → `welcome`)
-Las cards se agrupan en flows por:
-- El campo `flow` en los datos de la acción
-- `--group-by folder` (estructura de directorios)
-- El fallback `--default-flow`
+Cards are grouped into flows by:
+- `flow` field in action data
+- `--group-by folder` (directory structure)
+- `--default-flow` fallback
-## i18n y traducción automática
+## i18n & Auto-Translation
-### Extraer cadenas
+### Extract strings
```bash
greentic-cards2pack extract-i18n \
@@ -136,7 +148,7 @@ greentic-cards2pack extract-i18n \
--verbose
```
-Salida:
+Output:
```json title="i18n/en.json"
{
@@ -147,28 +159,28 @@ Salida:
```
-### Tipos de campos extraídos
+### Extracted field types
-| Campo | Origen |
+| Field | Source |
|-------|--------|
-| `text` | Contenido de TextBlock |
-| `title` | Títulos de acciones, títulos de cards y títulos de toggles |
-| `label` | Etiquetas de inputs |
-| `placeholder` | Placeholders de inputs |
-| `errorMessage` | Errores de validación |
-| `altText` | Texto alternativo de imágenes |
-| `fallbackText` | Contenido fallback |
-| FactSet `title`/`value` | Entradas de facts |
-| ChoiceSet `title` | Opciones de choice |
-
-### Traducción automática (un solo comando)
+| `text` | TextBlock content |
+| `title` | Action titles, card titles, toggle titles |
+| `label` | Input labels |
+| `placeholder` | Input placeholders |
+| `errorMessage` | Validation errors |
+| `altText` | Image alt text |
+| `fallbackText` | Fallback content |
+| FactSet `title`/`value` | Fact entries |
+| ChoiceSet `title` | Choice options |
+
+### Auto-translate (one command)
```bash
greentic-cards2pack generate \
@@ -179,7 +191,7 @@ greentic-cards2pack generate \
--langs fr,de
```
-Esto extrae cadenas de los archivos originales de cards, las traduce mediante `greentic-i18n-translator` usando hasta 8 hilos concurrentes y empaqueta todo:
+This extracts strings from the original card files, translates via `greentic-i18n-translator` using up to 8 concurrent threads, and bundles everything:
```
my-pack/assets/i18n/
@@ -189,12 +201,12 @@ my-pack/assets/i18n/
```
-### Glosario
+### Glossary
-Usa un glosario para mantener consistentes los nombres de marca y términos técnicos:
+Use a glossary to keep brand names and technical terms consistent:
```json title="glossary.json"
{
@@ -210,9 +222,9 @@ greentic-cards2pack generate \
--glossary glossary.json
```
-## Generación de Flows
+## Flow Generation
-Las secciones de flow generadas se envuelven en marcadores:
+Generated flow sections are wrapped in markers:
```yaml
# BEGIN GENERATED (cards2pack)
@@ -222,18 +234,18 @@ Las secciones de flow generadas se envuelven en marcadores:
# Developer space below (preserved on regen)
```
-El contenido fuera de los marcadores se conserva cuando regeneras.
+Content outside the markers is preserved when you regenerate.
-### Modo estricto
+### Strict mode
-Con `--strict`:
-- Los destinos de ruta faltantes producen errores (en lugar de nodos stub)
-- Los valores duplicados de `cardId` producen errores
-- El JSON no válido produce errores
+With `--strict`:
+- Missing route targets cause errors (instead of stub nodes)
+- Duplicate `cardId` values cause errors
+- Invalid JSON causes errors
-## Variables de plantilla
+## Template Variables
-Usa sintaxis Handlebars para contenido dinámico:
+Use Handlebars syntax for dynamic content:
```json
{
@@ -243,10 +255,10 @@ Usa sintaxis Handlebars para contenido dinámico:
```
-## Ejemplo: Formulario de varios pasos con traducción
+## Example: Multi-Step Form with Translation
```bash
# Create cards in cards/ directory, then:
@@ -260,11 +272,11 @@ greentic-cards2pack generate \
--strict
```
-Consulta el [ejemplo translate-demo](https://github.com/greentic-ai/greentic-cards2pack/tree/master/examples/translate-demo) para ver un recorrido completo.
+See the [translate-demo example](https://github.com/greentic-ai/greentic-cards2pack/tree/master/examples/translate-demo) for a complete walkthrough.
-## Siguientes pasos
+## Next Steps
-- [Guía de traducción de Cards](/es/i18n/cards-translation/)
-- [Resumen de i18n](/es/i18n/overview/)
-- [Guía de Flows](/es/concepts/flows/)
+- [Cards Translation Guide](/i18n/cards-translation/)
+- [i18n Overview](/i18n/overview/)
+- [Flows Guide](/concepts/flows/)
- [Adaptive Cards Designer](https://adaptivecards.io/designer/)
diff --git a/src/content/docs/id/components/cards2pack.mdx b/src/content/docs/id/components/cards2pack.mdx
index 36fb534..d03cbd1 100644
--- a/src/content/docs/id/components/cards2pack.mdx
+++ b/src/content/docs/id/components/cards2pack.mdx
@@ -1,37 +1,49 @@
---
title: cards2pack
-description: Ubah Adaptive Cards menjadi pack Greentic
+description: Convert Adaptive Cards to Greentic packs
---
import { Aside, Steps } from '@astrojs/starlight/components';
-## Gambaran Umum
+## Overview
-**cards2pack** adalah alat CLI yang mengubah file JSON Adaptive Card menjadi pack Greentic. Alat ini:
+**cards2pack** is a CLI tool that converts Adaptive Card JSON files into Greentic packs. It:
-- Memindai card, membangun grafik dependensi, menghasilkan flow `.ygtc`
-- Mengekstrak string yang dapat diterjemahkan untuk i18n
-- Menerjemahkan card secara otomatis via `greentic-i18n-translator`
-- Mengemas semuanya menjadi `.gtpack` yang siap di-deploy
+- Scans cards, builds a dependency graph, generates `.ygtc` flows
+- Extracts translatable strings for i18n
+- Auto-translates cards via `greentic-i18n-translator`
+- Packages everything into a deployable `.gtpack`
-## Instalasi
+
+
+## Installation
```bash
cargo install greentic-cards2pack
```
-Alat yang dibutuhkan:
+Required tools:
```bash
cargo install greentic-flow greentic-pack
cargo install greentic-i18n-translator # optional, for --auto-translate
```
-## Mulai Cepat
+## Quick Start
-1. **Buat Adaptive Cards**
+1. **Create Adaptive Cards**
```json title="cards/welcome.json"
{
@@ -51,7 +63,7 @@ cargo install greentic-i18n-translator # optional, for --auto-translate
}
```
-2. **Hasilkan pack**
+2. **Generate pack**
```bash
greentic-cards2pack generate \
@@ -60,7 +72,7 @@ cargo install greentic-i18n-translator # optional, for --auto-translate
--name my-pack
```
-3. **Hasil**
+3. **Output**
```
my-pack/
@@ -73,61 +85,61 @@ cargo install greentic-i18n-translator # optional, for --auto-translate
-## Referensi CLI
+## CLI Reference
### `generate`
-Perintah utama, memindai card, menghasilkan flow, dan membangun pack.
+Main command — scan cards, generate flows, build pack.
```bash
greentic-cards2pack generate [OPTIONS]
```
-| Flag | Deskripsi |
-|------|-----------|
-| `--cards ` | Direktori file JSON Adaptive Card (wajib) |
-| `--out ` | Direktori workspace output (wajib) |
-| `--name ` | Nama pack (wajib) |
-| `--strict` | Error saat target hilang, duplikat, atau JSON tidak valid |
-| `--group-by ` | Pengelompokan flow: `folder` atau `flow-field` |
-| `--default-flow ` | Nama flow default untuk card yang tidak dikelompokkan |
-| `--prompt` | Aktifkan routing berbasis prompt (menambahkan node `prompt2flow`) |
-| `--prompt-json ` | JSON jawaban untuk routing prompt (memerlukan `--prompt`) |
-| `--auto-translate` | Terjemahkan card otomatis dengan hingga 8 thread paralel (memerlukan `greentic-i18n-translator`) |
-| `--langs ` | Kode bahasa dipisahkan koma; kosongkan untuk menerjemahkan ke semua 65+ locale yang didukung |
-| `--glossary ` | Glossary JSON untuk terjemahan yang konsisten |
-| `--verbose` | Cetak output terperinci |
+| Flag | Description |
+|------|-------------|
+| `--cards ` | Directory of Adaptive Card JSON files (required) |
+| `--out ` | Output workspace directory (required) |
+| `--name ` | Pack name (required) |
+| `--strict` | Errors on missing targets, duplicates, invalid JSON |
+| `--group-by ` | Flow grouping: `folder` or `flow-field` |
+| `--default-flow ` | Default flow name for ungrouped cards |
+| `--prompt` | Enable prompt-based routing (adds `prompt2flow` node) |
+| `--prompt-json ` | Answers JSON for prompt routing (requires `--prompt`) |
+| `--auto-translate` | Auto-translate cards with up to 8 parallel threads (requires `greentic-i18n-translator`) |
+| `--langs ` | Comma-separated language codes; omit to translate to all 65+ supported locales |
+| `--glossary ` | Glossary JSON for consistent translations |
+| `--verbose` | Print detailed output |
### `extract-i18n`
-Ekstrak string yang dapat diterjemahkan dari card ke dalam bundle JSON.
+Extract translatable strings from cards into a JSON bundle.
```bash
greentic-cards2pack extract-i18n [OPTIONS]
```
-| Flag | Deskripsi |
-|------|-----------|
-| `--input ` | Direktori file JSON card (wajib) |
-| `--output ` | Path JSON output (default: `i18n/en.json`) |
-| `--prefix ` | Prefiks key (default: `card`) |
-| `--include-existing` | Sertakan string yang sudah mengandung pola `$t()` |
-| `--verbose` | Cetak laporan ekstraksi |
+| Flag | Description |
+|------|-------------|
+| `--input ` | Directory of card JSON files (required) |
+| `--output ` | Output JSON path (default: `i18n/en.json`) |
+| `--prefix ` | Key prefix (default: `card`) |
+| `--include-existing` | Include strings that already contain `$t()` patterns |
+| `--verbose` | Print extraction report |
-## Identifikasi Card
+## Card Identification
-Card diidentifikasi berdasarkan (urutan prioritas):
-1. Field `greentic.cardId` di JSON card
-2. Stem nama file (misalnya, `welcome.json` → `welcome`)
+Cards are identified by (in order of priority):
+1. `greentic.cardId` field in the card JSON
+2. Filename stem (e.g., `welcome.json` → `welcome`)
-Card dikelompokkan ke dalam flow berdasarkan:
-- Field `flow` di action data
-- `--group-by folder` (struktur direktori)
-- Fallback `--default-flow`
+Cards are grouped into flows by:
+- `flow` field in action data
+- `--group-by folder` (directory structure)
+- `--default-flow` fallback
-## i18n & Terjemahan Otomatis
+## i18n & Auto-Translation
-### Ekstrak string
+### Extract strings
```bash
greentic-cards2pack extract-i18n \
@@ -136,7 +148,7 @@ greentic-cards2pack extract-i18n \
--verbose
```
-Hasil:
+Output:
```json title="i18n/en.json"
{
@@ -147,28 +159,28 @@ Hasil:
```
-### Jenis field yang diekstrak
+### Extracted field types
-| Field | Sumber |
+| Field | Source |
|-------|--------|
-| `text` | Konten TextBlock |
-| `title` | Judul action, judul card, judul toggle |
-| `label` | Label input |
-| `placeholder` | Placeholder input |
-| `errorMessage` | Error validasi |
-| `altText` | Alt text gambar |
-| `fallbackText` | Konten fallback |
-| FactSet `title`/`value` | Entri fakta |
-| ChoiceSet `title` | Opsi pilihan |
-
-### Terjemahan otomatis (satu perintah)
+| `text` | TextBlock content |
+| `title` | Action titles, card titles, toggle titles |
+| `label` | Input labels |
+| `placeholder` | Input placeholders |
+| `errorMessage` | Validation errors |
+| `altText` | Image alt text |
+| `fallbackText` | Fallback content |
+| FactSet `title`/`value` | Fact entries |
+| ChoiceSet `title` | Choice options |
+
+### Auto-translate (one command)
```bash
greentic-cards2pack generate \
@@ -179,7 +191,7 @@ greentic-cards2pack generate \
--langs fr,de
```
-Perintah ini mengekstrak string dari file card asli, menerjemahkannya via `greentic-i18n-translator` menggunakan hingga 8 thread konkuren, lalu membundel semuanya:
+This extracts strings from the original card files, translates via `greentic-i18n-translator` using up to 8 concurrent threads, and bundles everything:
```
my-pack/assets/i18n/
@@ -189,12 +201,12 @@ my-pack/assets/i18n/
```
### Glossary
-Gunakan glossary untuk menjaga nama brand dan istilah teknis tetap konsisten:
+Use a glossary to keep brand names and technical terms consistent:
```json title="glossary.json"
{
@@ -210,9 +222,9 @@ greentic-cards2pack generate \
--glossary glossary.json
```
-## Pembuatan Flow
+## Flow Generation
-Bagian flow yang dihasilkan dibungkus dalam marker:
+Generated flow sections are wrapped in markers:
```yaml
# BEGIN GENERATED (cards2pack)
@@ -222,18 +234,18 @@ Bagian flow yang dihasilkan dibungkus dalam marker:
# Developer space below (preserved on regen)
```
-Konten di luar marker akan dipertahankan saat Anda melakukan generate ulang.
+Content outside the markers is preserved when you regenerate.
-### Mode strict
+### Strict mode
-Dengan `--strict`:
-- Target route yang hilang menyebabkan error (bukan node stub)
-- Nilai `cardId` yang duplikat menyebabkan error
-- JSON yang tidak valid menyebabkan error
+With `--strict`:
+- Missing route targets cause errors (instead of stub nodes)
+- Duplicate `cardId` values cause errors
+- Invalid JSON causes errors
-## Variabel Template
+## Template Variables
-Gunakan sintaks Handlebars untuk konten dinamis:
+Use Handlebars syntax for dynamic content:
```json
{
@@ -243,10 +255,10 @@ Gunakan sintaks Handlebars untuk konten dinamis:
```
-## Contoh: Form Multi-Langkah dengan Terjemahan
+## Example: Multi-Step Form with Translation
```bash
# Create cards in cards/ directory, then:
@@ -260,11 +272,11 @@ greentic-cards2pack generate \
--strict
```
-Lihat [contoh translate-demo](https://github.com/greentic-ai/greentic-cards2pack/tree/master/examples/translate-demo) untuk walkthrough lengkap.
+See the [translate-demo example](https://github.com/greentic-ai/greentic-cards2pack/tree/master/examples/translate-demo) for a complete walkthrough.
-## Langkah Berikutnya
+## Next Steps
-- [Panduan Terjemahan Cards](/id/i18n/cards-translation/)
-- [Ikhtisar i18n](/id/i18n/overview/)
-- [Panduan Flows](/id/concepts/flows/)
+- [Cards Translation Guide](/i18n/cards-translation/)
+- [i18n Overview](/i18n/overview/)
+- [Flows Guide](/concepts/flows/)
- [Adaptive Cards Designer](https://adaptivecards.io/designer/)
diff --git a/src/content/docs/ja/components/cards2pack.mdx b/src/content/docs/ja/components/cards2pack.mdx
index 278c3ef..d03cbd1 100644
--- a/src/content/docs/ja/components/cards2pack.mdx
+++ b/src/content/docs/ja/components/cards2pack.mdx
@@ -1,37 +1,49 @@
---
title: cards2pack
-description: Adaptive Cards を Greentic packs に変換する
+description: Convert Adaptive Cards to Greentic packs
---
import { Aside, Steps } from '@astrojs/starlight/components';
-## 概要
+## Overview
-**cards2pack** は Adaptive Card の JSON ファイルを Greentic packs に変換する CLI ツールです。次のことを行います:
+**cards2pack** is a CLI tool that converts Adaptive Card JSON files into Greentic packs. It:
-- cards を走査し、依存グラフを構築して `.ygtc` flows を生成する
-- i18n 用に翻訳可能な文字列を抽出する
-- `greentic-i18n-translator` によって cards を自動翻訳する
-- すべてをデプロイ可能な `.gtpack` にパッケージングする
+- Scans cards, builds a dependency graph, generates `.ygtc` flows
+- Extracts translatable strings for i18n
+- Auto-translates cards via `greentic-i18n-translator`
+- Packages everything into a deployable `.gtpack`
-## インストール
+
+
+## Installation
```bash
cargo install greentic-cards2pack
```
-必要なツール:
+Required tools:
```bash
cargo install greentic-flow greentic-pack
cargo install greentic-i18n-translator # optional, for --auto-translate
```
-## クイックスタート
+## Quick Start
-1. **Adaptive Cards を作成する**
+1. **Create Adaptive Cards**
```json title="cards/welcome.json"
{
@@ -51,7 +63,7 @@ cargo install greentic-i18n-translator # optional, for --auto-translate
}
```
-2. **pack を生成する**
+2. **Generate pack**
```bash
greentic-cards2pack generate \
@@ -60,7 +72,7 @@ cargo install greentic-i18n-translator # optional, for --auto-translate
--name my-pack
```
-3. **出力**
+3. **Output**
```
my-pack/
@@ -73,61 +85,61 @@ cargo install greentic-i18n-translator # optional, for --auto-translate
-## CLI リファレンス
+## CLI Reference
### `generate`
-メインコマンドです。cards を走査し、flows を生成して、pack をビルドします。
+Main command — scan cards, generate flows, build pack.
```bash
greentic-cards2pack generate [OPTIONS]
```
-| Flag | 説明 |
+| Flag | Description |
|------|-------------|
-| `--cards ` | Adaptive Card JSON ファイルのディレクトリ(必須) |
-| `--out ` | 出力 workspace ディレクトリ(必須) |
-| `--name ` | Pack 名(必須) |
-| `--strict` | 欠落した target、重複、無効な JSON をエラーにする |
-| `--group-by ` | Flow のグループ化: `folder` または `flow-field` |
-| `--default-flow ` | グループ化されない cards のデフォルト flow 名 |
-| `--prompt` | prompt ベースのルーティングを有効にする(`prompt2flow` node を追加) |
-| `--prompt-json ` | prompt ルーティング用の回答 JSON(`--prompt` が必要) |
-| `--auto-translate` | 最大 8 並列スレッドで cards を自動翻訳する(`greentic-i18n-translator` が必要) |
-| `--langs ` | カンマ区切りの言語コード。省略すると対応する 65 以上のすべての locale に翻訳 |
-| `--glossary ` | 一貫した翻訳のための glossary JSON |
-| `--verbose` | 詳細出力を表示する |
+| `--cards ` | Directory of Adaptive Card JSON files (required) |
+| `--out ` | Output workspace directory (required) |
+| `--name ` | Pack name (required) |
+| `--strict` | Errors on missing targets, duplicates, invalid JSON |
+| `--group-by ` | Flow grouping: `folder` or `flow-field` |
+| `--default-flow ` | Default flow name for ungrouped cards |
+| `--prompt` | Enable prompt-based routing (adds `prompt2flow` node) |
+| `--prompt-json ` | Answers JSON for prompt routing (requires `--prompt`) |
+| `--auto-translate` | Auto-translate cards with up to 8 parallel threads (requires `greentic-i18n-translator`) |
+| `--langs ` | Comma-separated language codes; omit to translate to all 65+ supported locales |
+| `--glossary ` | Glossary JSON for consistent translations |
+| `--verbose` | Print detailed output |
### `extract-i18n`
-cards から翻訳可能な文字列を JSON bundle に抽出します。
+Extract translatable strings from cards into a JSON bundle.
```bash
greentic-cards2pack extract-i18n [OPTIONS]
```
-| Flag | 説明 |
+| Flag | Description |
|------|-------------|
-| `--input ` | card JSON ファイルのディレクトリ(必須) |
-| `--output ` | 出力 JSON パス(デフォルト: `i18n/en.json`) |
-| `--prefix ` | キー接頭辞(デフォルト: `card`) |
-| `--include-existing` | すでに `$t()` パターンを含む文字列も含める |
-| `--verbose` | 抽出レポートを表示する |
+| `--input ` | Directory of card JSON files (required) |
+| `--output ` | Output JSON path (default: `i18n/en.json`) |
+| `--prefix ` | Key prefix (default: `card`) |
+| `--include-existing` | Include strings that already contain `$t()` patterns |
+| `--verbose` | Print extraction report |
-## Card の識別
+## Card Identification
-cards は次の優先順で識別されます:
-1. card JSON 内の `greentic.cardId` フィールド
-2. ファイル名の stem(例: `welcome.json` → `welcome`)
+Cards are identified by (in order of priority):
+1. `greentic.cardId` field in the card JSON
+2. Filename stem (e.g., `welcome.json` → `welcome`)
-cards は次の方法で flows にグループ化されます:
-- action data 内の `flow` フィールド
-- `--group-by folder`(ディレクトリ構造)
+Cards are grouped into flows by:
+- `flow` field in action data
+- `--group-by folder` (directory structure)
- `--default-flow` fallback
-## i18n と自動翻訳
+## i18n & Auto-Translation
-### 文字列を抽出する
+### Extract strings
```bash
greentic-cards2pack extract-i18n \
@@ -136,7 +148,7 @@ greentic-cards2pack extract-i18n \
--verbose
```
-出力:
+Output:
```json title="i18n/en.json"
{
@@ -147,28 +159,28 @@ greentic-cards2pack extract-i18n \
```
-### 抽出されるフィールドの種類
+### Extracted field types
-| Field | ソース |
+| Field | Source |
|-------|--------|
-| `text` | TextBlock の内容 |
-| `title` | Action titles、card titles、toggle titles |
+| `text` | TextBlock content |
+| `title` | Action titles, card titles, toggle titles |
| `label` | Input labels |
| `placeholder` | Input placeholders |
| `errorMessage` | Validation errors |
-| `altText` | 画像の代替テキスト |
-| `fallbackText` | フォールバック内容 |
+| `altText` | Image alt text |
+| `fallbackText` | Fallback content |
| FactSet `title`/`value` | Fact entries |
| ChoiceSet `title` | Choice options |
-### 自動翻訳(1 コマンド)
+### Auto-translate (one command)
```bash
greentic-cards2pack generate \
@@ -179,7 +191,7 @@ greentic-cards2pack generate \
--langs fr,de
```
-これにより、元の card ファイルから文字列を抽出し、最大 8 並列スレッドで `greentic-i18n-translator` によって翻訳し、すべてをまとめて bundle します:
+This extracts strings from the original card files, translates via `greentic-i18n-translator` using up to 8 concurrent threads, and bundles everything:
```
my-pack/assets/i18n/
@@ -189,12 +201,12 @@ my-pack/assets/i18n/
```
### Glossary
-brand 名や技術用語の表記を統一するには glossary を使います:
+Use a glossary to keep brand names and technical terms consistent:
```json title="glossary.json"
{
@@ -210,9 +222,9 @@ greentic-cards2pack generate \
--glossary glossary.json
```
-## Flow の生成
+## Flow Generation
-生成された flow セクションは markers で囲まれます:
+Generated flow sections are wrapped in markers:
```yaml
# BEGIN GENERATED (cards2pack)
@@ -222,18 +234,18 @@ greentic-cards2pack generate \
# Developer space below (preserved on regen)
```
-markers の外側の内容は再生成時にも保持されます。
+Content outside the markers is preserved when you regenerate.
-### strict モード
+### Strict mode
-`--strict` を使うと:
-- 欠落した route targets はエラーになる(stub nodes ではなく)
-- 重複した `cardId` 値はエラーになる
-- 無効な JSON はエラーになる
+With `--strict`:
+- Missing route targets cause errors (instead of stub nodes)
+- Duplicate `cardId` values cause errors
+- Invalid JSON causes errors
-## テンプレート変数
+## Template Variables
-動的コンテンツには Handlebars 構文を使います:
+Use Handlebars syntax for dynamic content:
```json
{
@@ -243,10 +255,10 @@ markers の外側の内容は再生成時にも保持されます。
```
-## 例: 翻訳付きマルチステップフォーム
+## Example: Multi-Step Form with Translation
```bash
# Create cards in cards/ directory, then:
@@ -259,3 +271,12 @@ greentic-cards2pack generate \
--glossary glossary.json \
--strict
```
+
+See the [translate-demo example](https://github.com/greentic-ai/greentic-cards2pack/tree/master/examples/translate-demo) for a complete walkthrough.
+
+## Next Steps
+
+- [Cards Translation Guide](/i18n/cards-translation/)
+- [i18n Overview](/i18n/overview/)
+- [Flows Guide](/concepts/flows/)
+- [Adaptive Cards Designer](https://adaptivecards.io/designer/)
diff --git a/src/content/docs/reference/channel-data-access.mdx b/src/content/docs/reference/channel-data-access.mdx
new file mode 100644
index 0000000..fc8ee5a
--- /dev/null
+++ b/src/content/docs/reference/channel-data-access.mdx
@@ -0,0 +1,177 @@
+---
+title: Channel Data Access Pattern
+description: How DirectLine channelData reaches flow templates and WASM components as envelope extensions.
+---
+
+import { Aside, Steps } from '@astrojs/starlight/components';
+
+## Overview
+
+WebChat and other DirectLine-compatible clients can attach free-form
+per-channel metadata to an activity via the DirectLine `channelData`
+field. In Greentic this metadata is not dropped and it is not treated as
+channel-specific plumbing — it becomes part of the normalized
+`ChannelMessageEnvelope` that flows through the whole runtime and reaches
+your flow templates and WASM components verbatim.
+
+This page documents the end-to-end contract. It is the canonical pattern
+used by the R1 demo (Paul's principals scenario): the front-end sets
+`channelData.r1_principals`, the flow reads it, and a WASM component
+receives it as structured input.
+
+
+
+## The wire contract
+
+### 1. Provider normalisation (camelCase -> snake_case)
+
+`messaging-provider-webchat` copies the DirectLine activity's
+`channelData` into the envelope's `extensions` map under the
+`channel_data` key. The rename from camelCase to snake_case is
+intentional: every well-known extension key uses snake_case inside
+Greentic so that flow templates and WASM components see a single,
+consistent naming convention.
+
+| Source (DirectLine wire) | Destination (Greentic envelope) |
+|--------------------------|---------------------------------|
+| `activity.channelData` | `envelope.extensions.channel_data` |
+
+The provider passes the payload through verbatim — it does not strip or
+normalise keys nested inside `channelData`. Whatever shape the client
+sends is the shape your flow receives.
+
+### 2. Flow-input scope
+
+Once the envelope is routed to a flow, the runtime builds a template
+context where the envelope is exposed under `entry.input`. Extensions
+are reachable at:
+
+```
+entry.input.extensions.channel_data
+```
+
+This is the scope used by inline `{{ ... }}` template expressions in the
+flow YAML.
+
+### 3. Node-input scope (auto-merge)
+
+Before each node is dispatched, the flow engine merges envelope-level
+extensions into the node's WASM input as a top-level `extensions` field,
+**unless** the node's `input` mapping already defines an explicit
+`extensions` key (user mappings always win).
+
+As a result, WASM components see the extensions object directly on
+`input`:
+
+```
+input.extensions.channel_data
+```
+
+The merge is defined in `greentic-runner-host` (see
+`src/runner/extensions.rs`). It is a no-op when `entry.input.extensions`
+is missing, empty, or not a JSON object.
+
+## End-to-end example
+
+The R1 demo front-end sends:
+
+```json
+{
+ "type": "message",
+ "text": "Summarise my open incidents",
+ "channelData": {
+ "r1_principals": {
+ "user": "paul@example.com",
+ "groups": ["noc-operators"]
+ }
+ }
+}
+```
+
+### Flow YAML — read from the template context
+
+```yaml
+nodes:
+ - id: call_handler
+ component: component-some-handler
+ operation: handle_message
+ input:
+ principals: '{{ entry.input.extensions.channel_data.r1_principals }}'
+ message: '{{ entry.input.payload.text }}'
+```
+
+Here `principals` is passed into the component as a nested object, and
+`message` pulls from `payload.text` on the envelope.
+
+### WASM component — read from the auto-merged input
+
+Because the engine auto-merges extensions into every node's input, a
+component can skip the template binding entirely and read extensions
+directly off its `input`:
+
+```rust
+use serde_json::Value;
+
+fn handle(input: &Value) -> anyhow::Result {
+ let principals = input["extensions"]["channel_data"]["r1_principals"].clone();
+ // ... use principals
+ Ok(serde_json::json!({ "ok": true }))
+}
+```
+
+
+
+## Naming rules
+
+
+
+1. **On the wire (DirectLine):** camelCase — `channelData`.
+
+2. **Inside the Greentic envelope:** snake_case — `extensions.channel_data`.
+
+3. **In flow templates and WASM components:** snake_case — always.
+
+
+
+The provider is the only place where the rename happens. Flows and
+components never see the camelCase form.
+
+## Well-known extension keys
+
+`channel_data` is one of a small set of well-known keys defined in
+`greentic-types` (`src/messaging/extensions.rs`). All of them follow the
+same auto-merge rule on the node-input side, and all of them round-trip
+verbatim on the egress side. See the [WebChat
+provider](/providers/messaging/webchat/) page for the full table of
+canonical keys, including `adaptive_card`, `entities`, `attachments`,
+`suggested_actions`, `speak`, and `input_hint`.
+
+## Regression test
+
+The propagation contract is pinned by
+`run_app_flow_input_preserves_envelope_extensions_channel_data` in
+`greentic-start` (`src/messaging_app.rs`). The test builds an envelope
+with `extensions.channel_data.r1_principals`, runs it through the full
+messaging app path, and asserts the value survives verbatim at
+`/input/extensions/channel_data/r1_principals` in the resulting
+`ExecutionState.entry`.
+
+If you are changing anything between HTTP ingress and
+`engine.execute` (envelope routing, request building, runner glue),
+re-run that test first.
+
+## Next steps
+
+- [WebChat provider](/providers/messaging/webchat/) — envelope extensions table, attachment shapes, egress round-trip.
+- [Flow YAML Schema](/reference/flow-schema/) — template context variables (`{{entry.*}}`).
+- [Flow Node Kinds](/reference/flow-node-kinds/) — builtin operators and the component-node model.
diff --git a/src/content/docs/reference/flow-node-kinds.mdx b/src/content/docs/reference/flow-node-kinds.mdx
new file mode 100644
index 0000000..ddc0bfb
--- /dev/null
+++ b/src/content/docs/reference/flow-node-kinds.mdx
@@ -0,0 +1,234 @@
+---
+title: Flow Node Kinds
+description: The node kinds understood by the flow engine — component nodes, builtin operators, and the state-store gap as of greentic-runner 0.5.11.
+---
+
+import { Aside, Steps } from '@astrojs/starlight/components';
+
+## Overview
+
+A flow is a DAG whose nodes are either **component nodes** (WASM
+components loaded from the pack or a cross-pack resolver) or **builtin
+operators** — short-circuit nodes the flow engine executes itself.
+This page lists every node kind the engine recognises today, plus the
+state-store gap the runner currently exposes.
+
+
+
+## Component nodes
+
+Component nodes run a WASM component from the pack. They are the
+default: any node whose `component` field does not resolve to a
+builtin prefix is dispatched as a component node.
+
+```yaml
+nodes:
+ - id: llm
+ component: component-llm-openai # pack-local component id
+ operation: complete # operation exported by the component
+ config:
+ api_key_secret: "llm-api-key"
+ input:
+ prompt: '{{ entry.input.payload.text }}'
+```
+
+Component nodes may also reference components provisioned by other
+packs through the **cross-pack resolver**; the engine falls back to
+that resolver when the `component` id does not exist locally. See
+[Packs](/concepts/packs/) for the pack-local vs cross-pack lookup
+rules.
+
+## Builtin operators
+
+Builtin operators are identified by a reserved prefix on the
+`component` (or legacy `operation` / `target`) field. The engine
+dispatches them directly — no WASM call, no pack lookup. As of
+`greentic-runner` 0.5.11 the full set is:
+
+| Operator | Purpose |
+|----------|---------|
+| `emit.response` | Emit a response back to the originating channel. Terminal. |
+| `emit.log` | Emit a structured log line without affecting the message envelope. |
+| `session.wait` | Pause the flow on a named route until a matching resume event arrives. |
+| `flow.call` | Invoke another flow as a subroutine and resume when it returns. |
+| `provider.invoke` | Call an operation on a provider component (cross-pack aware). |
+
+Any `component` value starting with `emit.`, `session.`, `flow.`, or
+`provider.` is routed into the builtin table. Unknown prefixes in
+those namespaces are a hard error — the engine does not fall back to
+component resolution for reserved prefixes.
+
+### `emit.response`
+
+```yaml
+- id: reply
+ component: emit.response
+ input:
+ text: '{{ entry.input.payload.text }}'
+```
+
+Terminates the current flow path and emits the node's `input` as the
+response envelope. Downstream providers (WebChat, Slack, Telegram, ...)
+render the envelope per channel.
+
+### `emit.log`
+
+```yaml
+- id: trace
+ component: emit.log
+ input:
+ level: info
+ msg: "handled principals for {{ entry.input.extensions.channel_data.r1_principals.user }}"
+```
+
+Does not terminate — the flow continues to the `next` node. Useful for
+marking points in the flow that should surface in runtime logs without
+involving a full WASM component.
+
+### `session.wait`
+
+```yaml
+- id: await_answer
+ component: session.wait
+ config:
+ route: "confirm_order"
+ timeout_ms: 30000
+ next: on_answer
+```
+
+Persists a `FlowSnapshot` keyed by the session key
+(`{tenant}:{provider}:{conversation}:{user}`) and pauses. The matching
+resume event is routed by the `route` name. See the runner architecture
+overview for the full pause/resume semantics.
+
+### `flow.call`
+
+```yaml
+- id: verify
+ component: flow.call
+ config:
+ flow_id: verify-user
+ input:
+ user: '{{ entry.input.payload.from.id }}'
+ next: after_verify
+```
+
+Invokes another flow as a subroutine. The subflow's terminal response
+becomes this node's output. `flow.call` fails the parent flow if the
+subflow pauses (use `session.wait` at the parent level for
+pause-compatible subcalls).
+
+### `provider.invoke`
+
+```yaml
+- id: send_dm
+ component: provider.invoke
+ config:
+ provider_id: messaging-provider-slack
+ op: send_message
+ input:
+ to: '{{ entry.input.payload.from.id }}'
+ text: "Got it."
+```
+
+Calls a typed operation on a provider component, respecting the
+cross-pack resolver and the provider's declared capabilities. This is
+how flows reach outbound messaging without binding to a specific pack
+layout.
+
+## State store gap
+
+
+
+### What ships today
+
+- **Storage backends ship as provider packs.** `state-memory` and
+ `state-redis` are available as packs that expose the
+ `greentic:state/state-store` host capability to WASM components.
+- **WASM components can read and write state.** A component in a pack
+ that declares `greentic:state/state-store` as a required host
+ capability gets a typed handle to the store via `wit-bindgen` and
+ can perform get/put/delete/list/cas operations from inside the
+ component.
+- **Manifest default is permissive.** When a component manifest omits
+ `host.state`, the runner defaults to allowing the state-store host
+ call (see the `state-store-default-allow` fix). Explicit deny is
+ still honoured.
+
+### What is not shipping
+
+There is no flow-level `state.*` builtin operator. The roadmap
+tracks flow-callable state primitives, but the 0.5.11 engine does not
+dispatch them.
+
+### Recommended workaround
+
+When a flow needs to persist data across turns, invoke a custom WASM
+component that reads/writes via the host capability:
+
+```yaml
+- id: remember_principals
+ component: component-state-helper
+ operation: put
+ input:
+ key: 'principals/{{ entry.input.payload.from.id }}'
+ value: '{{ entry.input.extensions.channel_data.r1_principals }}'
+```
+
+Inside `component-state-helper`, the handler calls the
+`greentic:state/state-store` host API directly. The component is
+responsible for key namespacing and serialisation; the runner only
+enforces the capability grant.
+
+### Forward-looking example
+
+The `qa-demo` flow in the demo catalog contains `state.get` /
+`state.put` nodes as a forward-looking example. **That flow is not
+runnable end-to-end on 0.5.11** — it is staged for the release that
+introduces flow-level state builtins. Use it as a reference for the
+intended YAML shape, not as a working flow today.
+
+## Legacy `type:` shorthand
+
+Some older `.ygtc` files use a `type: ` shorthand instead of
+`component: `. The engine still accepts the shorthand for
+backwards compatibility, but the canonical form going forward is
+`component:` (pack-local id or builtin prefix) plus `operation:`
+(the WIT-exported op name for component nodes).
+
+```yaml
+# Legacy
+- id: reply
+ type: reply
+ config:
+ message: "Hello"
+
+# Canonical
+- id: reply
+ component: emit.response
+ input:
+ text: "Hello"
+```
+
+New flows should use the canonical form. The legacy shorthand will
+remain accepted but is not guaranteed to receive new features
+(for example, per-node cross-pack resolver hints).
+
+## Next steps
+
+- [Flow YAML Schema](/reference/flow-schema/) — full YAML structure, template context, expression syntax.
+- [Channel Data Access](/reference/channel-data-access/) — how envelope extensions reach node inputs.
+- [Secret Seeding](/reference/secret-seeding/) — pack-scoped secret URIs for component nodes.
+- [Packs](/concepts/packs/) — pack-local vs cross-pack component resolution.
diff --git a/src/content/docs/reference/secret-seeding.mdx b/src/content/docs/reference/secret-seeding.mdx
new file mode 100644
index 0000000..b26becb
--- /dev/null
+++ b/src/content/docs/reference/secret-seeding.mdx
@@ -0,0 +1,218 @@
+---
+title: Secret Seeding Recipe
+description: Canonical patterns for seeding secrets into a Greentic bundle so packs and flows can resolve them at runtime.
+---
+
+import { Aside, Steps } from '@astrojs/starlight/components';
+
+## Overview
+
+Greentic secrets are addressed by a pack-scoped URI and resolved lazily
+by the runtime when a flow references them. Getting the URI right is
+the most common source of the runtime error
+
+```
+Secret was not found or not provisioned for this component.
+```
+
+This page documents the canonical URI scheme and the two supported
+seeding paths. **Prefer Path A (`setup.yaml` wizard)** — it gets the
+pack scope right by construction. Path B (manual seeding) is only
+necessary when a pack does not ship a `setup.yaml`.
+
+## URI scheme
+
+```
+secrets://{env}/{tenant}/{team}/{pack_id}/{key}
+```
+
+| Segment | Description |
+|---------|-------------|
+| `env` | Environment name, e.g. `dev`, `demo`, `prod`. |
+| `tenant` | Tenant ID the secret belongs to. |
+| `team` | Visibility scope within the tenant (`default` or a team name). |
+| `pack_id` | The **pack manifest id** of the consuming pack — **not** a component id. |
+| `key` | The short secret name referenced from the flow (e.g. `llm-api-key`). |
+
+
+
+## Path A — `setup.yaml` (preferred)
+
+When a pack ships an `assets/setup.yaml` with `secret: true` questions,
+the `gtc setup` wizard handles the URI construction for you. This is
+the recommended path for every production pack.
+
+### Pack side
+
+Declare the secret question in the pack's setup file:
+
+```yaml title="assets/setup.yaml"
+questions:
+ - id: llm-api-key
+ label: "OpenAI API key"
+ kind: string
+ required: true
+ secret: true
+ help: |
+ Used by the LLM handler to call OpenAI. Starts with `sk-`.
+```
+
+The wizard:
+
+- prompts the user (or reads the value from `--answers`),
+- persists the value at
+ `secrets://{env}/{tenant}/{team}/{this-pack-id}/llm-api-key`, and
+- never writes the value to disk in plaintext outside the secrets
+ backend.
+
+### Operator side
+
+Running setup seeds the secret at the correct URI:
+
+```bash
+gtc setup --pack deep-research-demo.gtpack --tenant demo
+```
+
+Or non-interactively:
+
+```bash
+gtc setup --answers deep-research-answers.json ./deep-research-demo-bundle
+```
+
+The wizard reads the bundle's tenant automatically and writes each
+answer under the owning pack's id — no manual URI assembly required.
+
+### Flow side
+
+The flow references the secret by its short `key` part only:
+
+```yaml title="flows/chat.ygtc"
+nodes:
+ - id: llm
+ component: component-llm-openai
+ operation: complete
+ config:
+ api_key_secret: "llm-api-key"
+ input:
+ prompt: '{{ entry.input.payload.text }}'
+```
+
+The runner expands `"llm-api-key"` to the full
+`secrets://{env}/{tenant}/{team}/{pack_id}/llm-api-key` URI using the
+**consuming pack's** id at resolve time. You never hand-write the URI
+in the flow.
+
+
+
+## Path B — manual `greentic-secrets admin set`
+
+Use this only when the pack does not ship a `setup.yaml` or when you
+are seeding secrets for a locally-built pack during development.
+
+```bash
+greentic-secrets admin set \
+ --tenant demo \
+ --pack-id training-m1 \
+ --name llm-api-key \
+ --visibility team \
+ --value sk-...redacted...
+```
+
+| Flag | Meaning |
+|------|---------|
+| `--tenant` | Tenant segment of the URI. |
+| `--pack-id` | **Pack manifest id** — must match the consuming pack's id. |
+| `--name` | Short key part of the URI (`llm-api-key` in the example). |
+| `--visibility` | `team` (default) or `tenant`. Maps to the `team` segment. |
+| `--value` | The secret value. Prefer `--value-stdin` in CI. |
+
+
+
+### Verifying what was written
+
+```bash
+greentic-secrets admin list --tenant demo
+```
+
+This prints the URIs of all secrets visible to the tenant, which is
+the fastest way to confirm the `pack_id` segment matches what the pack
+is actually resolving.
+
+## Component manifest: empty `required` list is by design
+
+A pack's component manifest typically looks like:
+
+```yaml
+capabilities:
+ host:
+ secrets:
+ required: []
+```
+
+An empty list does **not** mean "this component uses no secrets". It
+means "this component accepts any secret name; the pack and flow decide
+which ones". Concrete names are fixed at flow-configuration time
+(`api_key_secret: "llm-api-key"`) rather than pinned in the component.
+
+This design lets one WASM component (for example `component-llm-openai`)
+be reused across packs with different secret conventions without
+recompiling.
+
+## Troubleshooting
+
+### `Secret was not found or not provisioned for this component`
+
+
+
+1. **Check the `pack_id` segment.** The URI the runner looks up uses the
+ id of the pack that owns the flow, not the component id. Run
+ `greentic-secrets admin list --tenant ` and confirm the
+ `pack_id` segment matches the pack that contains the flow.
+
+2. **Check the `env` segment.** The CLI `--env` flag defaults to
+ `"demo"` in some commands and `"dev"` in others. If the runner is
+ started with `GREENTIC_ENV=dev`, secrets seeded under `env=demo`
+ will not be found. Use the same env on both sides.
+
+3. **Check the `team` segment.** `--visibility team` writes to
+ `team=default` (or the team you configured); `--visibility tenant`
+ writes to `team=tenant`. The flow resolves under the team scope the
+ pack declares.
+
+4. **Re-run the wizard.** If the pack ships a `setup.yaml`, running
+ `gtc setup --force` re-seeds the secret at the correct URI and is
+ safer than hand-seeding with `admin set`.
+
+
+
+### Secret value silently truncated
+
+Some shells interpret `$` in secret values. Use `--value-stdin` or a
+single-quoted argument when the value contains shell metacharacters.
+
+## Next steps
+
+- [gtc setup](/cli/setup/) — wizard-driven seeding via `setup.yaml`.
+- [Pack Format](/reference/pack-format/) — where `setup.yaml` lives in a pack.
+- [Multi-Tenancy](/concepts/multi-tenancy/) — tenant, team, and environment scopes.
diff --git a/src/content/docs/zh/components/cards2pack.mdx b/src/content/docs/zh/components/cards2pack.mdx
index 4cfeedd..d03cbd1 100644
--- a/src/content/docs/zh/components/cards2pack.mdx
+++ b/src/content/docs/zh/components/cards2pack.mdx
@@ -1,37 +1,49 @@
---
title: cards2pack
-description: 将 Adaptive Cards 转换为 Greentic packs
+description: Convert Adaptive Cards to Greentic packs
---
import { Aside, Steps } from '@astrojs/starlight/components';
-## 概述
+## Overview
-**cards2pack** 是一个 CLI 工具,用于将 Adaptive Card JSON 文件转换为 Greentic packs。它会:
+**cards2pack** is a CLI tool that converts Adaptive Card JSON files into Greentic packs. It:
-- 扫描卡片、构建依赖图并生成 `.ygtc` flows
-- 提取用于 i18n 的可翻译字符串
-- 通过 `greentic-i18n-translator` 自动翻译卡片
-- 将所有内容打包成可部署的 `.gtpack`
+- Scans cards, builds a dependency graph, generates `.ygtc` flows
+- Extracts translatable strings for i18n
+- Auto-translates cards via `greentic-i18n-translator`
+- Packages everything into a deployable `.gtpack`
-## 安装
+
+
+## Installation
```bash
cargo install greentic-cards2pack
```
-所需工具:
+Required tools:
```bash
cargo install greentic-flow greentic-pack
cargo install greentic-i18n-translator # optional, for --auto-translate
```
-## 快速开始
+## Quick Start
-1. **创建 Adaptive Cards**
+1. **Create Adaptive Cards**
```json title="cards/welcome.json"
{
@@ -51,7 +63,7 @@ cargo install greentic-i18n-translator # optional, for --auto-translate
}
```
-2. **生成 pack**
+2. **Generate pack**
```bash
greentic-cards2pack generate \
@@ -60,7 +72,7 @@ cargo install greentic-i18n-translator # optional, for --auto-translate
--name my-pack
```
-3. **输出结果**
+3. **Output**
```
my-pack/
@@ -73,61 +85,61 @@ cargo install greentic-i18n-translator # optional, for --auto-translate
-## CLI 参考
+## CLI Reference
### `generate`
-主命令,用于扫描卡片、生成 flows 并构建 pack。
+Main command — scan cards, generate flows, build pack.
```bash
greentic-cards2pack generate [OPTIONS]
```
-| 标志 | 说明 |
+| Flag | Description |
|------|-------------|
-| `--cards ` | Adaptive Card JSON 文件目录(必需) |
-| `--out ` | 输出工作区目录(必需) |
-| `--name ` | Pack 名称(必需) |
-| `--strict` | 对缺失目标、重复项和无效 JSON 直接报错 |
-| `--group-by ` | Flow 分组方式:`folder` 或 `flow-field` |
-| `--default-flow ` | 未分组卡片的默认 flow 名称 |
-| `--prompt` | 启用基于 prompt 的路由(添加 `prompt2flow` 节点) |
-| `--prompt-json ` | 用于 prompt 路由的 answers JSON(需要 `--prompt`) |
-| `--auto-translate` | 最多使用 8 个并行线程自动翻译卡片(需要 `greentic-i18n-translator`) |
-| `--langs ` | 逗号分隔的语言代码;省略时会翻译到所有 65+ 个受支持的语言区域 |
-| `--glossary ` | 用于保持翻译一致性的 glossary JSON |
-| `--verbose` | 打印详细输出 |
+| `--cards ` | Directory of Adaptive Card JSON files (required) |
+| `--out ` | Output workspace directory (required) |
+| `--name ` | Pack name (required) |
+| `--strict` | Errors on missing targets, duplicates, invalid JSON |
+| `--group-by ` | Flow grouping: `folder` or `flow-field` |
+| `--default-flow ` | Default flow name for ungrouped cards |
+| `--prompt` | Enable prompt-based routing (adds `prompt2flow` node) |
+| `--prompt-json ` | Answers JSON for prompt routing (requires `--prompt`) |
+| `--auto-translate` | Auto-translate cards with up to 8 parallel threads (requires `greentic-i18n-translator`) |
+| `--langs ` | Comma-separated language codes; omit to translate to all 65+ supported locales |
+| `--glossary ` | Glossary JSON for consistent translations |
+| `--verbose` | Print detailed output |
### `extract-i18n`
-将卡片中的可翻译字符串提取为一个 JSON bundle。
+Extract translatable strings from cards into a JSON bundle.
```bash
greentic-cards2pack extract-i18n [OPTIONS]
```
-| 标志 | 说明 |
+| Flag | Description |
|------|-------------|
-| `--input ` | 卡片 JSON 文件目录(必需) |
-| `--output ` | 输出 JSON 路径(默认:`i18n/en.json`) |
-| `--prefix ` | 键前缀(默认:`card`) |
-| `--include-existing` | 包含已经带有 `$t()` 模式的字符串 |
-| `--verbose` | 打印提取报告 |
+| `--input ` | Directory of card JSON files (required) |
+| `--output ` | Output JSON path (default: `i18n/en.json`) |
+| `--prefix ` | Key prefix (default: `card`) |
+| `--include-existing` | Include strings that already contain `$t()` patterns |
+| `--verbose` | Print extraction report |
-## 卡片识别
+## Card Identification
-卡片按以下优先级识别:
-1. 卡片 JSON 中的 `greentic.cardId` 字段
-2. 文件名主干(例如 `welcome.json` → `welcome`)
+Cards are identified by (in order of priority):
+1. `greentic.cardId` field in the card JSON
+2. Filename stem (e.g., `welcome.json` → `welcome`)
-卡片会按以下方式分组到 flows 中:
-- action data 中的 `flow` 字段
-- `--group-by folder`(目录结构)
-- `--default-flow` 兜底
+Cards are grouped into flows by:
+- `flow` field in action data
+- `--group-by folder` (directory structure)
+- `--default-flow` fallback
-## i18n 与自动翻译
+## i18n & Auto-Translation
-### 提取字符串
+### Extract strings
```bash
greentic-cards2pack extract-i18n \
@@ -136,7 +148,7 @@ greentic-cards2pack extract-i18n \
--verbose
```
-输出:
+Output:
```json title="i18n/en.json"
{
@@ -147,28 +159,28 @@ greentic-cards2pack extract-i18n \
```
-### 提取的字段类型
+### Extracted field types
-| 字段 | 来源 |
+| Field | Source |
|-------|--------|
-| `text` | TextBlock 内容 |
-| `title` | Action 标题、卡片标题、toggle 标题 |
-| `label` | Input 标签 |
-| `placeholder` | Input 占位文本 |
-| `errorMessage` | 验证错误信息 |
-| `altText` | 图片替代文本 |
-| `fallbackText` | 回退内容 |
-| FactSet `title`/`value` | Fact 条目 |
-| ChoiceSet `title` | 选项标题 |
-
-### 自动翻译(单条命令)
+| `text` | TextBlock content |
+| `title` | Action titles, card titles, toggle titles |
+| `label` | Input labels |
+| `placeholder` | Input placeholders |
+| `errorMessage` | Validation errors |
+| `altText` | Image alt text |
+| `fallbackText` | Fallback content |
+| FactSet `title`/`value` | Fact entries |
+| ChoiceSet `title` | Choice options |
+
+### Auto-translate (one command)
```bash
greentic-cards2pack generate \
@@ -179,7 +191,7 @@ greentic-cards2pack generate \
--langs fr,de
```
-这会从原始卡片文件中提取字符串,通过 `greentic-i18n-translator` 使用最多 8 个并发线程进行翻译,并将所有内容打包:
+This extracts strings from the original card files, translates via `greentic-i18n-translator` using up to 8 concurrent threads, and bundles everything:
```
my-pack/assets/i18n/
@@ -189,12 +201,12 @@ my-pack/assets/i18n/
```
### Glossary
-使用 glossary 来保持品牌名和技术术语一致:
+Use a glossary to keep brand names and technical terms consistent:
```json title="glossary.json"
{
@@ -210,9 +222,9 @@ greentic-cards2pack generate \
--glossary glossary.json
```
-## Flow 生成
+## Flow Generation
-生成的 flow 片段会包裹在标记中:
+Generated flow sections are wrapped in markers:
```yaml
# BEGIN GENERATED (cards2pack)
@@ -222,18 +234,18 @@ greentic-cards2pack generate \
# Developer space below (preserved on regen)
```
-重新生成时,标记之外的内容会被保留。
+Content outside the markers is preserved when you regenerate.
-### Strict 模式
+### Strict mode
-启用 `--strict` 时:
-- 缺失的路由目标会报错(而不是生成 stub 节点)
-- 重复的 `cardId` 值会报错
-- 无效 JSON 会报错
+With `--strict`:
+- Missing route targets cause errors (instead of stub nodes)
+- Duplicate `cardId` values cause errors
+- Invalid JSON causes errors
-## 模板变量
+## Template Variables
-使用 Handlebars 语法表示动态内容:
+Use Handlebars syntax for dynamic content:
```json
{
@@ -243,10 +255,10 @@ greentic-cards2pack generate \
```
-## 示例:带翻译的多步骤表单
+## Example: Multi-Step Form with Translation
```bash
# Create cards in cards/ directory, then:
@@ -260,11 +272,11 @@ greentic-cards2pack generate \
--strict
```
-请参阅 [translate-demo example](https://github.com/greentic-ai/greentic-cards2pack/tree/master/examples/translate-demo) 获取完整演练。
+See the [translate-demo example](https://github.com/greentic-ai/greentic-cards2pack/tree/master/examples/translate-demo) for a complete walkthrough.
-## 下一步
+## Next Steps
-- [Cards Translation Guide](/zh/i18n/cards-translation/)
-- [i18n Overview](/zh/i18n/overview/)
-- [Flows Guide](/zh/concepts/flows/)
+- [Cards Translation Guide](/i18n/cards-translation/)
+- [i18n Overview](/i18n/overview/)
+- [Flows Guide](/concepts/flows/)
- [Adaptive Cards Designer](https://adaptivecards.io/designer/)
diff --git a/updates/2026-04-25/greentic-docs.md b/updates/2026-04-25/greentic-docs.md
new file mode 100644
index 0000000..71c9379
--- /dev/null
+++ b/updates/2026-04-25/greentic-docs.md
@@ -0,0 +1,53 @@
+# greentic-docs — canonical patterns (2026-04-25)
+
+Three new Reference pages close gaps surfaced by the 3Point team and
+Maarten's R1 demo debugging. Branch: `docs/canonical-patterns-2026-04-25`.
+
+## Pages added
+
+- `src/content/docs/reference/channel-data-access.mdx` — DirectLine
+ `channelData` -> `envelope.extensions.channel_data` -> flow template
+ `{{ entry.input.extensions.channel_data.* }}` -> WASM
+ `input.extensions.channel_data.*` (auto-merged by runner 0.5.11+).
+ Documents the camelCase/snake_case rename and points at the
+ regression test in `greentic-start/src/messaging_app.rs`.
+
+ **Closes:** 3Point's "how do we read `r1_principals` from a flow"
+ question from the R1 demo; Maarten's request for a canonical
+ pattern after the channelData plumbing fix.
+
+- `src/content/docs/reference/secret-seeding.mdx` — canonical URI
+ scheme `secrets://{env}/{tenant}/{team}/{pack_id}/{key}`, with
+ preferred Path A (`setup.yaml` wizard) and fallback Path B
+ (`greentic-secrets admin set`). Calls out `--category` as the
+ legacy alias of `--pack-id` and warns that the value must be the
+ pack manifest id, never a component id.
+
+ **Closes:** 3Point hitting "Secret was not found or not provisioned
+ for this component" because they passed `component-llm-openai` to
+ `--category`; Maarten's ask to make the pack-id-vs-component-id
+ rule explicit in docs.
+
+- `src/content/docs/reference/flow-node-kinds.mdx` — authoritative
+ list of node kinds recognised by runner 0.5.11: component nodes
+ plus `emit.response`, `emit.log`, `session.wait`, `flow.call`,
+ `provider.invoke`. Explicit gap note that no flow-callable
+ `state.*` builtin ships today; documents the state-memory /
+ state-redis backend + host-capability workaround and flags the
+ `qa-demo` state flow as a forward-looking (not runnable) example.
+
+ **Closes:** 3Point's confusion about why `state.get` nodes do not
+ dispatch; Maarten's request to set expectations for the state
+ roadmap item.
+
+## Config change
+
+- `astro.config.mjs` — three new Reference sidebar entries between
+ `flow-schema` and `pack-format`.
+
+## Not done
+
+- Translations — will run via `scripts/translate-docs.mjs` after merge.
+- State-store builtin docs — blocked on runner work (Option B framing
+ shipped instead of Option A because the runner does not yet
+ dispatch `state.*`).