@json-render/yaml

SkillCloud & infra

This skill gives an AI agent a YAML wire format for json-render, so it can write and stream UI specs as YAML code fences instead of JSONL. It includes a streaming parser that turns those fences into JSON Patch operations, prompt generators that teach the model the format, and an AI SDK transform for piping the output into a message stream. It supports merge, JSON Patch, and unified diff edit modes.

Then ask your AI: use the @json-render/yaml skill

Details

Instructions available. Your AI can read the instructions. Execution depends on the setup they require.

Install @json-render/yaml alongside @json-render/core.

What your AI can do with it

  • Stream YAML specs line by line and emit JSON Patch operations
  • Generate standalone or inline YAML prompts from a catalog
  • Recognize yaml-spec, yaml-edit, yaml-patch, and diff fences
  • Deep-merge partial YAML edits with the current spec (RFC 7396)
  • Apply RFC 6902 JSON Patch lines and unified diffs to a spec
  • Pipe YAML render output into an AI SDK message stream

Getting started

  1. Install @json-render/yaml alongside @json-render/core.
  2. Import yamlPrompt and pass your catalog to build a system prompt.
  3. Choose standalone mode for YAML-only output or inline mode for fenced YAML in chat.
  4. Use pipeYamlRender in place of pipeJsonRender to convert fences into patches.
  5. Pass previousSpec to pipeYamlRender when handling multi-turn edits.

What this skill tells your AI

The instructions your AI receives, as published by vercel-labs/json-render in skills/yaml/SKILL.md and read by Ahel’s review.

YAML wire format for @json-render/core. Progressive rendering and surgical edits via streaming YAML.

Key Concepts

  • YAML wire format: Alternative to JSONL that uses code fences (yaml-spec, yaml-edit, yaml-patch, diff)
  • Streaming parser: Incrementally parses YAML, emits JSON Patch operations via diffing
  • Edit modes: Patch (RFC 6902), merge (RFC 7396), and unified diff
  • AI SDK transform: TransformStream that converts YAML fences into json-render patches

Generating YAML Prompts

import { yamlPrompt } from "@json-render/yaml";
import { catalog } from "./catalog";

// Standalone mode (LLM outputs only YAML)
const systemPrompt = yamlPrompt(catalog, {
  mode: "standalone",
  editModes: ["merge"],
  customRules: ["Always use dark theme"],
});

// Inline mode (LLM responds conversationally, wraps YAML in fences)
const chatPrompt = yamlPrompt(catalog, { mode: "inline" });

Options:

  • system (string) — Custom system message intro
  • mode ("standalone" | "inline") — Output mode, default "standalone"
  • customRules (string[]) — Additional rules appended to prompt
  • editModes (EditMode[]) — Edit modes to document, default ["merge"]

AI SDK Transform

Use pipeYamlRender as a drop-in replacement for pipeJsonRender:

import { pipeYamlRender } from "@json-render/yaml";
import { createUIMessageStream, createUIMessageStreamResponse } from "ai";

const stream = createUIMessageStream({
  execute: async ({ writer }) => {
    writer.merge(pipeYamlRender(result.toUIMessageStream()));
  },
});
return createUIMessageStreamResponse({ stream });

For multi-turn edits, pass the previous spec:

pipeYamlRender(result.toUIMessageStream(), {
  previousSpec: currentSpec,
});

The transform recognizes four fence types:

  • yaml-spec — Full spec, parsed progressively line-by-line
  • yaml-edit — Partial YAML deep-merged with current spec (RFC 7396)
  • yaml-patch — RFC 6902 JSON Patch lines
  • diff — Unified diff applied to serialized spec

Streaming Parser (Low-Level)

import { createYamlStreamCompiler } from "@json-render/yaml";

const compiler = createYamlStreamCompiler<Spec>();

// Feed chunks as they arrive from any source
const { result, newPatches } = compiler.push("root: main\n");
compiler.push("elements:\n  main:\n    type: Card\n");

// Flush remaining data at end of stream
const { result: final } = compiler.flush();

// Reset for next stream (optionally with initial state)
compiler.reset({ root: "main", elements: {} });

Methods: push(chunk), flush(), getResult(), getPatches(), reset(initial?)

Edit Modes (from @json-render/core)

The YAML package uses the universal edit mode system from core:

import { buildEditInstructions, buildEditUserPrompt } from "@json-render/core";
import type { EditMode } from "@json-render/core";

// Generate edit instructions for YAML format
const instructions = buildEditInstructions({ modes: ["merge", "patch"] }, "yaml");

// Build user prompt with current spec context
const userPrompt = buildEditUserPrompt({
  prompt: "Change the title to Dashboard",
  currentSpec: spec,
  config: { modes: ["merge"] },
  format: "yaml",
  serializer: (s) => yamlStringify(s, { indent: 2 }).trimEnd(),
});

Fence Constants

For custom parsing, use the exported constants:

import {
  YAML_SPEC_FENCE,   // "```yaml-spec"
  YAML_EDIT_FENCE,   // "```yaml-edit"
  YAML_PATCH_FENCE,  // "```yaml-patch"
  DIFF_FENCE,        // "```diff"
  FENCE_CLOSE,       // "```"
} from "@json-render/yaml";

Key Exports

ExportDescription
yamlPromptGenerate YAML system prompt from catalog
createYamlTransformAI SDK TransformStream for YAML fences
pipeYamlRenderConvenience pipe wrapper (replaces pipeJsonRender)
createYamlStreamCompilerStreaming YAML parser with patch emission
YAML_SPEC_FENCEFence constant for yaml-spec
YAML_EDIT_FENCEFence constant for yaml-edit
YAML_PATCH_FENCEFence constant for yaml-patch
DIFF_FENCEFence constant for diff
FENCE_CLOSEFence close constant
diffToPatchesRe-export: object diff to JSON Patch
deepMergeSpecRe-export: RFC 7396 deep merge

Signals

GitHub stars
19k
Forks
985
Last commit
Oct 2026

Questions

What edit modes does it support?
It supports patch (RFC 6902), merge (RFC 7396), and unified diff. The editModes option controls which modes are documented in the generated prompt, and merge is the default.
What fence types does the transform recognize?
Four: yaml-spec for a full spec parsed progressively, yaml-edit for partial YAML deep-merged with the current spec, yaml-patch for RFC 6902 JSON Patch lines, and diff for a unified diff.
How do I handle multi-turn edits?
Pass the previous spec to pipeYamlRender using the previousSpec option, so incoming edits are applied against the current spec rather than starting fresh.
Advanced
Item type
skill
Key
yaml-vercel-labs
Source
github.com/vercel-labs/json-render