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; domai...
Scanned 5/27/2026
Install via CLI
openskills install matlab/agent-skills-playground---
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) |
No comments yet. Be the first to comment!