Claude Agent Skill · by Vercel Labs

Core

Install Core skill for Claude Code from vercel-labs/json-render.

Install
Terminal · npx
$npx skills add https://github.com/vercel-labs/skills --skill find-skills
Works with Paperclip

How Core fits into a Paperclip company.

Core drops into any Paperclip agent that handles this kind of work. Assign it to a specialist inside a pre-configured PaperclipOrg company and the skill becomes available on every heartbeat — no prompt engineering, no tool wiring.

S
SaaS FactoryPaired

Pre-configured AI company — 18 agents, 18 skills, one-time purchase.

$27$59
Explore pack
Source file
SKILL.md265 lines
Expand
---name: coredescription: Core package for defining schemas, catalogs, and AI prompt generation for json-render. Use when working with @json-render/core, defining schemas, creating catalogs, or building JSON specs for UI/video generation.--- # @json-render/core Core package for schema definition, catalog creation, and spec streaming. ## Key Concepts - **Schema**: Defines the structure of specs and catalogs (use `defineSchema`)- **Catalog**: Maps component/action names to their definitions (use `defineCatalog`)- **Spec**: JSON output from AI that conforms to the schema- **SpecStream**: JSONL streaming format for progressive spec building ## Defining a Schema ```typescriptimport { defineSchema } from "@json-render/core"; export const schema = defineSchema((s) => ({  spec: s.object({    // Define spec structure  }),  catalog: s.object({    components: s.map({      props: s.zod(),      description: s.string(),    }),  }),}), {  promptTemplate: myPromptTemplate, // Optional custom AI prompt});``` ## Creating a Catalog ```typescriptimport { defineCatalog } from "@json-render/core";import { schema } from "./schema";import { z } from "zod"; export const catalog = defineCatalog(schema, {  components: {    Button: {      props: z.object({        label: z.string(),        variant: z.enum(["primary", "secondary"]).nullable(),      }),      description: "Clickable button component",    },  },});``` ## Generating AI Prompts ```typescriptconst systemPrompt = catalog.prompt(); // Uses schema's promptTemplateconst systemPrompt = catalog.prompt({ customRules: ["Rule 1", "Rule 2"] });``` ## SpecStream Utilities For streaming AI responses (JSONL patches): ```typescriptimport { createSpecStreamCompiler } from "@json-render/core"; const compiler = createSpecStreamCompiler<MySpec>(); // Process streaming chunksconst { result, newPatches } = compiler.push(chunk); // Get final resultconst finalSpec = compiler.getResult();``` ## Dynamic Prop Expressions Any prop value can be a dynamic expression resolved at render time: - **`{ "$state": "/state/key" }`** - reads a value from the state model (one-way read)- **`{ "$bindState": "/path" }`** - two-way binding: reads from state and enables write-back. Use on the natural value prop (value, checked, pressed, etc.) of form components.- **`{ "$bindItem": "field" }`** - two-way binding to a repeat item field. Use inside repeat scopes.- **`{ "$cond": <condition>, "$then": <value>, "$else": <value> }`** - evaluates a visibility condition and picks a branch- **`{ "$template": "Hello, ${/user/name}!" }`** - interpolates `${/path}` references with state values- **`{ "$computed": "fnName", "args": { "key": <expression> } }`** - calls a registered function with resolved args `$cond` uses the same syntax as visibility conditions (`$state`, `eq`, `neq`, `not`, arrays for AND). `$then` and `$else` can themselves be expressions (recursive). Components do not use a `statePath` prop for two-way binding. Instead, use `{ "$bindState": "/path" }` on the natural value prop (e.g. `value`, `checked`, `pressed`). ```json{  "color": {    "$cond": { "$state": "/activeTab", "eq": "home" },    "$then": "#007AFF",    "$else": "#8E8E93"  },  "label": { "$template": "Welcome, ${/user/name}!" },  "fullName": {    "$computed": "fullName",    "args": {      "first": { "$state": "/form/firstName" },      "last": { "$state": "/form/lastName" }    }  }}``` ```typescriptimport { resolvePropValue, resolveElementProps } from "@json-render/core"; const resolved = resolveElementProps(element.props, { stateModel: myState });``` ## State Watchers Elements can declare a `watch` field (top-level, sibling of type/props/children) to trigger actions when state values change: ```json{  "type": "Select",  "props": { "value": { "$bindState": "/form/country" }, "options": ["US", "Canada"] },  "watch": {    "/form/country": { "action": "loadCities", "params": { "country": { "$state": "/form/country" } } }  },  "children": []}``` Watchers only fire on value changes, not on initial render. ## Validation Built-in validation functions: `required`, `email`, `url`, `numeric`, `minLength`, `maxLength`, `min`, `max`, `pattern`, `matches`, `equalTo`, `lessThan`, `greaterThan`, `requiredIf`. Cross-field validation uses `$state` expressions in args: ```typescriptimport { check } from "@json-render/core"; check.required("Field is required");check.matches("/form/password", "Passwords must match");check.lessThan("/form/endDate", "Must be before end date");check.greaterThan("/form/startDate", "Must be after start date");check.requiredIf("/form/enableNotifications", "Required when enabled");``` ## User Prompt Builder Build structured user prompts with optional spec refinement and state context: ```typescriptimport { buildUserPrompt } from "@json-render/core"; // Fresh generationbuildUserPrompt({ prompt: "create a todo app" }); // Refinement with edit modes (default: patch-only)buildUserPrompt({ prompt: "add a toggle", currentSpec: spec, editModes: ["patch", "merge"] }); // With runtime statebuildUserPrompt({ prompt: "show data", state: { todos: [] } });``` Available edit modes: `"patch"` (RFC 6902 JSON Patch), `"merge"` (RFC 7396 Merge Patch), `"diff"` (unified diff). ## Spec Validation Validate spec structure and auto-fix common issues: ```typescriptimport { validateSpec, autoFixSpec } from "@json-render/core"; const { valid, issues } = validateSpec(spec);const fixed = autoFixSpec(spec);``` ## Visibility Conditions Control element visibility with state-based conditions. `VisibilityContext` is `{ stateModel: StateModel }`. ```typescriptimport { visibility } from "@json-render/core"; // Syntax{ "$state": "/path" }                    // truthiness{ "$state": "/path", "not": true }      // falsy{ "$state": "/path", "eq": value }      // equality[ cond1, cond2 ]                         // implicit AND // Helpersvisibility.when("/path")                 // { $state: "/path" }visibility.unless("/path")               // { $state: "/path", not: true }visibility.eq("/path", val)              // { $state: "/path", eq: val }visibility.and(cond1, cond2)             // { $and: [cond1, cond2] }visibility.or(cond1, cond2)              // { $or: [cond1, cond2] }visibility.always                        // truevisibility.never                         // false``` ## Built-in Actions in Schema Schemas can declare `builtInActions` -- actions that are always available at runtime and auto-injected into prompts: ```typescriptconst schema = defineSchema(builder, {  builtInActions: [    { name: "setState", description: "Update a value in the state model" },  ],});``` These appear in prompts as `[built-in]` and don't require handlers in `defineRegistry`. ## StateStore The `StateStore` interface allows external state management libraries (Redux, Zustand, XState, etc.) to be plugged into json-render renderers. The `createStateStore` factory creates a simple in-memory implementation: ```typescriptimport { createStateStore, type StateStore } from "@json-render/core"; const store = createStateStore({ count: 0 }); store.get("/count");         // 0store.set("/count", 1);      // updates and notifies subscribersstore.update({ "/a": 1, "/b": 2 }); // batch update store.subscribe(() => {  console.log(store.getSnapshot()); // { count: 1 }});``` The `StateStore` interface: `get(path)`, `set(path, value)`, `update(updates)`, `getSnapshot()`, `subscribe(listener)`. ## Key Exports | Export | Purpose ||--------|---------|| `defineSchema` | Create a new schema || `defineCatalog` | Create a catalog from schema || `createStateStore` | Create a framework-agnostic in-memory `StateStore` || `resolvePropValue` | Resolve a single prop expression against data || `resolveElementProps` | Resolve all prop expressions in an element || `buildUserPrompt` | Build user prompts with refinement and state context || `buildEditUserPrompt` | Build user prompt for editing existing specs || `buildEditInstructions` | Generate prompt section for available edit modes || `isNonEmptySpec` | Check if spec has root and at least one element || `deepMergeSpec` | RFC 7396 deep merge (null deletes, arrays replace, objects recurse) || `diffToPatches` | Generate RFC 6902 JSON Patch operations from object diff || `EditMode` | Type: `"patch" \| "merge" \| "diff"` || `validateSpec` | Validate spec structure || `autoFixSpec` | Auto-fix common spec issues || `createSpecStreamCompiler` | Stream JSONL patches into spec || `createJsonRenderTransform` | TransformStream separating text from JSONL in mixed streams || `parseSpecStreamLine` | Parse single JSONL line || `applySpecStreamPatch` | Apply patch to object || `StateStore` | Interface for plugging in external state management || `ComputedFunction` | Function signature for `$computed` expressions || `check` | TypeScript helpers for creating validation checks || `BuiltInAction` | Type for built-in action definitions (`name` + `description`) || `ActionBinding` | Action binding type (includes `preventDefault` field) |