MATLAB Bridge
Drive the user's live MATLAB session on Windows. Nothing is clicked:
commands go in over COM, results come back through files. MATLAB must already be
running.
Locate the driver
$MLB = Join-Path $env:LOCALAPPDATA 'mlbridge\mlbridge.ps1'
if (-not (Test-Path $MLB)) {
# not deployed yet: install from this skill's bundle, then read its DRIVER line
powershell.exe -NoProfile -ExecutionPolicy Bypass -File ".\scripts\install.ps1"
}
Invoke it as:
powershell.exe -NoProfile -ExecutionPolicy Bypass -File $MLB <args>
-Help (or no arguments) prints the full option list.
| Goal |
Command |
| Run code |
-Code "A = magic(5); disp(sum(A))" |
| Run a .m file |
-ScriptFile D:\path\job.m |
| Long job, return at once |
-Code "do_work" -Async → then -Status -Id <id> |
| Long job, wait for it |
-Code "do_work" -Async -WaitSec 300 |
| Push a CSV in |
-Push in.csv -PushName D (combinable with -Code) |
| Pull a variable out |
-Pull D -Out out.csv |
| See the current figure |
-Shot (writes a PNG, prints its path) |
Hard rules
- Never read
Execute's return value — the driver already discards it. A
300x300 matrix costs 889 KB of text. Results arrive via the log tail.
diary does not work over COM (measured: the log stays 0 bytes). Output
is captured with evalc and written to <bridge>\logs\<id>.log.
- Use
-Async for anything slow. A synchronous call blocks MATLAB and can
hit the tool timeout. A COM round trip is only ~0.7 ms, so the real cost is
your turns: batch N steps into one -Code script instead of N calls.
- Keep bulk data out of stdout.
-Pull uses GetVariable and returns a
native .NET double[,] (200x200 in ~4 ms); big results should be written to
.mat/CSV by MATLAB and read from disk.
- Generated files are written as UTF-8 (MATLAB reports
feature('DefaultCharacterSet') == UTF-8); GBK produces mojibake.
-Shot raises the figure window (brief focus steal). That is the only
reliable way to capture MATLAB's OpenGL figure content.
- Task scripts must be valid MATLAB identifiers:
mlbtask_<id>.m. A name
starting with a digit or containing - makes run() fail silently.
- Never put
clear (or clear all) in a script you run via -ScriptFile.
The bridge runs it inside evalc in its own workspace, so clear wipes the
bridge's bookkeeping variables (mlb_out, …). The task then never completes:
the status file stays RUNNING with no log, and MATLAB looks idle (CPU flat).
If the script needs clear, use the batch route
instead — it gets a clean workspace of its own.
evalc only returns output when the body finishes, so a failure partway
through loses everything printed before it. For anything multi-step, have the
script append to its own log file (a fopen(...,'a') per line) — that
survives a crash. scripts/prog.m is a ready-made helper:
prog('step 2 done', fullfile(pwd,'run_progress.log')).
- Do not let a caller-side timeout kill the monitor process. If the shell
waiting on
-Async -WaitSec N is itself killed (e.g. by a 120 s tool cap),
the bridge never writes the final status and the task is stuck at RUNNING
forever. Either give the wait less time than the outer cap, or run the wait
as a background job.
Batch route (headless)
For work that must not touch the live session — a long model build, a
clear-using script, a reproducible re-run — use
scripts/batch_run.ps1 instead of COM. It starts a
separate matlab -batch process and handles three measured traps for you:
powershell.exe -NoProfile -ExecutionPolicy Bypass -File `
"C:\Users\<you>\.dsh\skills\matlab-bridge\scripts\batch_run.ps1" `
-ScriptFile D:\work\build_model.m -WorkDir D:\work -TimeoutSec 1800
| Trap |
What the helper does |
matlab -batch "run('X.m')" fails with "text character is invalid" on zh-CN, even for pure-ASCII files |
Invokes the script by bare name with -sd <dir> -batch <name> — the form that works |
A .m with Chinese comments/strings is misread as GBK |
Stages a copy as UTF-8 with BOM (-NoBom for ASCII-only) |
| A mid-run failure loses all buffered output |
Prints the script's own progress log, plus a filtered stdout/stderr tail |
| A hung MATLAB burns the session |
Applies -TimeoutSec itself and reports STATE: TIMEOUT |
It prints STATE: OK|ERR|TIMEOUT, EXIT, ELAPSED, the progress-log tail, and
the artifact list.
Simulink
Building/running a Simulink model from code has its own class of traps —
the worst being that an unconnected input port silently reads 0, so a model
can build, save and simulate while producing nonsense. Read
SIMULINK.md before scripting add_block / add_line / sim,
and always run its connectivity audit before trusting results.
Workflows
Analyse data and report
-Push data.csv -PushName D -Code "<compute; fprintf summary>"
- Check
STATE: OK, read the log tail. On STATE: ERR the detail is included.
Long simulation
-Code "<run; save results to .mat/.csv>" -Async → keep the returned id.
- Poll
-Status -Id <id> until OK / ERR, then read the result files.
(-Status only reads files, so polling works while MATLAB is busy.)
Iterate on a plot
-Code "<build figure with an explicit Name>"
-Shot, then inspect the PNG (e.g. with a vision tool).
Repair a wiped install
powershell.exe -NoProfile -ExecutionPolicy Bypass -File ".\scripts\install.ps1"
Troubleshooting
| Symptom |
Cause / fix |
Cannot attach to MATLAB |
MATLAB not running, or the automation server is off. Start MATLAB (startup.m enables it) or run enableservice('AutomationServer',true) inside MATLAB. |
STATE: NO-STATUS |
The task file never ran — inspect the generated pair in <bridge>\tasks. |
Log empty, STATE: OK |
The code simply printed nothing. |
| Shot shows the desktop |
No figure is open (or close all ran). |
Design decisions, the full pitfall log, and path resolution: REFERENCE.md.
1---2name: matlab-bridge3description: Control an already-running MATLAB session from DSH over Windows COM automation - execute code or .m scripts, exchange matrices through files, poll long-running jobs, and capture figure windows as PNG. Use when a task involves MATLAB or Simulink, running or authoring .m code, plotting or simulating in MATLAB, or when MATLAB is open and the work should land in that live session.4---56# MATLAB Bridge78Drive the user's **live** MATLAB session on Windows. Nothing is clicked:9commands go in over COM, results come back through files. MATLAB must already be10running.1112## Locate the driver1314```powershell15$MLB = Join-Path $env:LOCALAPPDATA 'mlbridge\mlbridge.ps1'16if (-not (Test-Path $MLB)) {17 # not deployed yet: install from this skill's bundle, then read its DRIVER line18 powershell.exe -NoProfile -ExecutionPolicy Bypass -File ".\scripts\install.ps1"19}20```2122Invoke it as:2324```powershell25powershell.exe -NoProfile -ExecutionPolicy Bypass -File $MLB <args>26```2728`-Help` (or no arguments) prints the full option list.2930| Goal | Command |31|---|---|32| Run code | `-Code "A = magic(5); disp(sum(A))"` |33| Run a .m file | `-ScriptFile D:\path\job.m` |34| Long job, return at once | `-Code "do_work" -Async` → then `-Status -Id <id>` |35| Long job, wait for it | `-Code "do_work" -Async -WaitSec 300` |36| Push a CSV in | `-Push in.csv -PushName D` (combinable with `-Code`) |37| Pull a variable out | `-Pull D -Out out.csv` |38| See the current figure | `-Shot` (writes a PNG, prints its path) |3940## Hard rules41421. **Never read `Execute`'s return value** — the driver already discards it. A43 300x300 matrix costs 889 KB of text. Results arrive via the log tail.442. **`diary` does not work over COM** (measured: the log stays 0 bytes). Output45 is captured with `evalc` and written to `<bridge>\logs\<id>.log`.463. **Use `-Async` for anything slow.** A synchronous call blocks MATLAB and can47 hit the tool timeout. A COM round trip is only ~0.7 ms, so the real cost is48 *your* turns: batch N steps into one `-Code` script instead of N calls.494. **Keep bulk data out of stdout.** `-Pull` uses `GetVariable` and returns a50 native .NET `double[,]` (200x200 in ~4 ms); big results should be written to51 `.mat`/CSV by MATLAB and read from disk.525. **Generated files are written as UTF-8** (MATLAB reports53 `feature('DefaultCharacterSet') == UTF-8`); GBK produces mojibake.546. `-Shot` raises the figure window (brief focus steal). That is the only55 reliable way to capture MATLAB's OpenGL figure content.567. Task scripts must be **valid MATLAB identifiers**: `mlbtask_<id>.m`. A name57 starting with a digit or containing `-` makes `run()` fail silently.588. **Never put `clear` (or `clear all`) in a script you run via `-ScriptFile`.**59 The bridge runs it inside `evalc` in its own workspace, so `clear` wipes the60 bridge's bookkeeping variables (`mlb_out`, …). The task then never completes:61 the status file stays `RUNNING` with no log, and MATLAB looks idle (CPU flat).62 If the script needs `clear`, use the [batch route](#batch-route-headless)63 instead — it gets a clean workspace of its own.649. **`evalc` only returns output when the body finishes**, so a failure partway65 through loses everything printed before it. For anything multi-step, have the66 script append to its own log file (a `fopen(...,'a')` per line) — that67 survives a crash. [scripts/prog.m](scripts/prog.m) is a ready-made helper:68 `prog('step 2 done', fullfile(pwd,'run_progress.log'))`.6910. **Do not let a caller-side timeout kill the monitor process.** If the shell70 waiting on `-Async -WaitSec N` is itself killed (e.g. by a 120 s tool cap),71 the bridge never writes the final status and the task is stuck at `RUNNING`72 forever. Either give the wait less time than the outer cap, or run the wait73 as a background job.7475## Batch route (headless)7677For work that must **not** touch the live session — a long model build, a78`clear`-using script, a reproducible re-run — use79[scripts/batch_run.ps1](scripts/batch_run.ps1) instead of COM. It starts a80separate `matlab -batch` process and handles three measured traps for you:8182```powershell83powershell.exe -NoProfile -ExecutionPolicy Bypass -File `84 "C:\Users\<you>\.dsh\skills\matlab-bridge\scripts\batch_run.ps1" `85 -ScriptFile D:\work\build_model.m -WorkDir D:\work -TimeoutSec 180086```8788| Trap | What the helper does |89|---|---|90| `matlab -batch "run('X.m')"` fails with *"text character is invalid"* on zh-CN, even for pure-ASCII files | Invokes the script **by bare name** with `-sd <dir> -batch <name>` — the form that works |91| A `.m` with Chinese comments/strings is misread as GBK | Stages a copy as **UTF-8 with BOM** (`-NoBom` for ASCII-only) |92| A mid-run failure loses all buffered output | Prints the script's own progress log, plus a filtered stdout/stderr tail |93| A hung MATLAB burns the session | Applies `-TimeoutSec` itself and reports `STATE: TIMEOUT` |9495It prints `STATE: OK|ERR|TIMEOUT`, `EXIT`, `ELAPSED`, the progress-log tail, and96the artifact list.9798## Simulink99100Building/running a Simulink model from code has its own class of traps —101**the worst being that an unconnected input port silently reads 0**, so a model102can build, save and simulate while producing nonsense. Read103[SIMULINK.md](SIMULINK.md) before scripting `add_block` / `add_line` / `sim`,104and always run its connectivity audit before trusting results.105106## Workflows107108**Analyse data and report**1091. `-Push data.csv -PushName D -Code "<compute; fprintf summary>"`1102. Check `STATE: OK`, read the log tail. On `STATE: ERR` the detail is included.111112**Long simulation**1131. `-Code "<run; save results to .mat/.csv>" -Async` → keep the returned id.1142. Poll `-Status -Id <id>` until `OK` / `ERR`, then read the result files.115 (`-Status` only reads files, so polling works while MATLAB is busy.)116117**Iterate on a plot**1181. `-Code "<build figure with an explicit Name>"`1192. `-Shot`, then inspect the PNG (e.g. with a vision tool).120121**Repair a wiped install**122123```powershell124powershell.exe -NoProfile -ExecutionPolicy Bypass -File ".\scripts\install.ps1"125```126127## Troubleshooting128129| Symptom | Cause / fix |130|---|---|131| `Cannot attach to MATLAB` | MATLAB not running, or the automation server is off. Start MATLAB (`startup.m` enables it) or run `enableservice('AutomationServer',true)` inside MATLAB. |132| `STATE: NO-STATUS` | The task file never ran — inspect the generated pair in `<bridge>\tasks`. |133| Log empty, `STATE: OK` | The code simply printed nothing. |134| Shot shows the desktop | No figure is open (or `close all` ran). |135136Design decisions, the full pitfall log, and path resolution: [REFERENCE.md](REFERENCE.md).