Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Interact with a Simulink model currently open in MATLAB via the MATLAB MCP server. Use this skill whenever the user asks to inspect, modify, query, or navigate a Simulink model that is open in MATLAB — for example changing block properties, finding blocks, adding blocks, connecting signals, or navigating model hierarchy. Trigger whenever the user refers to "this model", "this block", "this subsystem", "selected blocks", or asks to do anything to a Simulink model without specifying a file path to
.claude/skills/hashgraph-online-simulink-interactions/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-04 | ✗→✓ | ▲ Improved | 57% | 0% |
| case-05 | ✗→✓ | ▲ Improved | 231% | 0% |
| case-06 | ✗→✓ | ▲ Improved | 33% | 0% |
| case-07 | ✗→✓ | ▲ Improved | 154% | 0% |
| case-09 | ✗→✓ | ▲ Improved | 161% | 0% |
This skill defines conventions for interacting with the Simulink model currently open in MATLAB, using mcp__matlab__evaluate_matlab_code as the primary tool.
If the MATLAB MCP tool is unavailable in the current session but the user explicitly asks for real model creation or modification, fall back to local MATLAB execution such as matlab -batch. State the fallback briefly and keep the workflow identical: inspect, modify, verify, save.
Before doing anything, determine what model/system/block(s) the user is referring to.
| User says | Resolution | |---|---| | "this model" | bdroot(gcs) | | "this system" / "this subsystem" | gcs | | "this block" | gcb | | "selected blocks" (plural) | see snippet below | | "all Type] blocks in this subsystem" | see snippet below | | "all Type] blocks in the model" | see snippet below |
matlabopts = Simulink.FindOptions; opts.SearchDepth = 1; blks = getfullname(Simulink.findBlocks(gcs, 'Selected', 'on', opts));
matlabopts = Simulink.FindOptions; opts.SearchDepth = 1; BlockType = 'Gain'; % replace with actual type blks = getfullname(Simulink.findBlocksOfType(gcs, BlockType, opts));
matlabBlockType = 'Gain'; % replace with actual type blks = getfullname(Simulink.findBlocksOfType(bdroot, BlockType));
Use get_param to read current state before making changes. This helps you confirm you have the right block and understand its current configuration.
matlabget_param(gcb, 'Gain') % read a specific parameter get_param(gcb,'DialogParameters') % list all dialog parameters get_param(gcb, 'ObjectParameters') % list all available parameters
Use set_param for most property changes:
matlabset_param(gcb, 'Gain', '2') set_param(gcb, 'BackgroundColor', 'red')
For bulk operations on multiple blocks, iterate over the blks cell array:
matlabfor i = 1:numel(blks) set_param(blks{i}, 'BackgroundColor', 'yellow'); end
When adding blocks, follow these rules:
'Position' argument to add_blockset_param(blk, 'Position', ...) or set_param(blk, 'Location', ...)Simulink.BlockDiagram.arrangeSystemgetBlockPosition and setBlockDimensions (bundled in utils/) for all positioninggetBlockDimensions; to resize, use setBlockDimensionsUtility signatures (see utils/ for full source):
matlab[x, y] = getBlockPosition(block) % top-left corner [width, height] = getBlockDimensions(block) % block size setBlockPosition(block, x, y) % move, preserving size setBlockDimensions(block, width, height) % resize, preserving top-left
Never use set_param(block, 'Position', ...) — always use setBlockPosition and/or setBlockDimensions instead.
matlab% Example: add a Gain block to the right of the current block modelName = bdroot(gcs); refBlk = gcb; % 1. Get reference block geometry [refX, refY] = getBlockPosition(refBlk); [refW, ~] = getBlockDimensions(refBlk); % 2. Add block (no position argument) newBlk = [modelName '/MyGain']; add_block('built-in/Gain', newBlk); % 3. Position it to the right of the reference block gap = 50; setBlockPosition(newBlk, refX + refW + gap, refY); % 4. Connect it Simulink.connectBlocks(Source,Destination);
When editing a MATLAB Function block programmatically, do not assume set_param(block,'Script',...) exists. For MATLAB Function blocks, update the script through MATLABFunctionConfiguration:
matlabblk = 'model/MyMATLABFunction'; cfg = get_param(blk, 'MATLABFunctionConfiguration'); cfg.FunctionScript = sprintf([ ... 'function y = fcn(u)\n' ... '%%#codegen\n' ... 'y = 2*u;\n' ... 'end\n']);
If the function body references workspace parameters such as Kp, tau_sys, or Q_max, explicitly create Stateflow.Data entries with Scope = 'Parameter' or Simulink may fail size/type inference during compile:
matlabrt = sfroot; machine = rt.find('-isa', 'Stateflow.Machine', 'Name', bdroot(blk)); chart = machine.find('-isa', 'Stateflow.EMChart', 'Path', blk); param = Stateflow.Data(chart); param.Name = 'Q_max'; param.Scope = 'Parameter';
Without this explicit parameter declaration, a programmatically generated MATLAB Function block can fail with errors like "cannot determine output size/type" even when the same code works interactively.
Common built-in library paths:
built-in/Gainbuilt-in/Productbuilt-in/Constantbuilt-in/Scopebuilt-in/SubsystemException for Inport and Outport use:
sprintf('simulink/Ports &\nSubsystems/In1')sprintf('simulink/Ports &\nSubsystems/Out1')Exception for Sum. Never use the Sum block, always use Add or Subtract instead:
sprintf(['simulink/Math\nOperations/Add'])sprintf(['simulink/Math\nOperations/Subtract'])Always use Simulink.connectBlocks to connect blocks — never add_line. This API is more robust and handles port resolution automatically.
matlab% Connect two blocks (Simulink picks the appropriate ports) Simulink.connectBlocks(srcBlock, dstBlock); % Connect specific ports when needed Simulink.connectBlocks([srcBlock '/1'], [dstBlock '/1']);
When the user asks to log a signal, use Simulink's built-in signal logging on the port directly. Never use a To Workspace block or a To File block.
matlab% Log the first output port of a block ph = get_param(gcb, 'PortHandles'); set(ph.Outport(1), 'DataLogging', 'on'); % Set the name lf the logged signal set(ph.Outport(1), 'DataLoggingNameMode', 'SignalName'); set(ph.Outport(1), 'Name', 'mySignalName');
To log a specific block by path instead of gcb:
matlabph = get_param('modelName/BlockName', 'PortHandles'); set(ph.Outport(1), 'DataLogging', 'on');
After simulation, logged signals are accessible via logsout in the SimulationOutput object (when using sim()) or via Simulink.SimulationData.Dataset.
If the user explicitly asks for To Workspace blocks or named workspace artifacts as deliverables, follow the user's request. The "never use To Workspace" rule is only the default when the user asks to log signals and does not constrain the export mechanism.
When adding a group of related blocks that should live inside a subsystem, add and connect all the blocks first (following the iterative one-at-a-time workflow above), then group them into a subsystem at the end:
matlab% Collect handles of all blocks to group blocks = [get_param('model/Block1', 'Handle'), ... get_param('model/Block2', 'Handle'), ... get_param('model/Block3', 'Handle')]; % Group into a subsystem — Simulink handles port creation automatically Simulink.BlockDiagram.createSubsystem(blocks);
createSubsystem automatically adds the necessary Inport/Outport blocks inside the subsystem and rewires external connections. Do not manually create a Subsystem block and move blocks into it.
Simulink.BlockDiagram.deleteContents only accepts a block diagram, not an arbitrary subsystem path. If you need to rebuild a subsystem in place, delete its lines and child blocks manually:
matlabsubsys = 'model/MySubsystem'; lines = find_system(subsys, 'FindAll', 'on', 'SearchDepth', 1, 'Type', 'line'); if ~isempty(lines) delete_line(lines); end blocks = find_system(subsys, 'SearchDepth', 1, 'Type', 'Block'); blocks = setdiff(blocks, {subsys}, 'stable'); for i = 1:numel(blocks) delete_block(blocks{i}); end
This is the safe pattern when regenerating subsystem internals from a script.
After making changes, confirm success by reading back the modified parameter or reporting what was changed.
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | fail→fail | 30,961 | 16,545 | -47% | 1 | 1 | 0% | 1,196 | 3,384 | +183% | 0 | 0 | — |
case-02 | fail→fail | 19,101 | 21,469 | +12% | 1 | 1 | 0% | 2,831 | 2,895 | +2% | 0 | 0 | — |
case-03 | fail→fail | 19,656 | 33,725 | +72% | 1 | 1 | 0% | 2,385 | 3,358 | +41% | 0 | 0 | — |
case-04 | fail→pass | 11,264 | 16,758 | +49% | 1 | 1 | 0% | 2,051 | 3,222 | +57% | 0 | 0 | — |
case-05 | fail→pass | 10,706 | 10,343 | -3% | 1 | 1 | 0% | 981 | 3,247 | +231% | 0 | 0 | — |
case-06 | fail→pass | 24,348 | 13,251 | -46% | 1 | 1 | 0% | 2,695 | 3,575 | +33% | 0 | 0 | — |
case-07 | fail→pass | 13,858 | 14,754 | +6% | 1 | 1 | 0% | 1,679 | 4,270 | +154% | 0 | 0 | — |
case-08 | fail→fail | 15,453 | 10,330 | -33% | 1 | 1 | 0% | 1,968 | 2,912 | +48% | 0 | 0 | — |
case-09 | fail→pass | 7,473 | 6,952 | -7% | 1 | 1 | 0% | 1,405 | 3,662 | +161% | 0 | 0 | — |
case-10 | fail→pass | 13,534 | 6,820 | -50% | 1 | 1 | 0% | 1,577 | 3,548 | +125% | 0 | 0 | — |
case-11 | fail→pass | 18,706 | 10,671 | -43% | 1 | 1 | 0% | 2,427 | 3,379 | +39% | 0 | 0 | — |
case-12 | pass→pass | 18,006 | 11,568 | -36% | 1 | 1 | 0% | 2,690 | 4,568 | +70% | 0 | 0 | — |
case-13 | pass→pass | 14,470 | 11,128 | -23% | 1 | 1 | 0% | 1,725 | 3,407 | +98% | 0 | 0 | — |
case-14 | pass→pass | 17,716 | 10,061 | -43% | 1 | 1 | 0% | 2,032 | 3,149 | +55% | 0 | 0 | — |
case-15 | fail→fail | 6,184 | 23,250 | +276% | 1 | 1 | 0% | 1,126 | 3,164 | +181% | 0 | 0 | — |
case-16 | fail→fail | 10,933 | 12,444 | +14% | 1 | 1 | 0% | 1,015 | 3,688 | +263% | 0 | 0 | — |
case-17 | fail→pass | 11,851 | 10,536 | -11% | 1 | 1 | 0% | 1,398 | 3,362 | +140% | 0 | 0 | — |
case-18 | pass→fail | 11,168 | 33,783 | +202% | 1 | 1 | 0% | 2,313 | 5,550 | +140% | 0 | 0 | — |
case-19 | pass→pass | 6,229 | 27,161 | +336% | 1 | 1 | 0% | 963 | 3,890 | +304% | 0 | 0 | — |
case-20 | pass→fail | 7,769 | 50,121 | +545% | 1 | 1 | 0% | 1,554 | 10,915 | +602% | 0 | 0 | — |
case-21 | fail→pass | 7,357 | 19,348 | +163% | 1 | 1 | 0% | 1,339 | 3,554 | +165% | 0 | 0 | — |
case-22 | fail→pass | 16,455 | 10,653 | -35% | 1 | 1 | 0% | 1,819 | 3,316 | +82% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted, and 15 counted toward the lift figure. The other 7 produced results that are not comparable between the two arms, so they are excluded from the headline rather than averaged into it. The headline lift of +36 percentage points is the difference between those two pass rates over the 15 comparable cases. 4 cases got worse with the skill loaded, and they are included in that figure.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.