Generated banner for Matlab Build App
Generated logo for Matlab Build App

Matlab Build App

MathWorksOfficialCreated by MathWorks

  • Skill
  • Workflow
  • Software development
  • BSD-2-Clause
  • No issues found

From the author

Build MATLAB apps from requirements to working code. Asks discovery questions (or skips them when the path is known), recommends UIFigure or UIHTML architecture, identifies layout archetype (Dashboard, Explorer, Tabbed, Wizard, Canvas), produces an implementation plan, and executes the build. For UIFigure apps, optionally serializes as App Designer (.mlapp or plain-text .m + .xml). Use when a user wants to build a MATLAB app, create a GUI, make an interactive tool, build a uifigure app, build a uihtml app, build an App Designer app, build a .mlapp app, build a plain-text App Designer app, or asks which approach to use. Also use when user describes spatial layout needs: dashboard, control panel, sidebar, tabs, wizard, stepper, canvas, workspace.
— the description by MathWorks

AutoGineer summary

Written by AutoGineer from the skill’s own files, not by the author

This skill provides a structured approach to developing MATLAB applications, guiding users from initial requirements to a fully implemented codebase. It helps determine the optimal architecture (UIFigure or UIHTML) and layout archetype (e.g., Dashboard, Explorer, Wizard) based on the user's specific needs, team expertise, and maintenance requirements. The skill enforces a rigorous planning phase, requiring an implementation plan before any code is written, and supports multiple serialization formats for UIFigure apps, including App Designer (.mlapp) and plain-text (.m + .xml) formats.

What it does

  • Conducts discovery to identify app purpose, maintenance needs, and visual requirements.
  • Recommends the best architecture (UIFigure or UIHTML) and layout archetype.
  • Produces a detailed implementation plan and writes it to a markdown file.
  • Supports building UIFigure apps with optional App Designer serialization.
  • Ensures structural integrity by enforcing grid-based layouts and proper background task handling.
  • Provides a clear, step-by-step build sequence based on internal documentation.

When to use it

  • When you need to build a new MATLAB GUI or interactive tool.
  • When you are unsure whether to use UIFigure or UIHTML for a specific project.
  • When you need to define a clear development plan for a complex MATLAB application.
  • When you want to create an App Designer app using either binary or plain-text formats.

Advantages

  • Ensures consistent, maintainable application architecture.
  • Prevents common pitfalls by enforcing proven layout and background task patterns.
  • Provides clear guidance on choosing between App Designer and programmatic approaches.
  • Facilitates collaboration by requiring a documented implementation plan before coding.

Usage examples

“I need to build a MATLAB dashboard to monitor sensor data. What approach should I take?”
The agent will ask discovery questions about the app's lifespan, team skills, and visual needs, then recommend an architecture and layout archetype before creating a plan.
“Build me a UIHTML app for visualizing experimental results.”
The agent will skip the architecture recommendation, ask for any missing requirements, and proceed to generate an implementation plan for a UIHTML-based app.

Install

Documentation by MathWorks

MATLAB Build App

Determine the best architecture for a MATLAB application, produce an implementation plan grounded in internal references, and execute the build. For UIFigure apps, optionally serialize into an App Designer format.

When to Use This Skill

Use this skill when:

  • User wants to build a MATLAB app, GUI, or interactive tool

  • User asks "how should I build this app?" or "which approach should I use?"

  • User describes an application — with or without specifying an implementation path

  • User mentions: MATLAB app, GUI, uifigure, uihtml, interactive tool, dashboard, visualization app, App Designer, .mlapp, plain-text app

  • User describes spatial layout needs: dashboard, control panel, sidebar, tabs, wizard, stepper, canvas, workspace

  • User has already chosen a path (e.g., "build me a uihtml app") — handle directly

When Not to Use

  • The request is purely about MATLAB computation with no UI component

  • The user is asking about an existing app they want to modify → read references/editing-guide.md

  • The user wants to convert between App Designer formats (e.g., .mlapp to plain-text or vice versa) → tell them to use File > Save As in App Designer. Do NOT attempt the conversion programmatically.

Critical Rules

  • MUST ask discovery questions before recommending a path — unless the user already specified one

  • MUST confirm the path choice with the user before producing the implementation plan

  • MUST produce an implementation plan grounded in internal references before writing any code

  • MUST write the plan to a file (<app-name>-plan.md) in the working directory

  • NEVER recommend a path without understanding the user's constraints (unless path was pre-specified)

  • NEVER apply dark mode, custom colors, or visual themes unless the user explicitly requests them

  • ALWAYS present the recommendation as guidance, not a mandate — the user decides

  • MUST choose archetype based on the user's primary task, not aesthetics

  • NEVER treat two archetypes as equals within one app — one is always the primary container

  • UIFigure app: MUST use uigridlayout for all structural layout — never Position-based sizing

  • UIHTML/web app: MUST use CSS Grid or Flexbox for chrome — no absolute positioning for structural panels

  • The chrome (header, sidebar, tabs, step indicator) MUST remain spatially stable

  • Background execution (any operation taking more than ~1 second) requires a class-structured app and MUST be read up first in references/background-tasks.md — do NOT hand-write parfeval/backgroundPool/DataQueue plumbing from memory. For an App Designer app (.mlapp or plain text) you MUST use the addBackgroundTask verb and NEVER hand-roll the infrastructure or reuse the standalone-programmatic manual wiring. For a standalone programmatic app, use the MVVM structure per that doc. A flat nested-function app that needs background work MUST escalate to one of these.

  • App Designer serialization: MUST read references/app-designer/agent-guide-shared.md (covers ownership models, editing discipline, property rules, quoting) plus the format-specific guide (agent-guide-mlapp.md or agent-guide-plaintext.md) before building. Those docs are the single source of truth; do not attempt to edit app files without reading them first.

Workflow

User request arrives
        │
        ├── Path NOT specified → Full Discovery
        │       │
        │       ▼
        │   Ask Q1-Q4 (purpose, lifespan, polish, team skills)
        │       │
        │       ▼
        │   Identify layout archetype
        │       │
        │       ▼
        │   Recommend UIFigure vs UIHTML based on Q1-Q4
        │       │
        │       ▼
        │   *** STOP: Present recommendation and WAIT for user confirmation ***
        │   (Do NOT produce a plan or read references until user says yes)
        │       │
        │       ▼
        │   Ask Q5 (FINAL): Serialization format? (UIFigure apps only)
        │       │
        │       ├── App Designer → release check, present format choice,
        │       │       continue with UIFigure references + add serialization step
        │       │
        │       └── Standalone programmatic → no extra step
        │       │
        │       ▼
        │   Produce Implementation Plan → write to <app-name>-plan.md
        │       │
        │       ▼
        │   User reviews plan → confirms or adjusts
        │       │
        │       ▼
        │   Begin building (read references per the plan)
        │
        └── Path IS specified
                │
                ├── Serialization explicit (e.g., ".mlapp app", "plain-text app")
                │       → Skip Q5, proceed with stated format
                │       → Ask only missing requirements + archetype if unclear
                │       → Produce Implementation Plan
                │
                ├── Architecture explicit but serialization not stated
                │   (e.g., "build me a uifigure app")
                │       → Still ask Q5 (serialization) before planning
                │       → Ask missing requirements + archetype if unclear
                │       → Produce Implementation Plan
                │
                └── UIHTML or standalone programmatic explicit
                        → Skip Q5 entirely (not applicable)
                        → Ask missing requirements + archetype if unclear
                        → Produce Implementation Plan

Discovery Questions

Ask these conversationally — not as a rigid checklist. Gather requirements and layout intent first; ask the serialization question last, once you understand what the app needs to do.

Core Questions

1. What does the app do and who is it for?

What will this app do? Who will use it?

Listen for archetype signals: "dashboard", "control panel", "step-by-step", "workspace".

2. Is this a quick tool or something you'll maintain over time?

Is this meant to be maintained and evolved, or is it more of a quick, proof-of-concept tool?

  • Maintained → proceed to remaining questions; team skills matter

  • Ephemeral → favor UIHTML app path; can skip team question

3. How polished does the UI need to look?

Are standard MATLAB buttons, sliders, tables, and plots enough? Or do you need custom visuals — branded, animated, or visually richer?

  • Standard controls sufficient → UIFigure app signal

  • Custom visuals needed → UIHTML app signal

4. Who will work on this app going forward?

Will this be maintained by people comfortable only with MATLAB, or by people also comfortable with web technologies?

Only ask for maintained apps.

  • MATLAB-only team → UIFigure app

  • Web-comfortable team → UIHTML app

5. (FINAL) How should this app be saved?

Do you want this app to open and edit inside App Designer, or do you prefer a standalone programmatic file (no App Designer dependency)?

This is a serialization question, not an architecture question. The app's structure (components, layout, callbacks) is designed using UIFigure knowledge regardless of the answer. Q5 only determines how that design is persisted to disk.

  • App Designer → .mlapp or plain-text .m + .xml. Check release (plain-text needs R2026b+). If Q3 indicated custom visuals, note that App Designer constrains visual customization vs UIHTML and confirm.

  • Standalone programmatic → programmatic .m code, no App Designer dependency. MVVM may warrant multiple files; that is decided at build time.

Follow-up Probes (only if path isn't clear)
  • Interaction style: Real-time feedback needed? → slight UIFigure lean

  • Existing work: Existing MATLAB UI code? → UIFigure. Existing web assets? → UIHTML

  • Distribution: May need to work outside MATLAB? → UIHTML

  • Long computations: Will any operation take more than a second? → use a background task (read references/background-tasks.md). Note this requires a class-structured app: App Designer serialization, or MVVM if standalone programmatic. Heavy, long, or one-shot work is ALWAYS a background task, never a timer; a timer fits only scheduled, cheap-per-tick work that must update the UI on the main thread (read references/timers.md).

Path Decision Logic

Two stages: first determine architecture (Q1-Q4), then determine serialization format (Q5).

Stage A — Architecture (from Q1-Q4):

Ephemeral app? → Strong default to UIHTML app

Maintained app? → Weigh signals:

Strong UIFigure signals:
  ✓ Maintained + MATLAB-only team
  ✓ Standard UI components sufficient
  ✓ Tight real-time interaction
  ✓ Existing MATLAB UI code

Strong UIHTML signals:
  ✓ Ephemeral (regardless of team)
  ✓ Maintained + web-skilled team
  ✓ Custom visuals, branded look, animations
  ✓ Existing web assets
  ✓ Future portability outside MATLAB

UIFigure + uihtml accent:
  Mostly standard app but needs one custom visualization panel.

Stage B — Serialization format (Q5, UIFigure apps only):

Q5 = Standalone → programmatic code (no App Designer). Done.

Q5 = App Designer → adds a serialization layer ON TOP of Stage A.
  UIFigure references still apply in full. Serialization is IN ADDITION TO,
  not instead of, the normal UIFigure build.
  → Check release, present format choice (plain text vs .mlapp).
  → If Stage A indicated UIHTML for custom visuals, surface the trade-off:
    App Designer constrains custom visuals — confirm before committing.

Weighting: 1. Architecture (Q1-Q4) 2. Serialization (Q5, applies only to UIFigure)

Paths at a Glance

ArchitectureKey strength
UIFigure appSingle language, any MATLAB dev can maintain
UIHTML appFull visual control, rich interactivity
UIFigure + accentBest of both when you need one custom visual

For UIFigure apps, three serialization formats:

FormatTrade-off
Programmatic .mStandalone, no App Designer dependency
App Designer .mlappBinary, works on any release, opens in App Designer
App Designer plain text .m + .xmlSource-controllable, AI-editable, R2026b+

Layout Archetype

Pick based on the user's primary task:

ArchetypePrimary user taskStructure
DashboardMonitor and compare at a glanceKPI cards + charts + table; read-only
ExplorerAdjust parameters, observe live resultsSidebar controls + live display
TabbedNavigate between independent sectionsTab bar + content panels
WizardComplete a sequential workflowStep indicator + one-step-at-a-time
CanvasCreate, inspect, or edit spatial artifactsCentral workspace + tools

If unclear, ask: "Will users mostly be watching results (Dashboard), tweaking controls (Explorer), switching sections (Tabbed), going through steps (Wizard), or working on a central figure (Canvas)?"

Implementation Plan

After confirming path and archetype, produce a plan and write it to <app-name>-plan.md in the working directory. Present a concise summary inline with the approval request.

Plan Template
**Implementation Plan: [App Name]**

**Architecture:** [UIFigure app / UIHTML app / UIFigure + accent]
**Serialization:** [Programmatic .m / App Designer .mlapp / App Designer plain text]
**Layout:** [Archetype] — [one sentence describing spatial structure]

**Structure:**
- [Major panel/area — spatial description]
- [e.g., "Left sidebar (220px) with date range picker, category filter, refresh button"]
- [e.g., "Main area with line chart showing filtered results"]

**Key behaviors:**
- [User-visible interaction effects]

**Internal references that will be used:**

| Reference | Role in this app |
|-----------|-----------------|
| `references/path/file.md` | [what it provides] |
| ... | ... |

**External skills:**
- `matlab-build-chart` — [role, if applicable]
- `matlab-apply-theme` — [role, if applicable]

**File organization:**
[app directory tree]

**Implementation sequence:**
1. [First reference read] — [what it establishes]
2. [Next reference] — [what it adds]
3. [...]

Each reference pointer carries provenance: [src: references/uifigure/grid-layout.md §Spanning]

Plan Quality Checks

Before presenting:

  • [ ] Every reference listed has a concrete role

  • [ ] Structure uses spatial terms the user can visualize

  • [ ] Behaviors describe user-visible effects

  • [ ] Implementation sequence shows a logical build order

  • [ ] Plan is specific enough for "yes, that's what I want" or "change X"

Reference Router

After plan approval, read the relevant internal references to execute the build.

UIFigure Path
When building...Read
Grid layout, sizing, componentsreferences/uifigure/guide.md
Grid details (spanning, collapse)references/uifigure/grid-layout.md
Panels, tab groups, nested gridsreferences/uifigure/containers.md
Component reference (controls, display)references/uifigure/components.md
Callback patterns, data sharingreferences/uifigure/callbacks.md
Layout recipes (sidebar, form, split)references/uifigure/layout-patterns.md
MVVM architecture (complex apps)references/uifigure/mvvm-guide.md
View binding patternsreferences/uifigure/mvvm-view-binding.md
ViewModel testingreferences/uifigure/mvvm-testing.md
Background execution — concepts + routing (read first)references/background-tasks.md
Background execution — standalone programmatic (MVVM) wiringreferences/uifigure/mvvm-background-tasks.md
Timers — periodic main-thread work (NOT for offloading heavy work)references/timers.md
UIHTML Path
When building...Read
MATLAB-JS bridge, setup(), eventsreferences/uihtml/bridge-guide.md
Communication patterns (4 patterns)references/uihtml/communication-patterns.md
Data type conversionreferences/uihtml/data-types.md
Platform constraintsreferences/uihtml/platform-limitations.md
uihtml creation, hybrid layoutsreferences/uihtml/setup.md
Error handling (both sides)references/uihtml/error-handling.md
JS MVVM architecturereferences/uihtml/mvvm-guide.md
Observable/Computed classesreferences/uihtml/mvvm-observable-classes.md
JS View bindingreferences/uihtml/mvvm-view-binding.md
JS coding patterns, modulesreferences/uihtml/js-coding-guide.md
JS testing & debuggingreferences/uihtml/js-testing-debugging.md
Chart.js setup & patternsreferences/uihtml/charting-guide.md
Chart type selectionreferences/uihtml/chart-type-selection.md
Chart.js initializationreferences/uihtml/chartjs-setup.md
Line & bar chartsreferences/uihtml/line-bar-charts.md
Doughnut & scatter chartsreferences/uihtml/doughnut-scatter-charts.md
Chart data updatesreferences/uihtml/chart-updates.md
Chart ↔ bridge integrationreferences/uihtml/chart-bridge-integration.md
Chart performancereferences/uihtml/chart-performance.md
CSS styling & tokensreferences/uihtml/styling-guide.md
Component CSS (buttons, inputs)references/uihtml/component-styles.md
CSS layout patternsreferences/uihtml/css-layout-patterns.md
Brand design tokensreferences/uihtml/brand-design-tokens.md
Dark modereferences/uihtml/dark-mode.md
External color schemesreferences/uihtml/external-color-schemes.md
App Designer Serialization (UIFigure apps only)

Important: App Designer serialization is an additional step AFTER the normal UIFigure build. You MUST also read the UIFigure path references above (components, grid-layout, callbacks, containers, layout-patterns) to design the app's structure. The serialization references below cover only how to persist that design to disk.

Both formats use the same AppDesignerAgentInterface API via the bundled scripts/ tool; only the file extension passed to create()/open() differs.

Read first (both formats):

When building...Read
Verbs, build sequence, editing, save()/validate()/finalize(), inspect()references/app-designer/agent-guide-shared.md
Background execution — concepts + routing (read first)references/background-tasks.md
Background execution — addBackgroundTask verb referencereferences/app-designer/background-tasks.md

Plain-text (.m + .xml):

When building...Read
Ownership model, .xml authoring, flow, gotchasreferences/app-designer/agent-guide-plaintext.md
classdef structure & block ordering rulesreferences/app-designer/plaintext/classdef-template.md
XML structure and which properties to setreferences/app-designer/plaintext/xml-template.md
Per-component property names, types, defaultsreferences/app-designer/plaintext/property-reference.md
Authoritative XML schemareferences/app-designer/plaintext/matlabAppSchema.xsd

Binary .mlapp:

When building...Read
Build flow, native property values, save()/finalize()references/app-designer/agent-guide-mlapp.md
Editing an Existing App
When editing...Read
Any existing app (determines format, routes to approach)references/editing-guide.md
Archetype References
ArchetypeFile
Dashboardreferences/archetypes/dashboard.md
Explorerreferences/archetypes/explorer.md
Tabbedreferences/archetypes/tabbed.md
Wizardreferences/archetypes/wizard.md
Canvasreferences/archetypes/canvas.md
External Skills (invoked, not read)
  • matlab-build-chart — when the app includes MATLAB plots (UIFigure path or UIFigure+accent)

  • matlab-apply-theme — when the app needs dark mode, brand colors, or custom palettes (UIFigure path)

After Plan Approval

All UIFigure apps (regardless of serialization format)
  1. Read the archetype reference for the spatial skeleton

  2. If MVVM warranted (Explorer, Wizard, Canvas, or complex apps): read the architecture reference

  3. Read the UIFigure guide to establish layout (grid, components, containers)

  4. Layer in path-specific references per the implementation sequence

  5. For visual polish: invoke matlab-apply-theme (UIFigure) or read styling references (UIHTML accent)

  6. For charts: invoke matlab-build-chart (UIFigure) or read charting references (UIHTML accent)

  7. If App Designer serialization: read the app-designer reference docs (shared guide + format-specific guide), then use the AppDesignerAgentInterface API to persist the app. The docs contain the complete build flow, property rules, and editing discipline.

UIHTML path
  1. Read the archetype reference for the spatial skeleton

  2. If MVVM warranted: read the JS MVVM architecture reference

  3. Read the bridge guide to establish the MATLAB-JS connection

  4. Layer in path-specific references per the implementation sequence

  5. For visual polish: read styling/CSS references

  6. For charts: read charting references

Format Fallback

If the plain text path produces errors that cannot be resolved (e.g., version mismatch, unsupported component), fall back to the .mlapp path — the same verbs drive both formats; re-create the handle with a .mlapp extension. Only fall back to fully programmatic UIFigure code as a last resort.

Recommendation Template

Recommended architecture: [UIFigure app / UIHTML app / UIFigure + accent]

Based on what you've described:

  • [Key signal 1]

  • [Key signal 2]

  • [Key signal 3, if applicable]

What this means: [1-2 sentences on development experience]

Trade-off: [Main thing they'd give up vs the other path]

Serialization (if App Designer): I'd recommend [.mlapp / plain text] because [reason]. This doesn't change the app's structure, just how it's saved.

Want to proceed with this approach, or would you prefer the other path?


Copyright 2026 The MathWorks, Inc.


Files

references/app-designer/agent-guide-shared.md

AppDesignerAgentInterface: Shared Guide (read this first)

About this API. AppDesignerAgentInterface is an internal API, for agentic use only. It exists to be driven by an AI agent (you) through AppDesignerAgentInterface; it is not a supported, user-facing API. Its surface (verbs, arguments, behavior) may change between MATLAB releases without notice. Treat this guide, for the release you are running against, as the single source of truth. Do not assume any part of the API is permanent or carry assumptions about it across releases.

AppDesignerAgentInterface is a stateful MATLAB API that serializes UIFigure apps into App Designer formats. The app's structure (components, layout, callbacks) is designed using UIFigure knowledge; this tool handles how that design is persisted to disk. You call verbs that mutate an in-memory model, then save() serializes once. This file covers the paradigms that are the same for both formats. Then read the format-specific guide:

  • .mlapp apps: read agent-guide-mlapp.md.

  • plain-text (.m + .xml) apps: read agent-guide-plaintext.md.

The two formats have different ownership models, so do not assume a verb behaves the same in both. The single most important rule: the tool does exactly what it was told, nothing more, and tells the truth about what it did. If something is wrong it throws a descriptive error rather than silently guessing or "fixing" it.


How you interact with it

Everything runs in MATLAB. A session looks like:

addpath('.../matlab-build-app/scripts');    % put the API on the path
appBuilder = AppDesignerAgentInterface.create("C:/path/App.mlapp");   % or .open(...)
appBuilder.setProperty("UIFigure", "Name", "My App");      % ... verbs ...
appBuilder.save();                                    % serialize + gate

appBuilder is a handle object. All the instance verbs mutate the model it holds. The factory methods (create, open, finalize) are static (AppDesignerAgentInterface.create(...)).

Format is decided by the file extension you pass to create/open: .mlapp -> mlapp path, .m -> plaintext path. ClassName is derived from the filename stem, so name the file what you want the app class to be called.

Converting between formats: If the user asks to convert an existing app from .mlapp to plain text (or vice versa), do NOT rebuild it from scratch. Tell the user to open the app in App Designer and use Save As, changing the file extension to .mlapp or .m. App Designer handles the conversion natively and preserves all components, callbacks, and properties. Rebuilding wastes tokens and risks losing fidelity.


Calling conventions (keep a clean workspace)

Every eval you run lands in the base workspace. Follow these rules to avoid polluting it with temporaries:

  1. Always semicolon-terminate. Every statement must end with ;. Without it, MATLAB echoes the return value to the console (noisy) and assigns ans.

  2. Inline structs into verb calls. Do not create intermediate variables for property structs. Pass them directly:

    appBuilder.addComponent("Button", "Btn", "UIFigure", struct('Text','Go','FontSize',14));

    Not:

    props = struct('Text','Go','FontSize',14);  % BAD — leaves `props` in workspace
    appBuilder.addComponent("Button", "Btn", "UIFigure", props);
  3. Only appBuilder should persist. It is the one handle you need across calls. If a struct is genuinely too complex to inline readably, use it and then clear it in the same eval: clear props;


save() vs finalize() — what each one is

These are two different things and conflating them leads to invented workarounds. Get the model straight before the when-to-call rules below.

  • save() persists and validates. It serializes the in-memory model to disk and runs the real product loader as a gate. A file that save() accepted is complete, valid, and openable — nothing else is required to make it a real app. This is the workhorse: call it whenever you need the model on disk.

  • finalize() presents the finished result. It round-trips the saved file through the live product (mlapp: bakes the full runnable classdef; plaintext: canonicalizes the .xml) and leaves the app open so the user sees it rendered. It is a presentational, optional, once-at-completion step — not part of correctness. A save()d app is already done in every load-bearing sense; finalize() just makes it look finished on screen.

finalize() is reversible — it is not a one-way door. You can always open() the file after finalizing and keep editing (free it from AD first — open() for code, release() for plaintext .xml, per the iterate-to-preview rule below). Never avoid finalize() to "preserve editability" — editability is never lost, so that is not a real trade-off.

"finalize" is internal vocabulary — never say it to the user. To the user this is just "opening the app in App Designer so they can see it." When you offer it, ask in their terms ("Want me to open it in App Designer so you can take a look?"), not "should I finalize it?" — the word sounds like a committing, irreversible step, and it is neither. Keep finalize() as the mechanism you invoke, not a term you expose.

How to drive it: chunked inline calls, not a script

Run the verbs as inline calls in a persistent MATLAB session, grouped into a few logical chunks. Do not write the build out to a temp .m script and run that. Two reasons:

  • The model is a persistent handle. appBuilder lives in the session between calls, so each verb builds on the last. This only works against a persistent MATLAB session (what the connector / MCP server gives you) — the handle has to survive from one call to the next. A temp script throws that away and hides the operations from the user.

  • Failures stay cheap and local. Verbs validate before they mutate, so a verb that throws leaves the model untouched — you fix that one call and continue. Because the earlier verbs already applied to the live model, you never re-emit the whole build to recover from one bad call. A monolithic script forces exactly that re-run.

Chunk by logical unit — e.g. all of one panel's components in one call, then its callbacks in the next. Not one verb per round-trip (you pay latency for nothing) and not one giant block (a failure anywhere makes you hunt). A handful of coherent chunks gives you failure-pinpointing without the overhead.

Many cheap verbs, one save(). save() is the expensive step (it runs the real product loader as a gate). Do not save() between chunks to "check progress" — Layer-1 already validated each verb as you called it, and if save() does reject something it names the offending component, which you fix with a single setProperty and re-save. No rebuild.

Finalize once, when the work is done (both formats). When you have finished a build or an edit — not after every intermediate save() — make AppDesignerAgentInterface.finalize(filepath) your last action. finalize() launches App Designer and leaves the app open so the user sees the finished result with its theme rendered. What it accomplishes differs by format (mlapp bakes the full runnable classdef; plaintext canonicalizes the .xml) — see each format guide. Do NOT finalize between chunks or after each save() in a multi-step build — that relaunches App Designer every time (~4s each) and churns the UI the user is watching. Save as many times as the build needs; finalize exactly once at completion.

One exception — iterate-to-preview. If you finalize, then need a small adjustment, you must free the file from AD before editing it (finalize left it open; editing a file AD holds triggers a wedging reload dialog). Editing code → open() first; editing plaintext components (the .xml) → release() first. Then edit, save(), and finalize() again. See the plaintext guide's "Editing after finalize" section.

There are only a few HARD ordering rules; most of what looks ordered is not. In order of how much they matter:

  1. create() first. Seeds the root UIFigure.

  2. Parent before child. addComponent requires the parent to exist, so build the tree top-down: containers (Panel, GridLayout, TabGroup) before their contents. This is the one real constraint inside the "components" step.

  3. A target must exist before you reference it. setProperty and addCallback need their component present. (Naturally satisfied if you build top-down.)

  4. save() last.

Everything else is FREE — do not over-sequence:

  • Properties are not a separate phase. Set a component's properties inline in the addComponent props struct. Fewer calls, and coupled-order pairs (like DropDown Items-before-Value) are reordered for you (see the mlapp guide). Reserve setProperty for edits to an already-built app, not fresh construction. For a child of a GridLayout, place it in a cell with 'Layout', struct('Row', r, 'Column', c), a struct, never a [row col] vector (see the mlapp guide, "Placing a component into a GridLayout cell").

  • Code is order-free. Callback bodies, methods, and addProperty reference app.<X> at runtime, not when you call the verb. A callback body may mention a component or property you have not declared yet. The only code-side ordering rule is that addCallback (wiring an event slot) needs the component to exist. Wire StartupFcn last so it can reference everything.

So a natural mlapp build reads: create + figure props → component tree top-down (properties inline) → app-state addProperty → behavior (addCallback + bodies + methods, startup last) → save() once. Plaintext is the mirror image — components live in the hand-authored .xml, so the sequence is author .xml tree → code verbs → save() (see the plaintext guide).


The verbs (full public surface)

Factories (static)
CallReturnsNotes
AppDesignerAgentInterface.create(filepath)handleNew empty app. Seeds a root UIFigure. For plaintext also seeds a boilerplate .xml (see plaintext guide). Releases the file from AD first (posture A).
AppDesignerAgentInterface.open(filepath)handleLoad an existing app into a model. Releases the file from AD first (posture A).
AppDesignerAgentInterface.finalize(filepath [, deadlineSeconds])(void)Both formats. Opens in AD, saves through the product, leaves it open for viewing. mlapp bakes runnable code; plaintext canonicalizes the .xml. See each format guide.
AppDesignerAgentInterface.release(filepath)(void)Free a file from App Designer before hand-editing its .xml (posture A: closes a clean copy, rejects an unsaved one). The escape hatch for editing plaintext components after finalize(). See plaintext guide.
Component verbs (mutate the UI tree) — mlapp only

These edit components. On a plaintext model they HARD-ERROR (AppDesignerAgentInterface:plaintextComponentsInXml) because you author plaintext components in the .xml by hand. See the plaintext guide.

VerbSignature
addComponentappBuilder.addComponent(type, codeName, parentCodeName, props) — props optional struct
setPropertyappBuilder.setProperty(codeName, propName, value) — supports dot-path for sub-object properties (e.g. "Title.String")
removeComponentappBuilder.removeComponent(codeName)
moveComponentappBuilder.moveComponent(codeName, newParentCodeName)
addCallbackappBuilder.addCallback(codeName, eventName, callbackName) — wires an event slot to a function name
Code verbs (mutate the .m code side) — both formats
VerbSignature
setCallbackCodeappBuilder.setCallbackCode(callbackName, bodyCode) — the callback body text (dedented; no function line)
addPropertyappBuilder.addProperty(propName, value, access) — access = "public" (default) / "private" / "protected"
addMethodappBuilder.addMethod(name, bodyCode, access) — bodyCode is the FULL function ... end text
removeCallbackappBuilder.removeCallback(callbackName) — fully remove a callback: its body AND (mlapp) every component event slot wired to it. Throws AppDesignerAgentInterface:noSuchCallback only if the name has neither a body nor any wiring.
removeMethodappBuilder.removeMethod(name) — remove a method. Throws AppDesignerAgentInterface:noSuchMethod if absent.
removePropertyappBuilder.removeProperty(propName) — remove a property. Throws AppDesignerAgentInterface:noSuchProperty if absent.

set/add code verbs REPLACE, they do not append. setCallbackCode, addProperty, and addMethod each key on the name. If that name already exists, the verb overwrites the whole entry and emits a warning (AppDesignerAgentInterface:overwriteCallback / overwriteProperty / overwriteMethod) naming the key. Nothing is merged. To modify rather than replace, use the read-modify-write pattern below.

Inspection / lifecycle — both formats
VerbReturnsNotes
inspect()structFull model projection (see shape below). Read-only.
validate()struct arrayDry-run check. Non-throwing, writes nothing. Always a struct array with fields code, message, one element per problem. A clean result is a 0x0 struct (still has the two fields) — test it with isempty(v), which is true exactly when there are no problems.
save()(void)Serialize + loadability gate. Throws on failure.

All string arguments are MATLAB string ("...") or char ('...'); both work.


inspect() output shape

s = appBuilder.inspect() returns a struct:

s.ClassName    string
s.Format       "mlapp" | "plaintext"
s.StartupFcn   string (name of the startup callback, or "")
s.Nodes        cell array of node structs, in insertion order
s.Callbacks    struct: fieldname = callback name, value = body text
s.Methods      struct: fieldname = method name, value = struct with .Body (full function text) and .Access ("public"|"private")
s.Properties   struct: fieldname = property name, value = default value

Each node struct in s.Nodes:

node.CodeName        string   (the unique identifier for the component)
node.Type            string   (component type, e.g. "Button")
node.ParentCodeName  string
node.Props           struct   (property name -> native value)   << field is "Props", NOT "Properties"
node.Layout          struct   (Row / Column for grid children)
node.Callbacks       struct   (eventName -> wired callback name)
node.Children        string array of child codeNames

Gotcha: the node property bag is node.Props, not node.Properties. To read a component's Color: figNode.Props.Color.


Editing an existing app (read this before you change anything)

The API is stateful and additive. You never rebuild an app to change it, and you never re-run create() on a file that already exists. The rule is:

To edit, open() the app and apply the smallest set of verbs that make the change. Do NOT re-create the app or re-drive the whole build.

create() is for a brand-new file only. Everything else — adding a component, changing a property, editing code, removing something — is open() + a few surgical verbs + save(). The model you open already contains everything the app has; your verbs mutate it in place.

The disciplined edit loop is inspect first, then mutate:

appBuilder = AppDesignerAgentInterface.open("C:/path/MyApp.mlapp");
s  = appBuilder.inspect();          % <-- see the CURRENT state before you touch it
% ... decide the minimal change from what you actually see ...
appBuilder.setProperty("GoButton", "Text", "Start");
appBuilder.save();

Why inspect() first matters:

  • Placement/layout: before adding a component, read existing node Position (or Layout for grid children) so the new one fits, instead of guessing coordinates. See s.Nodes{k}.Props.Position / .Layout.

  • Avoiding accidental overwrite: before setCallbackCode/addProperty/ addMethod, check whether the name already exists in s.Callbacks / s.Properties / s.Methods. If it does, the verb REPLACES it (with a warning). That is the mechanism behind "it overwrote the callback I already wrote."

Modifying code (not replacing it): read-modify-write

There is no "append to a callback" verb. The code verbs replace by name. To add to existing code, read the current body, build the new full text yourself, and set it back:

s = appBuilder.inspect();
old = s.Callbacks.onGo;                         % current body ("" if unset)
newBody = old + newline + "app.Count = app.Count + 1;";
appBuilder.setCallbackCode("onGo", newBody);            % now holds old + new

If you skip the read and just call setCallbackCode("onGo", "app.Count = ..."), you lose the previous body and get an AppDesignerAgentInterface:overwriteCallback warning. The warning is your signal that you replaced something — if you did not intend to, you skipped the read step.

Removing code

Use the removal verbs (removeCallback / removeMethod / removeProperty). Each throws if the target does not exist, so a clean call means it was really there and is now gone. There is no verb to partially edit a body down — to shrink a method, read-modify-write the full replacement text, or remove and re-add.

Removing a component is removeComponent (mlapp only; plaintext edits the .xml). Removing a component does NOT remove any callback bodies it was wired to — those are code entries; remove them separately with removeCallback if they are now orphaned.


Component types and events are validated from the product (Layer-1)

When you add a component, set a property, or wire a callback, AppDesignerAgentInterface validates against the real App Designer component registry — nothing is hardcoded. An invalid type/property/event throws immediately and mutates nothing.

There are 54 component types. Use the short name (last segment of the class), e.g. "Button", "Label", "NumericEditField", "Slider", "DropDown":

AirspeedIndicator, Altimeter, ArtificialHorizon, Button, ButtonGroup, CheckBox,
CheckBoxTree, ClimbIndicator, ColorPicker, ContextMenu, DatePicker, DiscreteKnob,
DropDown, EGTIndicator, EditField, Gauge, GridLayout, HTML, HeadingIndicator,
Hyperlink, Image, Knob, Label, Lamp, LinearGauge, ListBox, Menu, NinetyDegreeGauge,
NumericEditField, Panel, PushTool, RPMIndicator, RadioButton, RangeSlider,
RockerSwitch, SemicircularGauge, Slider, Spinner, StateButton, Switch, Tab,
TabGroup, Table, TextArea, TimeScope, ToggleButton, ToggleSwitch, ToggleTool,
Toolbar, Tree, TreeNode, TurnCoordinator, UIAxes, UIFigure

Event names are per-type. Examples:

  • Button -> ButtonPushedFcn

  • Slider -> ValueChangedFcn, ValueChangingFcn

  • DropDown -> ValueChangedFcn, DropDownOpeningFcn, ClickedFcn

The app root is always UIFigure (seeded by create). The app-level startup callback is wired on UIFigure with event name StartupFcn.

Property order is handled for you

You can pass a component's properties in any order. Some components have coupled properties that the product requires be applied in a specific order (e.g. a DropDown's Items before its Value), but AppDesignerAgentInterface reorders each property bag into App Designer's own canonical order before applying it, so you never have to sequence them yourself. This is product-sourced, not a hardcoded list. See the mlapp guide ("Property order does not matter") for the full set of affected components.


The startup callback

Wire it on the figure, then set its body:

appBuilder.addCallback("UIFigure", "StartupFcn", "startupFcn");   % mlapp only; plaintext wires it in .xml
appBuilder.setCallbackCode("startupFcn", "app.CurrentPlayer = ""X"";");

StartupFcn is always a valid event on UIFigure. Use startup to initialize app state properties (declare them bare via addProperty(name, "", "private"), then assign real values in startup) so the app opens in a known state.


Callback bodies vs. method bodies (easy to get wrong)

  • setCallbackCode(name, body) takes just the body, dedented, no function line, no end. AppDesignerAgentInterface generates the function name(app, event) wrapper. Inside, you have app and event in scope.

  • addMethod(name, body, access) takes the FULL function ... end text, including the signature line. Write the whole thing:

appBuilder.addMethod("checkWin", strjoin([ ...
  "function tf = checkWin(app)" ...
  "    tf = false;" ...
  "    % ..." ...
  "end" ], newline), "private");

Reach components from a callback/method via app.<CodeName> (e.g. app.StatusLabel.Text = "..."). Reach app-level properties via app.<PropName>.

Which verb: is it wired to an event, or called from code? This is the distinction that decides setCallbackCode vs addMethod:

  • A function that fires from a component event (a button push, a value change, startup) is a callback: wire it with addCallback, then give it a body with setCallbackCode. App Designer only emits a callback that is wired to an event slot — a setCallbackCode body that no component wires to is silently dropped at save (it never appears in the generated app). validate() on an mlapp flags this as AppDesignerAgentInterface:orphanCallbackBody so you catch it before save.

  • A helper that other code calls by name (including anything you invoke via createCallbackFcn(app, @thing, true), or a plain app.thing() from another callback) is a method: add it with addMethod. Do not create it with setCallbackCode — an unwired body is dropped, so the call would reference a function that does not exist.

A name cannot be both a callback and a method. If the same name is wired as a callback body and added as a method, it would be generated as two functions with the same name (a broken classdef). AppDesignerAgentInterface rejects the collision with AppDesignerAgentInterface:nameCollision from whichever verb is called second. To convert a callback into a method (e.g. you wired it but really want a callable helper), removeCallback(name) first — that removes the body and unwires the event slot — then addMethod(name, ...).

Body text is treated as opaque code — it is stored and emitted verbatim, not interpreted or reformatted. Literal %, $, quotes, and sprintf/fprintf format strings pass through unchanged (e.g. a body containing sprintf("$%.2f", total) round-trips exactly). You do not need to escape anything for AppDesignerAgentInterface's sake; write the body as the MATLAB code you want to appear in the file. (The usual MATLAB rule still applies to the string you hand the verb: a " inside a double-quoted MATLAB string literal must be doubled "", but that is your call's syntax, not an AppDesignerAgentInterface transformation of the body.)

Quoting patterns for bodies containing single quotes (transpose ' or char literals 'text'):

% Option 1: use a double-quoted string — single quotes pass through unescaped
appBuilder.setCallbackCode("onPress", "x = [1 2 3]';" + newline + "app.Btn.Text = 'done';");

% Option 2: use sprintf with a char vector — escape ' as ''
appBuilder.setCallbackCode("onPress", sprintf('x = [1 2 3]'';\napp.Btn.Text = ''done'';'));

Both produce identical stored bodies. Prefer double-quoted strings (option 1) since single quotes inside them require no escaping.


Shared callbacks (one function, many components)

Wire multiple components to the SAME callback name, then define the body once. Distinguish which fired using event.Source:

appBuilder.addCallback("RockButton", "ButtonPushedFcn", "PlayMove");
appBuilder.addCallback("PaperButton", "ButtonPushedFcn", "PlayMove");
appBuilder.setCallbackCode("PlayMove", "move = string(event.Source.Text); ...");

save() gates on real loadability — trust the error, don't fight it

save() does not just write bytes. It runs the app through the real product loader (or, for mlapp, a round-trip re-read plus the loader). If the result would not load cleanly in App Designer, save() throws with the loader's own error. Two failure shapes to know:

  1. Parse/config error — the file structure is bad (e.g. malformed .xml).

  2. Errored components — the app parses but a component fails to construct (usually a bad property value the lexical checks let through, like an out-of-range enum). The error names the offending component codeName.

When save() throws, read the message: it tells you exactly what the product rejected. Fix the model/.xml and save again. Do not assume a throw means the AppDesignerAgentInterface is broken — it usually means the app really would not load.


Not yet supported

Two feature areas are out of scope for AppDesignerAgentInterface today:

Apps that embed or bind to a Simulink model (signal viewers, dashboard blocks, model callbacks) are not supported. The plain text format has no representation for Simulink bindings at all. The mlapp format can encode them, but AppDesignerAgentInterface does not expose verbs for model association, signal routing, or variable binding. Do not attempt to wire Simulink connections through raw property manipulation; it will not produce a loadable app.

User Authored Components (UAC)

UACs (custom component classes authored by the user) cannot be added through addComponent. The plain text format does not support UACs. For mlapp, the workaround is to instantiate the UAC programmatically in the app's StartupFcn callback:

appBuilder.setCallbackCode("startupFcn", ...
    "app.MyCustomGauge = MyGaugeComponent(app.UIFigure);" + newline + ...
    "app.MyCustomGauge.Layout.Row = 2;" + newline + ...
    "app.MyCustomGauge.Layout.Column = 1;");

This is a valid App Designer pattern. The UAC will function at runtime but will not appear in Design View. Alternatively, suggest the user add the UAC in Design View manually; AppDesignerAgentInterface can then access it via setProperty/getProperty on subsequent open() calls.


Working-session gotchas (for whoever drives MATLAB, incl. me)

  • After editing source (AppDesignerAgentInterface.m / MlappBackend.m / PlainTextBackend.m), run clear classes; rehash toolboxcache before the next call, or MATLAB keeps the stale class definition. Not needed for test/script edits.

  • .mlapp is a zip. To read the generated code, use appdesigner.internal.serialization.FileReader(path).readMATLABCodeText() — NOT fileread (reads raw zip bytes) and there is no matlabCodeText struct field.

  • String property values in the plaintext .xml must be quoted ('text') — they are parsed as native MATLAB literals. See the plaintext guide. (mlapp props are passed as native MATLAB values directly through the verbs, so this only bites plaintext.)

  • Bounded any App-Designer-touching run with a timeout; a wedged AD can block on an unbounded wait.


Copyright 2026 The MathWorks, Inc.


Requirements and compatibility

Works with: Claude Code, Claude apps, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, Kiro, OpenCode, Goose, Amp, Roo Code, JetBrains Junie, Factory Droid, Devin (ex-Windsurf), Mistral Vibe, OpenHands, Letta

“Works with” means the tool reads the open Agent Skills format; a skill written for one tool may use features others lack.

Needs: Declares allowed tools

Security

No issues found by our static scan· No issues found

A static scan is not a guarantee. Skills are third-party content: review a skill before you let an agent use it.

Attribution and licence

Created by
MathWorks
Publisher
MathWorks (Official)
Source
matlab/matlab-agentic-toolkit · skills-catalog/matlab-app-building/matlab-build-app · commit 2a7f215
Licence
BSD 2-Clause License (redistribution allowed)
  • LICENSE (added by AutoGineer from LICENSE.md)
  • ATTRIBUTION.md (written by AutoGineer)
Synced

AutoGineer is not affiliated with or endorsed by MathWorks or MathWorks.

Get it from the source

5 of this skill’s files are not mirrored here, so there is no ZIP. Get the complete skill from its source: matlab/matlab-agentic-toolkit