Agent skill

App Builder

by vellum-ai in vellum-ai/vellum-assistant

Build and edit small, personal visual tools and artifacts — dashboards, trackers, calculators, data visualizations, charts, simple landing pages, and slide decks the user wants for THEMSELVES.

MITAuto-check: warningsFrontend & Design

Install App Builder

The automated check flagged lines worth reading first. See the safety section below.

skills CLI
$ npx skills add vellum-ai/vellum-assistant --skill app-builder -a claude-code

Project install by default; add -g for ~/.claude/skills/.

GitHub CLI
$ gh skill install vellum-ai/vellum-assistant app-builder --agent claude-code

Project scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).

Manual copy
$ git clone --depth 1 https://github.com/vellum-ai/vellum-assistant.git skills-src && mkdir -p .claude/skills && cp -r skills-src/assistant/src/config/bundled-skills/app-builder .claude/skills/app-builder && rm -rf skills-src

Use ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.

Claude Code skills documentation · loads skills from .claude/skills/

Facts

Skill name
app-builder
GitHub stars
1.4k
Token cost
~7.1k tokens
SKILL.md length
2,908 words
Files
20 (incl. references)
Skills in repo
108
Repo updated
First seen
Licence
MIT

At a glance

Build and edit small, personal visual tools and artifacts — dashboards, trackers, calculators, data visualizations, charts, simple landing pages, and slide decks the user wants for THEMSELVES.

  • Works in 7 steps: Preflight — optional profile switch → Plan and build, fast → Design the data schema (only if it… → …
  • Tasks that involve Data visualization
  • SKILL.md covers Scope — what belongs here,…, Filesystem layout, Responsive & design system and Build workflow, plus 5 more sections
  • Runs TypeScript scripts from its folder

What it does

App Builder is an agent skill from vellum-ai/vellum-assistant. Build and edit small, personal visual tools and artifacts — dashboards, trackers, calculators, data visualizations, charts, simple landing pages, and slide decks the user wants for THEMSELVES. This is the right skill whenever the user asks to "visualize this," "make a chart," or "build an artifact" for their own use, or to edit an app they already built here. Do NOT reach for a uishow dynamicpage to fake an artifact — build a real persistent app here. A one-off diagram, chart, or explainer that just accompanies…

Its SKILL.md is about 7.1k tokens, which your agent loads only when the skill is triggered. The skill folder holds 22 other files, including reference files (for example `TOOLS.json`, `references/CUSTOM_ROUTES.md` and `references/DESIGN_SYSTEM.md`).

It sits in Frontend & Design, covering Data visualization, Landing pages and Slides and decks. The repository describes itself as: An AI Assistant that’s easy to setup, does your work 24/7, knows your preferences and gets better over time. The licence is MIT.

When your agent uses it

  • Tasks that involve Data visualization
  • Tasks that involve Landing pages
  • Tasks that involve Slides and decks

Example prompts

  • “visualize this,”
  • “make a chart,”
  • “build an artifact”
  • “/app-builder”

Requirements

  • Node.js

Workflow steps

7 steps, taken from the step headings in SKILL.md.

  1. Preflight — optional profile switch
  2. Plan and build, fast
  3. Design the data schema (only if it persists data)
  4. Create the app (scaffold, then expand)
  5. Compile
  6. Show the preview card
  7. Iteration

What it can do on your machine

Read from SKILL.md and the folder at commit 844117a. It shows what the files ask for, not the result of running them.

  • Tool permissions

    Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.

    From allowed-tools in the SKILL.md frontmatter.

  • Runs code

    Ships script files (TypeScript, from the files we listed), which the agent can run.

    From the folder's file list and the shell code blocks in SKILL.md.

  • Network

    No URLs in SKILL.md.

    From URLs in SKILL.md, links to its own repository left out.

  • Credentials

    Names no API keys, tokens, secrets or passwords.

    From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.

Context cost

App Builder loads about 7.1k tokens when it runs, and up to ~22k if it reads all its reference files. Until then it costs about 182 tokens; SKILL.md has 2,908 words of instructions outside code blocks.

Always · name and description, kept in context so the agent knows when to use it
~182
When it runs · the whole SKILL.md, loaded when a task matches
~7.1k
With references · SKILL.md plus every file in references/, read only if the agent opens them
~22k

Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.

Safety

Auto-check: warnings

The automated check found patterns that need a careful read before installing.

  • WarningTells the agent its actions are pre-authorized / not to stop for confirmationSKILL.md:22
    sign* below), and build it immediately. Don't ask permission to be creative — pick the colors, the layout, the atmospher

Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.

SKILL.md

The full file from vellum-ai/vellum-assistant at commit 844117a, republished under its MIT licence (© vellum-ai). 2,908 words, ~7,074 tokens.

Download SKILL.mdSave it as .claude/skills/app-builder/SKILL.md (or your agent's skills folder). This skill also uses 19 other files; get the full folder from GitHub.
name
app-builder
description
Build and edit small, personal visual tools and artifacts — dashboards, trackers, calculators, data visualizations, charts, simple landing pages, and slide decks the user wants for THEMSELVES. This is the right skill whenever the user asks to "visualize this," "make a chart," or "build an artifact" for their own use, or to edit an app they already built here. Do NOT reach for a ui_show dynamic_page to fake an artifact — build a real persistent app here. A one-off diagram, chart, or explainer that just accompanies an answer belongs to the visualize skill (ui_show visual), not an app. NOT for complex, multi-user, or shippable products — those go to a real project folder with a coding agent (see Scope below).
metadata.emoji
🛠️

You build small, personal visual tools — dashboards, trackers, calculators, data visualizations, simple landing pages, and slide decks. These are quick, single-user tools the user wants for themselves, not products they ship to other people.

Move fast: think, plan in one pass, pick a striking visual direction following the frontend-design skill (included with this load — see Included Skill: Frontend Design below), and build it immediately. Don't ask permission to be creative — pick the colors, the layout, the atmosphere, the micro-interactions. Every tool gets its own identity: a plant tracker feels earthy and green, a finance dashboard precise and navy. They should feel designed, not generated.

Design quality is delegated to the frontend-design skill, and you MUST follow it completely. That skill owns the aesthetics (typography, color, motion); this skill owns the technical infrastructure (sandbox, data, widgets, lifecycle). Its instructions load automatically with this skill — if they are missing (listed under Suggested Included Skills (not loaded)), call skill_load("frontend-design") before building anything. Building without them gives generic, templated UI, which is a failed build.


Scope — what belongs here, what doesn't

Build here (the default — lean toward it): a tool the user wants for themselves. A dashboard, tracker, calculator, data viz, slide deck, or a simple landing page they'll use on their own. Personal and self-contained.

Does NOT belong here: anything complex, multi-user, or meant to be published, deployed, handed off, or shipped to other people. Sandbox apps are single-user, run only in this preview, and can't be exported or deployed. They're the wrong home for a real product.

When a request is for a shippable/complex app, don't build in the sandbox. Instead:

  1. Explain the approach in a sentence: a real product belongs in a project folder they own — version-controlled, deployable, shareable — and you'll build it with them as a coding agent, not inside a preview.
  2. Establish a project folder (propose a path, or use one they name).
  3. Hand off to a coding agent: skill_load("acp") → acp_spawn({ task: "<what to build>", cwd: "<folder>" }) (agent defaults to claude), then follow the acp skill.

Triage on intent, not artifact type. A simple landing page is a personal build by default — it only becomes a handoff when the user signals they want to publish or share it. When the signal is weak, lean personal and just build. If you genuinely can't tell, ask exactly one short question.

Editing an existing sandbox app? Skip scope entirely — that's iteration. Resolve the app (see below), open it, and go to Iteration.

Resolving an app the user mentions

app_open takes an app_id, not a name:

  1. If the app_id is already in your context, use it.
  2. Otherwise app_list(query: "<what they said>") returns matches with app_id + name. app_list() with no query lists everything.
  3. One match → open it. Multiple → list them and ask which. None → say so, show what exists, offer to build it.

Filesystem layout

Apps live under /workspace/data/apps/:

/workspace/data/apps/
  <slug>.json          # App metadata
  <slug>/
    src/               # Source files (TSX) — what you write
    dist/              # Compiled output, generated by app_refresh or assistant apps refresh
    records/           # Data records (one JSON file per record)
  <slug>.preview       # Preview image (auto-generated)

Metadata fields: id, name, description, icon, schemaJson, createdAt, updatedAt, formatVersion, dirName. Records: { "id", "appId", "data": {...}, "createdAt", "updatedAt" } — the system auto-adds everything but data.

Every app is multi-file TSX (formatVersion: 2). Never write a root-level index.html or pages/ — all source lives under src/.

⚠️ Correct source path is /workspace/data/apps/<slug>/src/. Never /workspace/apps/.


Responsive & design system

Every app works phone (~360px) to desktop (~1400px+). The <turn_context> block carries a client_os: field (the OS the user is on): ios/android → mobile-first (design narrow first, body 17px); macos/windows/web → desktop-first (multi-column, body 14px); absent → desktop-first unless the request implies phone use ("for my iPhone"). (The sibling interface: field is the transport surface, always web for the apps, so key layout off client_os, not interface.)

Universal baseline — every build, regardless of client_os:

  • Viewport meta: width=device-width, initial-scale=1, viewport-fit=cover. Never user-scalable=no (blocks accessibility zoom).
  • Pad the root with env(safe-area-inset-*) so content clears the notch: padding-top: max(var(--v-spacing-lg), env(safe-area-inset-top)), mirrored for the other sides.
  • Full-height containers use 100dvh, not 100vh.
  • Form controls (input/textarea/select) must be font-size: 16px+ or iOS Safari zooms on focus. Add inputmode (numeric/decimal/email/tel/url).
  • Interactive elements ≥44×44pt (.v-button already complies; custom controls set min-height: 44px). Gate hover behind @media (hover: hover).
  • Fluid widths only — %, fr, minmax, clamp(), never fixed px on containers. Size chart containers in vw/%. At narrow widths, collapse tables into stacked label-value cards.

Mobile-first extras (client_os: ios / android): body --v-font-size-lg (17px); one column by default, multi-column only above @media (min-width: 720px); bottom-anchor the primary action (position: sticky; bottom: env(safe-area-inset-bottom)); bottom sheets instead of side modals.

Full detail when reachable: {baseDir}/references/RESPONSIVE.md.

A design-system CSS and CSS widget library are auto-injected (inside a @layer, so your own styles always win). Use the --v-* variables and .v-* classes below — they switch light/dark automatically, no manual dark-mode CSS needed. For charts, bundle chart.js (an allowed package), or hand-write inline SVG / CSS bars for tiny sparklines — sized to the container so they can't overflow.

Design tokens (use these, don't invent hex values):

CategoryTokens
Backgrounds--v-bg, --v-surface, --v-surface-border
Text--v-text, --v-text-secondary, --v-text-muted
Accent--v-accent, --v-accent-hover
Status--v-success, --v-danger, --v-warning
Spacing--v-spacing-xxs(2) -xs(4) -sm(8) -md(12) -lg(16) -xl(24) -xxl(32) -xxxl(48)
Radius--v-radius-xs(2) -sm(4) -md(8) -lg(12) -xl(16) -pill(999)
Shadows--v-shadow-sm/md/lg
Typography--v-font-family, --v-font-mono, --v-font-size-xs(10) -sm(11) -base(14) -lg(17) -xl(22) -2xl(26)
Animation--v-duration-fast(.15s) -standard(.25s) -slow(.4s)
Palettes--v-slate/emerald/violet/indigo/rose/amber-{950..50}
Constant--v-aux-white (always #FFF both modes — text on filled/accent backgrounds)

Utility classes: .v-button (.secondary/.danger/.ghost), .v-card, .v-list/.v-list-item, .v-badge (.success/.warning/.danger), .v-input-row, .v-empty-state, .v-toggle.

Theme: the --v-* tokens switch light/dark on their own. For custom (non-token) colors that must follow the theme, use @media (prefers-color-scheme: dark) in CSS.

For a custom branded look, write complete CSS with hardcoded colors + @media (prefers-color-scheme: dark) — don't mix --v-* auto-switching vars with hardcoded colors in the same element.

⚠️ Never hardcode color: white / #fff — use var(--v-aux-white) on filled/accent backgrounds, var(--v-text) / var(--v-text-secondary) on surfaces. Hardcoded white goes invisible on light surfaces.

Full detail when reachable: {baseDir}/references/DESIGN_SYSTEM.md. Note: in local dev these reference files live outside the app's sandbox and may not be readable — the essentials here are self-contained, so you can build without them.

Widget library (auto-injected)

CSS classes for standard patterns: .v-metric-card/.v-metric-grid (big-number stats), .v-data-table (sortable, sticky header, th[data-sortable]), .v-tabs, .v-accordion, .v-search-bar, .v-timeline, .v-action-list (rows with per-item actions), .v-card-grid, .v-progress-bar, .v-status-badge (.success/.error/.warning/.info), .v-stat-row/.v-stat, .v-tag-group, .v-avatar-row. Landing-page components: .v-hero/.v-hero-badge/.v-hero-subtitle, .v-section-header/.v-section-label, .v-feature-grid/.v-feature-card, .v-pullquote, .v-comparison (.before/.after), .v-page, .v-gradient-text, .v-animate-in. Domain widgets: .v-weather-card, .v-stock-ticker, .v-receipt, .v-invoice, .v-itinerary, .v-boarding-pass.

Interactive behavior is your own JS: charts → the bundleable chart.js (or inline SVG for tiny sparklines); formatting → Intl.NumberFormat / Intl.DateTimeFormat; table sort/filter, tabs, accordions, toasts, countdowns → plain JS wired to the .v-* markup.

Use custom HTML for novel/creative UIs (games, art tools); the .v-* classes for standard patterns; mix freely. Full list: {baseDir}/references/WIDGETS.md.


Build workflow

0. Preflight — optional profile switch

App builds are multi-step and benefit from a stronger model. If the active model profile looks weak for this work, you may offer to switch profiles first. Use the ui_show tool to ask, with surface_type: "confirmation" and await_action: true, so the user explicitly opts in before anything changes. Do not call the shell command assistant ui confirm for this — it can block the build flow before app work starts. If the user declines, just proceed on the current profile.

1 — Plan and build, fast

Think (what's the tool, who's the single user), plan in one pass (visual direction, minimal schema, core layout), then build. No wireframes, no mockups, no color questions. Make the creative calls yourself. Only ask a question when the request is genuinely ambiguous about what to build — and even then, prefer building something strong from context clues.

2 — Design the data schema (only if it persists data)

A JSON Schema for a single record. The system auto-adds id, appId, createdAt, updatedAt — define only user-facing fields. Keep it flat (string, number, boolean); encode nested data as JSON strings.

json
{
  "type": "object",
  "properties": {
    "title":  { "type": "string" },
    "status": { "type": "string", "enum": ["todo", "doing", "done"] }
  },
  "required": ["title"]
}

Calculators, single-page tools, landing pages, and slide decks skip this — pass an empty schema_json or omit it.

3 — Create the app (scaffold, then expand)

⚠️ app_create is ONE-SHOT per build. Call it exactly once. After it returns an app_id, all further changes go through file_write / file_edit and a single compile (assistant apps refresh or app_refresh). To start over: app_delete(app_id) first, then a fresh app_create.

Apps are multi-file Preact + TSX projects; esbuild bundles when you compile. Structure:

src/
  index.html          # Minimal shell that loads the bundle
  main.tsx            # Renders <App /> into #app
  components/App.tsx  # Top-level component
  styles.css          # Global styles (import from TSX)
tsx
import { render } from "preact";
import { App } from "./components/App";
import "./styles.css";
render(<App />, document.getElementById("app")!);

Scaffold-then-expand is the pattern for every non-trivial app. Cramming all files into one app_create blows the response token budget mid-emit:

  1. app_create with a 4-file scaffold: src/index.html, src/main.tsx, a placeholder src/components/App.tsx (<div>Loading...</div>), and an empty src/styles.css. The placeholders make the first compile clean — a 2-file scaffold leaves broken imports.
  2. file_write each real file, one per tool call, overwriting the placeholders and adding components.
  3. Compile ONCE at the end. File edits do not compile on their own. Use assistant apps inspect <name> to see whether source drifted, then assistant apps refresh <name> (or app_refresh).

Actually write the files. Source code in reasoning/thinking is invisible to the app sandbox and is not a file write. Put every real file body in an app_create.source_files, file_write, file_edit, or app_update.source_files tool call, then verify the files exist before compiling when there is any doubt.

Allowed packages (esbuild-resolved, no CDN): date-fns, chart.js, lodash-es, zod, clsx. For icons, write inline <svg> markup directly — no icon package is bundled.

Constraints: Preact not React. No CDN imports. No external fonts/images (system fonts, inline CSS/SVG). Responsive only, no fixed-pixel widths. The WebView blocks navigation — href and form action don't work.

⚠️ compile_errors in the app_create response is NOT a retry signal — the response also has an app_id, so the app was created. Proceed. Calling app_create again makes a duplicate.

app_create accepts EXACTLY these 6 keys — nothing else

name (optional — defaults to the preview title, else "New App"), description, schema_json, source_files, preview, auto_open.

Anything else fails with Invalid input for tool "app_create": Unknown parameter "X". The retired keys models still reach for:

  • html — old single-file shortcut. Put your HTML inside source_files["src/index.html"].
  • pages — retired. Multi-page apps use TSX components under src/components/.
  • icon: NOT a top-level param. The icon goes in preview.icon as a Lucide icon name from the list below (e.g. preview: { title: "Bean Coffee", icon: "coffee" }). Pick the one that best says what the app is; it is drawn in the sidebar and the library, so an emoji or a URL is wrong here. For an AI-generated image icon, call app_generate_icon(app_id, description) after the app exists.
  • A file path as a top-level key (e.g. "src/components/Header.tsx") — these go inside source_files, or in a file_write after app_create.

If a prior session in your context shows app_create({ html }) or app_create({ pages }), that example is outdated — ignore it.

// ❌ Wrong                          // ✅ Right
app_create({                         app_create({
  name: "Landing",                     name: "Landing",
  html: "<!DOCTYPE...>"  // INVALID     source_files: {
})                                        "src/index.html": "<!DOCTYPE...>",
                                          "src/main.tsx": "...",
                                          "src/components/App.tsx": "...",
                                          "src/styles.css": ""
                                        }
                                      })

Key notes: preview — always include, title required (plus optional subtitle, description, icon, up to 3 metrics). auto_open — always pass false so you don't get a duplicate preview card (Step 5 owns surfacing).

App icon names (preview.icon, kebab-case, one of): calculator, calendar, list-todo, list-checks, square-check, timer, clock, alarm-clock, notebook-pen, sticky-note, pencil, file-text, clipboard-list, bookmark, book, book-open, chart-bar, chart-line, chart-pie, table, square-kanban, database, gauge, activity, target, flag, trophy, wallet, dollar-sign, piggy-bank, credit-card, receipt, percent, shopping-cart, package, gift, ticket, mail, inbox, message-square, phone, bell, users, contact, music, headphones, mic, video, film, tv, play, image, camera, gamepad-2, puzzle, party-popper, smile, map, map-pin, compass, globe, plane, car, bus, bike, ship, truck, house, bed, briefcase, graduation-cap, languages, brain, lightbulb, heart, heart-pulse, dumbbell, pill, stethoscope, baby, paw-print, utensils, coffee, wine, beer, cake, apple, carrot, salad, egg, fish, cloud, sun, moon, umbrella, snowflake, thermometer, droplets, flame, leaf, mountain, code, terminal, cpu, bot, wifi, lock, key, shield, settings, wrench, plug, battery, search, link, hash, layers, folder-open, palette, pen-tool, ruler, scale, scissors, shirt, newspaper, repeat, shuffle, volume-2, speaker, star, sparkles, zap, rocket, home.

Show full SKILL.md (1,011 more words)Show less
4 — Compile

File edits do not compile on their own. After ALL file writes, compile once:

assistant apps inspect <name>
assistant apps refresh <name>

assistant apps inspect reports whether source changed since the last compile. assistant apps refresh compiles and refreshes open surfaces. app_refresh(app_id) also compiles. If compile fails, the response has error details; fix with file_edit, then compile again.

5 — Show the preview card
app_open(app_id, open_mode: "preview")

⚠️ Don't skip this — without it the user has no Open button, just your text. It fires after all writes, so the card shows final content (this is why auto_open must be false). Don't use open_mode: "workspace" unless the user explicitly asks for the full panel.

6 — Iteration

Editing an existing app means reusing its app_id — never app_create. Resolve it from name if needed (see Resolving an app), open it so the live result is visible, then:

  • file_edit — targeted changes (styles, fixes, small features), full path /workspace/data/apps/<slug>/src/...
  • file_write — new files or full rewrites
  • app_update — rename or change description/schema, and/or rewrite files via source_files, in one call. It recompiles for you, so no separate app_refresh is needed. Use this instead of editing <slug>.json by hand.
  • Full rebrand — still iteration, edit the existing files.

Then compile ONCE (assistant apps refresh <name> or app_refresh(app_id)) unless you used app_update, which already recompiled. If the change is substantial, app_open(app_id, open_mode: "preview") for a fresh card; for small tweaks the existing card stays valid.

⚠️ skill_load("app-builder") is required before every app_* call (including the first app_create). The skill can auto-unload between turns; without the reload, app_refresh / app_open error with "not currently active." It's idempotent — call it every time.


Using your assistant's tools and data

The point of these apps is to put the user's own data and the assistant's capabilities behind a real interface. Apps reach the assistant backend through custom routes.

Call routes with window.vellum.fetch("/v1/x/...") — never raw fetch(). Raw fetch fails in the sandboxed origin. This is how an app reads and writes persistent records, runs server-side logic, and touches files.

tsx
async function loadRecords() {
  const res = await window.vellum.fetch("/v1/x/my-route");
  if (!res.ok) { notifyError("Couldn't load"); return []; } // your own toast/inline error
  return res.json();
}

Always wrap calls in try/catch, check res.ok before parsing, and surface failures with a toast or inline error — never fail silently:

tsx
useEffect(() => {
  window.vellum.fetch("/v1/x/items")
    .then(res => res.ok ? res.json() : Promise.reject(res.status))
    .then(setItems)
    .catch(() => notifyError("Couldn't load")); // your own toast/inline error
}, []);

Bundled media — window.vellum.asset(path). For binary assets too big to inline (images, audio, short video, custom fonts), bundle the file under the app directory with file_write and load it at runtime via window.vellum.asset("assets/intro.mp4"), which resolves to a blob: URL the sandbox can use directly. Don't reach for giant base64 data-URIs.

tsx
const [src, setSrc] = useState("");
useEffect(() => {
  window.vellum.asset("assets/intro.mp4").then(setSrc).catch(() => notifyError("Couldn't load media"));
}, []);
return src ? <video src={src} controls /> : null;

Paths are validated server-side (no traversal, no records/); the file is served only from this app's own directory.

Live updates — window.vellum.subscribe({ tags }, cb). Instead of polling on a timer, subscribe to your own invalidation tags and refresh when the data actually changes. After a route mutates data it publishes a sync_changed event (import { publishEvent } from "@vellumai/plugin-api", then publishEvent({ …, message: { type: "sync_changed", tags: ["my-app:items"] } })); the app subscribes to that tag and re-fetches when it fires. Returns an unsubscribe function — call it on cleanup. Only your own custom tags are delivered (host namespaces like conversation:/assistant: are never forwarded), and the payload is just the changed tags — re-fetch through window.vellum.fetch for the data.

tsx
useEffect(() => {
  const off = window.vellum.subscribe({ tags: ["my-app:items"] }, () => {
    void loadItems(); // re-fetch on change — no polling
  });
  return off;
}, []);

Writing a route handler. Routes are .ts/.js files in {workspaceDir}/routes/, served at /v1/x/<filename> (routes/items.ts → /v1/x/items; routes/bar/index.ts → /v1/x/bar). Write them with file_write before app_refresh. Each exports named functions per HTTP method (GET/POST/PUT/PATCH/DELETE), receiving the Web Request. Full Node API access (fs, path, crypto), 30s timeout, hot-reloaded on change. No [id].ts dynamic segments — use query params.

typescript
// routes/items.ts
import { readFileSync, writeFileSync, mkdirSync, existsSync } from "node:fs";
import { join } from "node:path";
export const description = "Item CRUD — JSON file storage";        // optional, for `assistant routes list`
const FILE = join(process.env.VELLUM_WORKSPACE_DIR!, "data", "items.json");
const load = () => existsSync(FILE) ? JSON.parse(readFileSync(FILE, "utf-8")) : [];
const save = (x:unknown[]) => { mkdirSync(join(process.env.VELLUM_WORKSPACE_DIR!,"data"),{recursive:true}); writeFileSync(FILE, JSON.stringify(x,null,2)); };

export function GET(): Response { return Response.json(load()); }
export async function POST(req: Request): Promise<Response> {
  const item = { id: crypto.randomUUID(), ...(await req.json()), createdAt: new Date().toISOString() };
  const items = load(); items.push(item); save(items);
  return Response.json(item, { status: 201 });
}

To reach daemon capabilities, import from @vellumai/plugin-api — publishEvent({...}) to push real-time events to connected clients (UI updates, navigation, notifications), or runConversationTurn({...}) to post an inbound event into a conversation as a real assistant turn. (An older context second argument still works in-process but is deprecated — prefer these imports.) Full guide + copyable examples (Focus Timer, Habit Tracker, Expense Tracker): {baseDir}/references/CUSTOM_ROUTES.md, {baseDir}/references/examples/.

Persistence options: localStorage for ephemeral UI state (filters, view modes, drafts); custom routes for persistent records and server-side logic.


Interaction standards

  • Feedback for every action — a toast or inline confirmation after creates, deletes, updates, errors. Build your own (e.g. toggle the .v-toast class with JS).
  • Confirm destructive actions — render your own confirmation (an inline "Are you sure?" or a modal) before deleting or resetting.
  • Validate forms before submit, show errors inline, disable submit during async.
  • Loading states — skeleton or spinner, never a blank screen.
  • Designed empty states — .v-empty-state when there's no data.
Keep the assistant aware

Wire window.vellum.sendAction() during the build so the app can pull the assistant in. The host handles two actions: relay_prompt ({ prompt, conversation }) sends a message to the assistant as if the user typed it — the way to get an explanation, summary, or follow-up from inside the app (conversation: "new" starts a fresh chat instead of the open one); set_view ({ view }) arranges the app and chat ("split" / "full" / "chat"). These two are the whole app→host surface — relay anything you want the assistant to act on as a self-contained prompt. Patterns in {baseDir}/references/INTERACTION_HOOKS.md.

Actionable UI

For triage/bulk-action UIs: render selectable items + action buttons → the user selects and clicks → relay the choice as a prompt with window.vellum.sendAction("relay_prompt", { prompt: ... }), listing the selected items in the text, so the assistant can run the tools and report back. Render your own confirmation for destructive actions.


Slides

Slide decks are a different domain — skip app patterns (contextual headers, search/filter, toasts, form validation, custom routes). Build navigation and layouts with custom HTML/CSS. Templates and principles in {baseDir}/references/SLIDES.md.


SKILL COMPLETE WHEN

  • Request was scoped: personal build (sandbox) or complex/shippable (handed off to a project folder + coding agent)
  • Sandbox path: app_create returned an app_id; all files written via file_write; compile ran ONCE clean (assistant apps refresh or app_refresh); app_open(open_mode: "preview") rendered the card; user told what was built (3-6 bullets); iterations reflected live
  • Handoff path: project folder established; coding agent spawned via acp_spawn({ task, cwd }); user told work continues in the folder

Reference files

Read with file_read using the {baseDir}/references/... paths ({baseDir} resolves to this skill's directory):

  • RESPONSIVE.md — mobile vs desktop, universal baseline, safe areas
  • DESIGN_SYSTEM.md — token table, utility classes, theme/dark mode
  • WIDGETS.md — CSS widget classes (no JS chart/format runtime)
  • CUSTOM_ROUTES.md — server-side persistence and custom API routes
  • examples/ — complete copyable example apps
  • INTERACTION_HOOKS.md — relay_prompt / set_view app→host actions
  • SLIDES.md — presentation slide design

© vellum-ai, MIT. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file

Files

SKILL.md and 19 other files (references) in assistant/src/config/bundled-skills/app-builder of vellum-ai/vellum-assistant.

  • SKILL.md
  • TOOLS.json
  • icon.svg
  • references/CUSTOM_ROUTES.md
  • references/DESIGN_SYSTEM.md
  • references/INTERACTION_HOOKS.md
  • references/RESPONSIVE.md
  • references/SLIDES.md
  • references/WIDGETS.md
  • references/examples/README.md
  • references/examples/expense-tracker.md
  • references/examples/focus-timer.md
  • references/examples/habit-tracker.md
  • tools/app-create.ts
  • tools/app-delete.ts
  • tools/app-generate-icon.ts
  • tools/app-list.ts
  • tools/app-open.ts
  • … and 2 more

Open the folder on GitHubat commit 844117a

Compare with similar skills

App Builder next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.

App Builder compared with similar skills
SkillStarsUsed inTokensAuto-checkLicenceRepo updated
App Builder this skillvellum-ai/vellum-assistant1.4k—~7.1kAutomated safety check: WarnMIT
Pro Deck Builderthatrebeccarae/claude-marketing162—~6.1kAutomated safety check: PassMIT
Cc DesignZeroZ-lab/cc-design827—~2.2kAutomated safety check: NotesNone
Claude Designjiji262/claude-design-skill203—~3.6kAutomated safety check: PassMIT
Web Designdrewnekota/cetus146—~2.1kAutomated safety check: PassMIT
Vetta UI Designopenvetta/open-vetta291—~7.3kAutomated safety check: PassApache-2.0

Similar skills

  • Pro Deck Builder

    thatrebeccarae/claude-marketing

    Create polished HTML slide decks and PDF-ready documents for consulting deliverables.

    162 GitHub stars~6.1k tokensUpdated 4 mo ago
    Frontend & DesignAuto-check passed
  • Cc Design

    ZeroZ-lab/cc-design

    High-fidelity HTML design and prototype creation. An agent skill from ZeroZ-lab/cc-design.

    827 GitHub stars~2.2k tokensUpdated 3 mo ago
    Frontend & DesignAuto-check: notes
  • Claude Design

    jiji262/claude-design-skill

    Produce thoughtful, high-fidelity design artifacts in HTML — landing pages, slide decks, interactive prototypes, animated videos, posters, wireframes, and visual explorations.

    203 GitHub stars~3.6k tokensUpdated 2 mo ago
    Frontend & DesignAuto-check passed
  • Web Design

    drewnekota/cetus

    A skill your agent uses when building any web page, HTML artifact, landing page, dashboard, slide deck, report, email, or UI component the user will look at.

    146 GitHub stars~2.1k tokensUpdated today
    Frontend & DesignAuto-check passed
  • Vetta UI Design

    openvetta/open-vetta

    Build and edit design documents (.vetd) on the Vetta design canvas — app screens, landing pages, slides, posters, infographics.

    291 GitHub stars~7.3k tokensUpdated today
    Frontend & DesignAuto-check passed
  • Scroll Reveal Libraries

    freshtechbro/claudedesignskills

    Simple scroll-triggered reveal animations using AOS (Animate On Scroll).

    1k GitHub stars~4.3k tokensUpdated 10 mo ago
    Frontend & DesignAuto-check passed

More from vellum-ai/vellum-assistant

All 108 skills in this repo
  • Vellum GitHub App Setup

    vellum-ai/vellum-assistant

    Create and configure a GitHub App so the assistant can push commits, open PRs, and comment under its own bot identity.

    1.4k GitHub stars~3.1k tokensUpdated today
    Auto-check passed
  • Discord App Setup

    vellum-ai/vellum-assistant

    Connect a Discord bot to the assistant via the Discord Gateway with guided application creation and intent configuration

    1.4k GitHub stars~4.2k tokensUpdated today
    Auto-check passed
  • Sentry App Setup

    vellum-ai/vellum-assistant

    Create and configure a Sentry internal integration so the assistant can manage issues, alerts, and releases under its own identity

    1.4k GitHub stars~1.3k tokensUpdated today
    Auto-check passed
  • Memory Corpus Ingest

    vellum-ai/vellum-assistant

    Ingest a large dataset into memory as a skimmed map. An agent skill from vellum-ai/vellum-assistant.

    1.4k GitHub stars~3k tokensUpdated today
    Auto-check: notes
  • Plugin Builder

    vellum-ai/vellum-assistant

    A skill your agent uses when the user wants to build, scaffold, ship, or edit a Vellum plugin that bundles multiple surfaces (hooks, tools, skills, and more) into one installable package.

    1.4k GitHub stars~3.1k tokensUpdated today
    Auto-check passed
  • Slack App Setup

    vellum-ai/vellum-assistant

    Connect a Slack app to the Vellum Assistant via Socket Mode.

    1.4k GitHub stars~2.5k tokensUpdated today
    Auto-check: warnings

Questions about App Builder

What does App Builder do?

Build and edit small, personal visual tools and artifacts — dashboards, trackers, calculators, data visualizations, charts, simple landing pages, and slide decks the user wants for THEMSELVES. App Builder is an agent skill from vellum-ai/vellum-assistant. Build and edit small, personal visual tools and artifacts — dashboards, trackers, calculators, data visualizations, charts, simple landing pages, and slide decks the user wants for THEMSELVES.

When should I use App Builder?

App Builder fits situations like: tasks that involve Data visualization; tasks that involve Landing pages; tasks that involve Slides and decks.

How do I install App Builder in Claude Code?

Run `npx skills add vellum-ai/vellum-assistant --skill app-builder -a claude-code`. Or copy the skill folder (assistant/src/config/bundled-skills/app-builder in vellum-ai/vellum-assistant) into .claude/skills/app-builder in your project. Claude Code loads it when a task matches its description.

How do I install App Builder in Codex?

Run `npx skills add vellum-ai/vellum-assistant --skill app-builder -a codex`. Or copy the skill folder (assistant/src/config/bundled-skills/app-builder in vellum-ai/vellum-assistant) into .agents/skills/app-builder in your project. Codex loads it when a task matches its description.

Can I use App Builder in Cursor, Gemini CLI or GitHub Copilot?

Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add vellum-ai/vellum-assistant --skill app-builder -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/app-builder, .gemini/skills/app-builder, .github/skills/app-builder and .opencode/skills/app-builder in your project.

What does App Builder need to run?

Going by SKILL.md and its folder, App Builder needs TypeScript for the scripts in its folder. Our summary lists: Node.js.

Does App Builder access the network?

SKILL.md contains no URLs. Any network use would come from the scripts or tools the agent runs. This is read from the text; nothing was executed.

Is App Builder safe to install?

Our automated static check of SKILL.md flagged 1 warning(s): tells the agent its actions are pre-authorized / not to stop for confirmation. Read the flagged lines before installing; the check is not a guarantee either way.

What licence does App Builder use?

App Builder is published under the MIT licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.

How many tokens does App Builder use?

About 7.1k tokens (SKILL.md is roughly 28k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full. Its references folder adds about 15k tokens, read only when the agent opens those files.

What are the alternatives to App Builder?

Skills that share tags, products or a category with App Builder: Pro Deck Builder (thatrebeccarae/claude-marketing, 162 stars), Cc Design (ZeroZ-lab/cc-design, 827 stars), Claude Design (jiji262/claude-design-skill, 203 stars) and Web Design (drewnekota/cetus, 146 stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.

Who maintains App Builder?

vellum-ai (a GitHub organization) maintains it in vellum-ai/vellum-assistant, which has 1,400 GitHub stars. The repository holds 108 skills in this directory. The repository was last updated on October 9, 2026.

Source: vellum-ai/vellum-assistant on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.