agentsclimarketplace

Mbse architecture

Skill matlab/agent-skills-playground/demos/mbse-with-agentic-ai/skills/mbse-architecture

A sandbox for prototyping and demonstrating Agent Skills for MATLAB and Simulink work.

Install
npx -y skills add matlab/agent-skills-playground --skill mbse-architecture

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.

What its author says it does

Copied from the file, not written here

Use 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.

The file declares its own license as MathWorks BSD-3-Clause (see LICENSE). That is the author’s claim about this one file, and it is not the same thing as the license GitHub reports for the repository, which is listed with the other numbers below.

SKILL.md

19.5 KB, ~4.4k tokens by cl100k_base, as published. Nobody here has run it

MBSE Architecture, Allocation & Analysis (Phases 3–6)

See the system-composer skill for the full System Composer API reference (interfaces, ports, connections, auto-layout). This skill covers the MBSE-specific decisions and patterns layered on top, plus allocation and analysis.

For analysis details see references/analysis.md (prose) plus code/myRollupAnalysis.m and code/runMyAnalysis.m (templates).


When to defer to building-simulink-models / model_edit

This skill produces reusable idempotent build scripts — the whole three-layer architecture, its interface dictionaries, profile, and allocation sets, built from scratch in one buildAll() run. That is its sweet spot.

For one-off edits to an already-built SC model — adding a single SubSystem to explore a variant, tweaking one port name, renaming a component — prefer SATK's building-simulink-models with the model_edit MCP tool. model_edit handles autolayout, undo, and error recovery automatically and is faster for interactive tweaks.

Once the MBSE model is in a state where you need to round-trip it through buildPhysical.m etc. again (for example because you added a stereotype property or changed an allocation), go back to this skill — the buildXxx.m scripts will rebuild from scratch and all of model_edit's ad-hoc changes will be overwritten. That is intentional: the build scripts are the source of truth.

Never mix the two in one script. The two skills use different System Composer API layers (architecture-modeling vs. block-diagram). See the system-composer skill's "When to use this skill vs. building-simulink-models" section for the API-layer differences.


Three-Model Architecture (RFLPV)

The MBSE workflow uses three separate System Composer models, one per layer:

ModelLayerAnswersInterface style
MyFunctional.slxF — FunctionsWhat does the system do?Abstract flows, solution-neutral
MyLogical.slxL — LogicalWhat kind of element solves it?Typed signals, design-agnostic
MyPhysical.slxP — PhysicalHow is it built?Concrete fields, physical units

Each model has its own interface dictionary at the appropriate abstraction level. All three dictionaries are independent — no model script depends on another being open.

Build order: Functional first, Logical second, Physical third.

These three models are structural views. For a behavioral companion (message sequences across components for a specific scenario), attach a System Composer Interaction to the Logical model — see system-composer/SKILL.md#sequence-diagrams. The Logical layer is the natural home because it's stable across Physical-layer variant trade studies.

The Logical layer is the key distinction from classic RFLP. Logical components are design-agnostic solution principles (e.g., SensingUnit, ControlUnit, ActuationUnit) — they commit to what kind of element is needed without specifying vendor, geometry, or implementation. Physical components are the actual realization.


Functional architecture model (MyFunctional.slx) — build first

What the system does — logical functions and the abstract information flows between them. Creates and owns the functional interface dictionary.

See code/buildMyFunctional.m for the full parameterized function:

buildMyFunctional(modelName, dictFile, archDir)

Logical architecture model (MyLogical.slx) — build second

What kind of element solves each function — solution principles without physical commitment. Creates and owns the logical interface dictionary.

See code/buildMyLogical.m for the full parameterized function:

buildMyLogical(modelName, dictFile, archDir)

Naming guidance for logical components: Use nouns that describe the role of the solution element, not the specific hardware. Good: SensingUnit, ControlUnit, ActuationUnit, PowerConverter. Avoid hardware brand names or part numbers — those belong in the Physical layer.

Interface guidance: Logical interfaces sit between functional (abstract flows) and physical (hardware-spec signals). Include typed fields with semantic meaning but without datasheet-level specifics — no voltage ranges, baud rates, or tolerance values.


Physical architecture model (MyPhysical.slx) — build third

What the system implements — hardware/software components, physical interfaces, and stereotype properties. Creates and owns the physical interface dictionary.

See code/buildMyModel.m for the full parameterized function:

buildMyModel(modelName, dictFile, archDir)

Key gotchas:

  • modelName must be a double-quoted MATLAB string so char(modelName) + ".slx" concatenates; single-quoted char + char does arithmetic
  • addpath(archDir) before createDictionary and createModel — SC resolves files via MATLAB path
  • Simulink.data.dictionary.closeAll("-discard") before creating a new dictionary — stale handles from a prior run block createDictionary
  • Re-fetch interfaces after dict.save() before calling setInterface — handles become stale across a save
  • Before deleting a file that is tracked in a MATLAB project, call removeFile(proj, filePath) first. A bare delete() removes the file from disk but leaves a broken reference in the project, which causes health check failures. Pattern:
proj = currentProject();
removeFile(proj, fullfile(archDir, 'OldFile.sldd'));  % untrack first
delete(fullfile(archDir, 'OldFile.sldd'));             % then remove from disk

If the file no longer exists on disk (already deleted) but is still tracked, call removeFile without delete. If no project is open, currentProject() errors — guard with matlab.project.rootProject() if needed.


Component Naming and Domains

Group components by domain — makes the architecture readable and informs interfaces:

% Computation
flightComputer = addComponent(arch, 'FlightComputer');

% Sensing
sensorSuite    = addComponent(arch, 'SensorSuite');

% Actuation
actuatorSystem = addComponent(arch, 'ActuatorSystem');

% Power
powerSystem    = addComponent(arch, 'PowerSystem');

Stereotype Properties — Set Up in the Architecture Script

Define and apply stereotypes at the end of buildMyModel() so property estimates travel with the model and survive every rebuild.

The stereotype can capture any engineering properties relevant to the project — mass, power, cost, reliability, latency, data rate, etc. Choose property names and units based on what decisions the project needs to support.

Naming: Name the stereotype after what the component is or what you are characterizing, not the analysis activity. Good examples: FlightProperties, HardwareProperties, ComponentCharacteristics. Avoid generic names like BudgetProperties — they imply the stereotype is only for budgeting, when in practice it often carries performance, reliability, and other attributes too.

profileName = 'MySystemProfile';
profileXml  = fullfile(archDir, [profileName, '.xml']);

systemcomposer.profile.Profile.closeAll();
profileFile = fullfile(archDir, [profileName, '.xml']);
if isfile(profileFile), delete(profileFile); end
if isfolder(profileFile), rmdir(profileFile, 's'); end   % clean up old bad saves

profile = systemcomposer.profile.Profile.createProfile(profileName);
st = addStereotype(profile, 'ComponentProperties', AppliesTo="Component");
addProperty(st, 'Mass_kg',         Type="double", Units="kg", DefaultValue="0");
addProperty(st, 'PowerEstimate_W', Type="double", Units="W",  DefaultValue="0");
addProperty(st, 'PowerBudget_W',   Type="double", Units="W",  DefaultValue="0");
addProperty(st, 'PowerMargin_W',   Type="double", Units="W",  DefaultValue="0");  % computed

% CRITICAL: pass the FOLDER, not the file path.
% profile.save(folder)      → saves <profileName>.xml into that folder  ✓
% profile.save(folder/a.xml) → creates a DIRECTORY named a.xml          ✗
profile.save(archDir);

applyProfile(model, profileName);
prefix = [profileName, '.ComponentProperties.'];   % ← char concat, not string +

%         Component        Mass_kg  PwrEstimate  PwrBudget
values = {
    'FlightComputer',   3.5,  120,  150;
    'SensorSuite',      4.0,   45,   50;
    % ...
};

for i = 1:size(values, 1)
    comp = arch.getComponent(values{i, 1});
    applyStereotype(comp, [profileName, '.ComponentProperties']);
    setProperty(comp, [prefix, 'Mass_kg'],         num2str(values{i, 2}));
    setProperty(comp, [prefix, 'PowerEstimate_W'], num2str(values{i, 3}));
    setProperty(comp, [prefix, 'PowerBudget_W'],   num2str(values{i, 4}));
end

Profile path gotcha — and the broader string-vs-char trap

profile.save() requires a char array path:

profile.save([profileName, '.xml'])   % OK  — char concat
profile.save(profileName + ".xml")    % FAILS — string type not accepted

This is one instance of a recurring trap across SC and slreq: some APIs silently fail or error with unhelpful messages when handed a string where a char array is expected. The poison source is typically proj.RootFolder — it returns string, and fullfile(string, ...) and fileparts on a string path both stay string, so once any upstream path is string, everything downstream is string unless explicitly cast.

Symptoms to recognize:

  • profile.save(archDir)Invalid input for argument 2 (p0): Value must be a scalar Fix: profile.save(char(archDir)).
  • [baseName, 'Set'] where baseName came from fileparts(stringPath) → MATLAB builds a 2-element string array, not a char concatenation. Passing that array as a name to createAllocationSet fails with No method 'createNewAllocationSet' with matching signature found for class 'systemcomposer.allocation.app.AllocationAppCatalog' — unhelpful, but the cause is the multi-element name. Fix: [char(baseName), 'Set'].
  • createAllocationSet(name, srcModel, dstModel) also misbehaves when you pass model objects instead of model names (char/string). Pass names.

Rule of thumb: in scripts that derive paths from proj.RootFolder, wrap defensively:

archDir  = char(fullfile(proj.RootFolder, 'architecture'));   % char from the start
% or cast at the point of use:
profile.save(char(archDir));
allocSetName = [char(allocBase), 'Set'];

When an SC/slreq API errors with a signature-mismatch message and the args look right, suspect string-vs-char before anything else.


Connectivity Verification

After building, check for unconnected ports before saving:

for i = 1:numel(arch.Components)
    for j = 1:numel(arch.Components(i).Ports)
        if isempty(arch.Components(i).Ports(j).Connectors)
            fprintf('Unconnected: %s.%s\n', ...
                arch.Components(i).Name, arch.Components(i).Ports(j).Name);
        end
    end
end

Rebuilding the model invalidates allocation links — always re-run allocation scripts after rebuilding the architecture.


Architecture Views for review dashboards

Once the Physical model has a stereotype applied with properties like Mass_kg / Power_kW / Cost_*, you get cheap review dashboards by defining architecture views — stereotype-query filters on the model. The core SC API is covered in the system-composer skill ("Architecture Views — filtered lenses on a large model"); this note is about which views are typically worth creating for an MBSE project.

Generate these from a buildMyViews() step that runs after buildMyModel() (otherwise the model rebuild wipes them). A short, high-value starter set:

ViewQuerySignals
CostDriversCost > 0.1 × budgetComponents that dominate the cost budget — first targets for trimming when an SR fails
HighPowerConsumersPower > 10% of capLikely contributors to a power-margin miss
HeavyStructureMass > 1000 kg (or project-appropriate)Typically the chassis / pressure vessels / bulk hardware — candidates for material substitution
ZeroedEstimates_FlagMass == 0 on non-leaf componentsCatches components where the estimate was forgotten; PostOrder rollup will mask this silently otherwise
ThroughputContributorsThroughput > 0The production-pipeline members — the ones whose min drives the system bottleneck

The first three are standard procurement/budget views. ZeroedEstimates_Flag is the one that reliably catches mistakes: if a component has no stereotype values set, the rollup silently treats it as 0. A view that highlights zeros in red during review is more reliable than reading the analysis printout.

Views also support explicit element lists (no query) for groupings that depend on allocation or supplier rather than a single property — see system-composer skill for the pattern.


Allocation (Phases 6–8)

Three distinct allocation steps:

PhaseWhatAPI
6Functional → Logical allocation setsystemcomposer.allocation
7Logical → Physical allocation setsystemcomposer.allocation
8Requirements → Component Implement linksslreq.createLink

Phase 6: Functional-to-Logical Allocation Set

Maps each logical function to the logical element(s) that realize it.

See code/buildAllocationSet.m. The allocation set name is derived automatically by appending 'Set' to the file base name:

buildAllocationSet(allocFile, funcModelName, logicalModelName, archDir)

Reuse the default scenario; do not call createScenario. createAllocationSet auto-creates a default scenario named "Scenario 1". If you call createScenario on top of that, you get a second scenario and the Allocation Editor opens to the empty default — making it look like nothing is allocated. Instead: rename allocSet.Scenarios(1) and populate it.


Phase 7: Logical-to-Physical Allocation Set

Maps each logical element to the physical component(s) that implement it. Uses the same function — just pass the logical and physical model names:

buildAllocationSet(allocFile, logicalModelName, physModelName, archDir)

Query allocations

allocatedTo = getAllocatedTo(scenario, funcArch.getComponent('FunctionA'));
for i = 1:numel(allocatedTo), fprintf('%s\n', allocatedTo(i).Name); end

Open the Allocation Editor

systemcomposer.allocation.editor('path/to/MyAllocation.mldatx')

Phase 8: Architecture → Requirements Implement Links

Implement links connect architecture artifacts to the system requirements they realize ("requirement → implemented by → architectural element"). Per slreq convention the link source is the architecture element and the destination is the requirement:

lnk      = slreq.createLink(component, req);   % source = component, destination = requirement
lnk.Type = 'Implement';

From the requirement's perspective these are inLinks(), not outLinks. The cleanup helper for idempotent rebuilds iterates req.inLinks() and filters by source artifact.

Register the link-store file with the project. The first time slreq creates a link into a model, it auto-generates {modelName}~mdl.slmx next to the .slx to store the link data. Every allocation script must register this file with the project (alongside the .slx), or project checks will fail and the traceability won't travel with the project.

This is distinct from the allocation sets (Phases 6–7, systemcomposer.allocation) — Implement links live in the requirements toolbox and are queryable via slreq.

Refine links remain a valid slreq link type, but are reserved for refining a requirement into more specific requirements (same artifact kind, more detail). Do not use Refine for requirement → architecture in this workflow.

Three sets of Implement links are created, in order:

SR → Function (mandatory): Every SR must trace to at least one function in the functional architecture. This closes the loop between requirements and the functional decomposition — if a function has no SRs pointing to it, it is either orphaned or covering an undocumented need.

SR → Logical component: Use when the requirement is non-functional (timing, performance, safety, security) or is specific to a logical solution role.

SR → Physical component: Use when the requirement is hardware-specific (connector type, EMC rating, operating temperature range, packaging envelope, installation constraints).

One SR may link to a function and a logical and a physical component. Each link type answers a different question: what does the system do (F), what kind of element owns it (L), what hardware implements it (P).

See code/buildAllocation.m for the full parameterized function:

buildAllocation(reqDir, archDir)

Never use '..' in paths passed to System Composer — use fileparts twice to get the project root, then addpath before opening the model by name (shown above).

Addressing nested components in allocation tables

Sub-components inside a composite (e.g. CoordinateOperations/SequenceProduction) can't be resolved by a single getComponent call — you have to walk into each parent's .Architecture. Use the shared helper code/resolveComponent.m so every allocation script uses the same path-resolution logic:

comp = resolveComponent(arch, 'Parent/Child');       % nested
comp = resolveComponent(arch, 'TopLevelComponent');  % also works

Keep the per-SR allocation tables as { 'SR-ID', { 'Parent/Child', 'Other' } } cell arrays and loop through resolveComponent — the same idiom works at every layer (F→SR, L→SR, P→SR, and F→L / L→P allocation sets).


Analysis (Phase 6)

Analysis is optional and project-specific. Read references/analysis.md in this skill folder when the user needs to set up quantitative analysis (roll-up, trade study, sensitivity, margins).

Default pattern for roll-ups: write a dedicated analysis function (MySystemRollupAnalysis.m, one file per model, signature function fn(instance, varargin)) matching the MathWorks CostAndWeightRollupAnalysis shape, and drive it with iterate(instance, 'PostOrder', @fn). Do not default to flat-loop aggregation in MATLAB — the analysis-function approach writes rolled-up values to every parent in the hierarchy so the Instance Viewer is useful at every level. Details, non-sum aggregations (min/mean), and when to bypass the pattern: references/analysis.md. Runnable templates: code/myRollupAnalysis.m (analysis function) and code/runMyAnalysis.m (driver).

Gives 0 of the 12 instructions most architecture codebase skills give in ~4.4k tokens

Counted across 811 of the 1,134 authors here whose files we hold, read 2026-08-06

  • ask the user which candidate to explorein 46 of 811, across 16 files
  • apply the deletion test to suspected shallow modulesin 43 of 811, across 15 files
  • read any relevant architecture decision records firstin 31 of 811, across 7 files
  • use exact glossary terms in every suggestionin 29 of 811, across 9 files
  • accept dependencies instead of creating themin 24 of 811, across 5 files
  • include before and after visualisations for each candidatein 24 of 811, across 5 files
  • read the domain glossary before exploringin 24 of 811, across 6 files
  • return results instead of producing side effectsin 23 of 811, across 4 files
  • explore the codebase for shallow modules and frictionin 23 of 811, across 3 files
  • introduce seams only where things varyin 22 of 811, across 3 files
  • reduce the number of methodsin 21 of 811, across 2 files
  • design deep modules with small interfacesin 21 of 811, across 2 files

Said here and by no other author read

  • Build functional, logical, and physical models sequentially
  • Create independent interface dictionaries for each model
  • Write idempotent build scripts to construct models
  • Define and apply stereotype properties at end of script
  • Untrack project files before deleting them from disk
  • Pass folder paths instead of file paths to profile save

Grouped from the skills themselves: near-identical wordings counted once, and counted by distinct author, so one author publishing three of these counts once. Length counted with cl100k_base; the agent that loads this file may tokenize it differently.

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.