matlab-project

$npx mdskill add matlab/agent-skills-playground/matlab-project

Manage MATLAB projects: create, track, configure, and build.

  • Creates and configures MATLAB project files (.prj).
  • Depends on MATLAB Project API and Simulink cache settings.
  • Uses project health checks and file system sync to guide actions.
  • Delivers project setup, build scripts, and health check results.

SKILL.md

.github/skills/matlab-projectView on GitHub ↗
---
name: matlab-project
description: Use this skill for any work involving a MATLAB Project (.prj file) — creating a new project, tracking files, managing the project path, configuring Simulink cache and code-generation folders, running project health checks, or writing build scripts that keep the project in sync with the file system. Trigger phrases include "set up a MATLAB project", "create a .prj", "track this file in the project", "project health check", "build script conventions". This skill is the generic foundation; domain-specific skills (e.g. `mbse-workflow`) build on it.
license: MathWorks BSD-3-Clause (see LICENSE)
metadata:
  author: MathWorks
  version: "1.0"
---

# MATLAB Project — Setup, Conventions, and Build-Script Patterns

A MATLAB Project (`.prj`) is a single file that manages path, tracked artifacts,
shortcuts, derived-output locations, and health checks. This skill covers the
mechanics so every downstream workflow (requirements, architecture, analysis,
anything else) can rely on a predictable project shape.

Domain skills reuse this skill's helpers (`setupProject`, `registerWithProject`)
and conventions (idempotent build scripts, `removeFile` before `delete`,
`runChecks` at the end of `buildAll`). They may override the living-doc
templates with domain-specific versions.

---

## Creating a project

Use [`code/setupProject.m`](code/setupProject.m) to create the project inline
(not as a saved script — the `scripts/` folder doesn't exist yet):

```matlab
setupProject(projectName, projectFolder, subfolders, derivedSubfolders)
```

- `subfolders` — cell array of folders that are created, added as tracked
  project files, and placed on the MATLAB path. Callers choose the layout.
- `derivedSubfolders` — cell array of folders for build outputs. Created but
  **not tracked**. The first two entries are wired to `SimulinkCacheFolder`
  and `SimulinkCodeGenFolder` if supplied, so Simulink cache / codegen stays
  out of source control.

Example (MBSE shape):

```matlab
setupProject("MySystem", "C:\work\MySystem", ...
    {'requirements','architecture','analysis','verification','scripts'}, ...
    {fullfile('derived','cache'), fullfile('derived','codegen')});
```

### Path management rule

**Every tracked folder that is supposed to be on the path must be registered
with both `addFolderIncludingChildFiles` *and* `addPath`.** If you only do the
first, `runChecks` later fails with `Project:Checks:ProjectPath` ("a folder is
on the MATLAB path but not registered as a project path folder"). `setupProject`
handles this for the initial folder set; any folder added later must follow the
same pattern.

### Why no `startup.m`

A `startup.m` is unnecessary when build scripts are idempotent and self-cleaning
(each script clears its own state at the top — see below). Adding one introduces
hidden state that survives between runs and tends to mask bugs. Leave it out.

---

## File lifecycle — tracking, shortcuts, removal

### Tracking files as they're created

Use the [`code/registerWithProject.m`](code/registerWithProject.m) helper from
every build script. It is idempotent and a no-op if no project is open:

```matlab
registerWithProject({fileA, fileB, ...}, {folderA, ...})
```

Each build script should call this at the end, passing the files it created.
`buildAll.m` additionally registers all script files. This keeps the project
in sync with the file system without any manual `addFile` bookkeeping.

### Shortcuts

`addShortcut(proj, filePath)` (no label argument) adds a file to the project's
Shortcuts panel. Add shortcuts progressively as key files are created — typical
targets: the top-level build script, the main model, the primary data file.

### Removing tracked files

**Always call `removeFile` before `delete`** when getting rid of a tracked file.
A bare `delete()` removes the file from disk but leaves a broken reference in
the project, causing `runChecks` failures:

```matlab
proj = currentProject();
removeFile(proj, fullfile(archDir, 'OldArtifact.sldd'));  % untrack first
delete(fullfile(archDir, 'OldArtifact.sldd'));             % then remove from disk
```

This matters whenever a build script replaces an artifact with a new name — the
old tracked entry must be removed explicitly.

---

## Build-script idempotency conventions

Any build script that writes tracked artifacts should follow these rules so
`buildAll.m` can run any phase in any order without accumulating stale state:

1. **Clear state at the top.** For MATLAB it is often enough to `clear` nothing
   and rely on the delete-and-recreate step. For toolboxes with in-memory
   state (e.g. `slreq.clear()`, `Profile.closeAll()`), call their reset APIs
   as the first action.
2. **Delete the target artifacts before recreating them.** Guard every file
   op with `isfile` / `isfolder` so the first run (when files don't exist)
   and later runs (when they do) take the same path.
3. **Recreate artifacts from scratch.** Never mutate an existing file in place.
4. **Call `registerWithProject` at the end**, passing every artifact the
   script produced. The helper is a no-op if a file doesn't exist, so
   conditional artifacts (link-store files that only appear when links are
   created) are safe to pass unconditionally.

This pattern is what lets users rebuild everything cleanly by calling
`buildAll()` — there is no state to undo, just regenerate.

---

## `buildAll.m` shape

The top-level orchestrator script calls each phase / build script in order,
then registers the script files themselves, then runs project health checks:

```matlab
%% Register all scripts with the project
scriptsDir = fileparts(mfilename('fullpath'));
scriptFiles = { ...
    fullfile(scriptsDir, 'buildAll.m'), ...
    % ... every other script the project uses ...
    fullfile(scriptsDir, 'registerWithProject.m'), ...
};
registerWithProject(scriptFiles);

%% Project health check
proj = matlab.project.currentProject();
if ~isempty(proj.Name)
    results = runChecks(proj);
    nFail = 0;
    fprintf('\nProject checks:\n');
    for i = 1:numel(results)
        if results(i).Passed
            fprintf('  [PASS] %s\n', results(i).Description);
        else
            fprintf('  [FAIL] %s\n', results(i).Description);
            for j = 1:numel(results(i).ProblemFiles)
                fprintf('           %s\n', results(i).ProblemFiles(j));
            end
            nFail = nFail + 1;
        end
    end
    if nFail == 0
        fprintf('All checks passed.\n');
    else
        fprintf('%d check(s) failed — review output above.\n', nFail);
    end
end
```

`runChecks` runs 8 built-in project checks including file existence, path
consistency (`Project:Checks:ProjectPath`), unsaved files, and SLPRJ folder
placement. The most common failure is `Project:Checks:ProjectPath` — fix with
`addPath(proj, folderPath)` on the offending folder.

---

## Living documentation: `plan.md` and `decisions.md`

Projects built with this skill carry two hand-curated markdown files at the
project root. They are *not* build outputs — they preserve context a future
reader otherwise couldn't recover from the code alone.

| File | Purpose | Update cadence |
|---|---|---|
| `plan.md` | Canonical overview: scope, source artifacts, milestone status, open questions, known risks. | At each milestone and whenever scope or constraints change. |
| `decisions.md` | Append-only log of non-obvious decisions — each with context, options, rationale, revisit trigger. | Append at any checkpoint where the chosen approach wasn't forced by the inputs, and at every rollback. |

Templates live at [`templates/plan.md`](templates/plan.md) and
[`templates/decisions.md`](templates/decisions.md). Copy both into the project
root during setup, fill placeholders, and register them with the project so
they ship with the repo:

```matlab
proj = currentProject();
addFile(proj, fullfile(proj.RootFolder, 'plan.md'));
addFile(proj, fullfile(proj.RootFolder, 'decisions.md'));
```

**Override for domain skills.** Any domain skill (e.g. `mbse-workflow`) may
ship its own `plan.md` / `decisions.md` templates under its own `templates/`
folder and use those *instead* of the generic ones here. Overrides should
keep the core section order (Overview → Source artifacts → Status → Open
questions → Known risks) so readers moving between projects find familiar
anchors. Add domain-specific sections below the core set.

**When to append a decisions entry:** only when a judgment call was made.
Mechanical steps and input-forced decisions don't belong. Good examples:
"shortened artifact prefix from full system name to make filenames
manageable"; "split module X into four sub-modules per user preference"; "added
property Y mid-project after initial scope excluded it". Bad examples: "created
the .prj file"; "imported 27 rows from xlsx".

**When to skip an entry:** bug fixes, API iteration, rerunning a script after
an error, or anything that reflects tooling friction rather than design
judgment.

---

## Quick reference

| Task | Call |
|---|---|
| Create project | `setupProject(name, folder, subfolders, derivedSubfolders)` |
| Track files/folders after creation | `registerWithProject(files, folders)` |
| Add a shortcut | `addShortcut(proj, filePath)` |
| Remove a tracked file | `removeFile(proj, path)` **then** `delete(path)` |
| Ensure folder is on path | `addPath(proj, folderPath)` |
| Health check | `runChecks(proj)` (see `buildAll.m` shape above) |

More from matlab/agent-skills-playground

SkillDescription
agent-skill-authorUse this skill when the user wants to author, design, scope, or refine an Agent Skill (a SKILL.md file). Trigger phrases include "build a new skill", "design an agent skill", "scope a SKILL.md", "how should I structure this skill", "write a skill for X", "my skill isn't working well", or any request to improve an existing SKILL.md. Walks the user through an empirical, test-first process — probe the agent for real failures, design only for genuine knowledge gaps, iterate against runnable examples, and verify across models.
embedded-ai-deployment>
matlab-performance-optimizerOptimize MATLAB code for better performance through vectorization, memory management, and profiling. Use when user requests optimization, mentions slow code, performance issues, speed improvements, or asks to make code faster or more efficient.
matlab-symbolic-mathGenerate correct MATLAB code using the Symbolic Math Toolbox. Use when the user asks for symbolic computations, analytical solutions, symbolic differentiation/integration, equation solving, or converting symbolic results to numeric MATLAB functions. Also use when converting differential equations to transfer functions or state-space form.
matlab-uihtml-app-builderBuild interactive web applications using HTML/JavaScript interfaces with MATLAB computational backends via the uihtml component. Use when creating HTML-based MATLAB apps, JavaScript MATLAB interfaces, web UIs with MATLAB, interactive MATLAB GUIs, or when user mentions uihtml, HTML, JavaScript, web apps, or web interfaces.
matlab-uihtml-designGenerate beautiful, distinctive HTML/CSS/JS control panels for MATLAB uihtml components. 8 built-in styles (Clean, Material, Cosmic Dark, Neumorphic, Dashboard Light, Midnight Gradient, Minimal Mono, Warm Dark) plus custom aesthetics. Produces production-grade UI with sliders, buttons, toggles, and panels. Use when building visually polished MATLAB app UIs with uihtml.
mbse-architectureUse this skill for the architecture phases of an MBSE workflow in MATLAB, when writing idempotent buildXxx.m scripts that produce a three-layer RFLPV architecture (Functional, Logical, Physical) with interface dictionaries, stereotype profiles, allocation sets, and requirements Implement links. Trigger for defining stereotype properties, functional-to-logical / logical-to-physical allocation, mapping requirements to components via slreq Implement links, or running quantitative roll-up analysis on the architecture. Do NOT trigger for ad-hoc structural edits to an already-built System Composer model (adding one component, rewiring a port) — use `building-simulink-models` with `model_edit` for that. Works alongside the `system-composer` skill for detailed SC API patterns.
mbse-workflowUse this skill for guided MBSE work in MATLAB — starting a new project, resuming work mid-workflow on an existing project, or answering orientation questions about how the MBSE skills fit together. Trigger when the user says they want to create, start, or set up a new MBSE project; work on a model-based systems engineering / RFLPV project; or asks which skill covers which phase. Walks through phases one at a time — propose → approve → generate → run → confirm. Use proactively whenever someone mentions starting or continuing an MBSE project.
simulink-requirementsUse this skill for all requirements-related work in a MATLAB MBSE project using the Requirements Toolbox (slreq). Covers creating and populating requirement sets, derivation links, test case requirements, verification coverage, reading and tracing links across requirement sets and models, checking link health, allocating requirements to components (Implement links), and building traceability reports. Trigger when the user asks about slreq API, slreqx files, slmx link files, outLinks/inLinks, traceability matrices, coverage analysis, broken links, or mapping requirements to architecture components. Use proactively for any requirements or traceability task.
system-composerUse this skill when authoring reusable, idempotent MATLAB scripts that build System Composer architecture models via the architecture-modeling API — `systemcomposer.createModel`, `addComponent`, `addPort`, `setInterface`, `connect(srcPort, dstPort)`, interface dictionaries (.sldd) with `addInterface`/`addElement`, profiles/stereotypes with `Profile.createProfile` and `addStereotype`, or `systemcomposer.allocation.createAllocationSet`. Also trigger when debugging these APIs (connections that don't appear, interfaces that don't resolve, profile save errors, `createAllocationSet` signature-mismatch errors). Do NOT trigger for ad-hoc structural edits to an already-built model (adding one SubSystem, rewiring a port) — use `building-simulink-models` with `model_edit` for that.