# Matlab Bridge

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

- Skill: `infei12306/matlab-bridge` (Agent Skill, multi-file: 7 files)
- Install (CLI): `npx skillmds@latest add infei12306/matlab-bridge`
- Raw SKILL.md: https://api.skillmd.com/api/skills/infei12306/matlab-bridge/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Productivity
- Author: infei12306 (https://skillmd.com/u/infei12306)
- Updated: 2026-09-22
- Page: https://skillmd.com/skills/infei12306/matlab-bridge

---


# 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

```powershell
$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
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

1. **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.
2. **`diary` does not work over COM** (measured: the log stays 0 bytes). Output
   is captured with `evalc` and written to `<bridge>\logs\<id>.log`.
3. **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.
4. **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.
5. **Generated files are written as UTF-8** (MATLAB reports
   `feature('DefaultCharacterSet') == UTF-8`); GBK produces mojibake.
6. `-Shot` raises the figure window (brief focus steal). That is the only
   reliable way to capture MATLAB's OpenGL figure content.
7. Task scripts must be **valid MATLAB identifiers**: `mlbtask_<id>.m`. A name
   starting with a digit or containing `-` makes `run()` fail silently.
8. **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](#batch-route-headless)
   instead — it gets a clean workspace of its own.
9. **`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](scripts/prog.m) is a ready-made helper:
   `prog('step 2 done', fullfile(pwd,'run_progress.log'))`.
10. **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](scripts/batch_run.ps1) instead of COM. It starts a
separate `matlab -batch` process and handles three measured traps for you:

```powershell
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](SIMULINK.md) before scripting `add_block` / `add_line` / `sim`,
and always run its connectivity audit before trusting results.

## Workflows

**Analyse data and report**
1. `-Push data.csv -PushName D -Code "<compute; fprintf summary>"`
2. Check `STATE: OK`, read the log tail. On `STATE: ERR` the detail is included.

**Long simulation**
1. `-Code "<run; save results to .mat/.csv>" -Async` → keep the returned id.
2. 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**
1. `-Code "<build figure with an explicit Name>"`
2. `-Shot`, then inspect the PNG (e.g. with a vision tool).

**Repair a wiped install**

```powershell
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](REFERENCE.md).

