Install
$ agentstack add skill-wolframresearch-system-modeler-ai-toolkit-diagnose-modelica ✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
About
Diagnose Modelica Model
This skill generates a comprehensive diagnostic report for a Modelica model. You run the model through the bundled launcher, then turn the artifacts it leaves behind into a report with the bundled report_blocks.py / trace_variable.py scripts. The report covers variable counts, equation structure, block analysis, solver settings, and (if simulated) runtime performance.
Before you run anything
This skill drives WSMKernelX through the shared launcher ../scripts/wsm_run.py. Read [the shared-conventions appendix at the end of this file](#appendix-shared-conventions-for-the-modelica-skills) first — launcher resolution, the Windows-vs-Unix shell/Python rules, the temp-dir and cleanup conventions, the JSON-array output gotcha, and the MSL 4.x dialect notes that every step below assumes.
In --mode diagnose the launcher enables the diagnostic options it needs and keeps all intermediate build artifacts for the report scripts (report_blocks.py / trace_variable.py). It works in _wsm_diagnose_temp/ next to the .mo file and leaves all artifacts there. Tell the user: "Working in temporary directory _wsm_diagnose_temp/. This will be deleted after the report is generated."
Workflow
1. Identify the model file and name
Identify the .mo file and extract the model name — see [Appendix → Picking the model name](#picking-the-model-name). For a directory-form (multi-file) library, point --model at the library folder (not one class file) and pass the full dotted --name — see [Appendix → Directory-form (multi-file) libraries](#directory-form-multi-file-libraries).
2. Run the launcher
python3 "/wsm_run.py" --mode diagnose \
--model "" --name ModelName --timeout 180
MSL is auto-detected; override with --msl yes|no or --msl-version 4.1.0. If the model uses an installed non-MSL library (e.g. Hydraulic), add --load-library — see [Appendix → Using non-MSL libraries](#using-non-msl-libraries-hydraulic-and-other-installed-libraries).
For structure only, skip the simulation entirely: add --no-sim (build-only, much faster). The structural report below still works; only the runtime-performance line is omitted.
A Fatal error: exception ...(_) (e.g. ErrorExt.ErrorMessage(_), LError.Errors(_)) is not an opaque crash — it's a normal error (assertion, parameter/init, type, lookup) that +g let escape, since +g keeps build artifacts but disables exception catching. On any failure the launcher prints the recovered message in an === actual kernel diagnostic === block (re-running the same call without +g, so exception catching is back on and the error surfaces at whatever stage it occurred). Read that block first; don't infer a compiler bug from the Fatal error line. Use the staged diagnostics below only if it surfaces nothing readable.
Staged diagnostics (for a genuinely opaque crash)
A full run goes through the whole pipeline (flatten → optimize → build → simulate); a crash partway through gives no clue which stage failed. The launcher's --call option runs a stage-restricted entry point so you can bracket the failure, and --debug adds the compiler's per-stage dumps and execution statistics:
| --call | What it does | When to use | |----------|--------------|-------------| | instantiate | Flatten only. | First call when a model is failing — confirms whether flattening succeeds. | | build | Flatten + translate to simulator (no simulation). | If flatten passes but the full run crashes — isolates optimization/code-gen from the runtime. | | sim | Full pipeline including simulation. | Default for healthy models (used when --call is omitted). |
Workflow (only when the diagnostic block above surfaced nothing readable):
- Run with
--call instantiatefirst. If it fails → it's a flatten error (type/connection/balance). Read the=== actual kernel diagnostic ===block, thendiagnose.out.jsonin the temp dir. - If flatten passes, run
--call build --debugand capture stdout — the last stage printed before the crash localizes the bug. The--debugoutput can be large, so redirect it:
``bash python3 "/wsm_run.py" --mode diagnose \ --model "" --name ModelName \ --call build --debug > debug.log 2>&1 ``
- Only then run the default (
--call sim, or omit it) for the full report.
If the log shows ++++ Running or runtime annotation lines, the model already built — the failure is at init/simulation (a model error), not code-gen; a truncated _build.log ("Step 2 of 4") does not mark where it died.
3. Generate the structural report
After a successful run, use the bundled report_blocks.py script to generate a complete report. This is the preferred approach — it parses all the artifacts automatically, so you never need to read them by hand:
python3 "/report_blocks.py" \
"/ModelName_blockdebug.json" \
--header "/ModelName_header.h" \
--reslog "/ModelName_res.log"
The script produces a full report covering variable counts, block summaries, non-trivial systems with solvability details, eliminated aliases, and runtime performance.
Prefer --summary (or --json) for a few-line digest — states, algebraic/parameter counts, zero-crossings, coupled-system count + largest block, and runtime — instead of the full multi-screen report. Reach for the full report only when you need block-level detail. With --no-sim the same --summary works from the _blockdebug.json alone; only the runtime-performance line is omitted.
The artifacts report_blocks.py reads all live in the temp dir (ModelName_header.h, ModelName.sim, ModelName_blockdebug.json, ModelName_res.log, ModelName.log, diagnose.out.json). The script understands their formats for you; only open them directly if you need to dig past what the report surfaces.
4. Present the diagnostic report
Present the report to the user in this format:
# Diagnostic Report: ModelName
## Build Status
- Flatten: Pass/Fail
- Build: Pass/Fail
- Simulation: Pass/Fail
## Model Summary
| Metric | Count |
|--------|-------|
| Continuous states (NX) | ... |
| Discrete states (NDX) | ... |
| Algebraic variables (NY) | ... |
| Parameters (NP) | ... |
| Inputs (NI) | ... |
| Outputs (NO) | ... |
| Zero crossings | ... |
| External objects | ... |
| Clocked partitions | ... |
## Solver Settings
- Method: ...
- Time range: ... to ...
- Step size: ...
- Output steps: ...
## Variable Details
| Name | Kind | Type | Unit | Init |
|------|------|------|------|------|
| ... | STATE | Real | m/s | exact |
## Equation Structure
### Initialization (N blocks)
- Block 0: [solved] variable_name ← equation_text
- ...
### ODE (N blocks)
- Block 0: [solved] ...
- ...
### Output (N blocks)
- ...
### Eliminated Variables (N aliases)
- gain.u → sine.y
- ...
## Potential Issues
- [List any nonlinear systems, large blocks, unsolvable equations, etc.]
## Runtime Performance
- Integration time: ... s
- Function evaluations: ...
- Events: ...
- Step events (dynamic state switches): ...
## Compiler
- Version: ...
Tailor the "Potential Issues" section based on what report_blocks.py reports:
- Nonlinear blocks → "Nonlinear system of N equations — may cause convergence issues at initialization or during simulation"
- Large algebraic loops → "Algebraic loop with N equations — consider breaking with
Modelica.Blocks.Math.InverseBlockConstraintsor adding initial guesses" - Many zero crossings → "N zero crossings — may cause slow simulation due to frequent event detection"
- No states → "No continuous states — this is a purely algebraic/discrete model"
- Many events at runtime → "N events detected — consider smoothing discontinuities"
5. Trace a specific variable (optional)
If the user asks to trace a variable (e.g. "trace clutch1.wrel", "what equations solve wrel"), use the bundled trace_variable.py script to walk the full dependency chain.
The script needs the _blockdebug.json produced in step 2. Run it from the temp directory:
python3 "/trace_variable.py" "/ModelName_blockdebug.json" "variable.name" --section both
Options for --section:
init— How the variable gets its starting value (initialization phase)ode— How the variable is computed each integration stepboth— Show both traces (default)
The script automatically:
- Walks backwards through predecessor blocks from the target variable to all leaf nodes
- Shows each equation, its source file/line, and solvability
- Flags non-trivial solvability (nonlinear, mixed, conditioned, relaxed)
- If the variable isn't found in the ODE section, automatically tries
der(variable)(since state variables are integrated, their derivatives are what appears in the ODE blocks) - Reports eliminated variable aliases
6. Clean up
Remove _wsm_diagnose_temp/ entirely — commands per OS: [Appendix → Temporary directories](#temporary-directories).
Edge cases
- Model fails to flatten: Report errors from
diagnose.out.json. Analyze the error messages and suggest fixes (missing components, type mismatches, unbalanced equations). - Model flattens but fails to build: Still run
report_blocks.pyon_blockdebug.jsonif it was generated — it's produced before compilation. Report build errors fromModelName.log. - Model builds but fails to simulate: Report runtime errors from
_res.log. Check for division by zero, assertion failures, or solver convergence issues. Fatal error: exception ...(_)(no_blockdebug.jsonor.sim): a normal error+glet escape, not a compiler bug. Read the launcher's=== actual kernel diagnostic ===block (it auto-recovers the message by re-running the same call without+g). Only if it surfaces nothing readable, use the staged diagnostics above; report to Wolfram only when the failure lands in a compiler stage with no model-level cause.- Multiple models in one file: Use the top-level model/package name — see [Appendix → Picking the model name](#picking-the-model-name).
- WSMKernelX or compiler not found: see [Appendix → When the install or compiler isn't found](#when-the-install-or-compiler-isnt-found).
Appendix: shared conventions for the Modelica skills
> Shared by every Modelica skill that drives WSMKernelX through the > bundled launcher; inlined here at release time. For the CLI/option > reference, environment variables (WSM_HOME, WSM_VSDEVCMD), > install discovery, and the analysis scripts, see > [../scripts/README.md](../scripts/README.md).
Locating the launcher
` (used throughout the skills) is the shared scripts/` folder. Some installs symlink the skill directories without it, so resolve it in this order and use the first that exists:
$WSM_SKILLS_SCRIPTS(bash) or$env:WSM_SKILLS_SCRIPTS(PowerShell), if set.../scriptsrelative to the skill directory — in a normal install
../scripts/wsm_run.py already exists, so use that path directly; do not run a shell probe to "resolve" it.
- The repo checkout you installed from, e.g.
.../agentskills/scripts. - Last resort, search the home directory:
- PowerShell:
Get-ChildItem $HOME -Recurse -Filter wsm_run.py -ErrorAction SilentlyContinue | Select-Object -First 1 - bash/zsh:
find ~ -name wsm_run.py -path '*scripts*' 2>/dev/null | head -1
If only #4 finds it, the install is missing the scripts/ link — tell the user to run install.sh (or install.ps1) from the repo, which links scripts/ too.
Shell and Python
On Windows, use PowerShell. The Git-Bash/cygwin layer may be broken (even ls/find can be absent, giving a misleading "exit 127 / command not found"). Run wsm_run.py with python (not python3); those calls are single-line and shell-agnostic. For cleanup use Remove-Item -Recurse -Force, not rm -rf. On macOS/Linux any POSIX shell is fine and python3 is the usual name.
Let the launcher own .mos/.bat and paths
Do not hand-write .mos scripts, .bat files, or hardcode install/compiler paths. The bundled scripts/wsm_run.py handles every OS difference — it finds the System Modeler install and kernel binary (macOS / Windows / Linux), finds and loads the right MSL files, generates the .mos, and runs the kernel with a working compiler environment per platform (system clang/gcc on macOS/Linux; the Visual Studio dev environment via VsDevCmd.bat on Windows). See [../scripts/README.md](../scripts/README.md) for WSM_HOME, the Windows compiler prerequisites, and the full option table.
When the install or compiler isn't found
The launcher searches each OS's standard install locations. If it prints ERROR: Could not locate a Wolfram System Modeler installation, the install is in a non-standard place — ask the user for it and re-run with --wsm-home "" (or have them set WSM_HOME).
Building and simulating also need a C++ toolchain:
- Windows: Visual Studio Build Tools. The launcher locates
VsDevCmd.bat
itself; if it reports the compiler environment is missing, pass --vsdevcmd "" (or set WSM_VSDEVCMD) and make sure Build Tools are installed.
- macOS: the Xcode command-line tools (
xcode-select --install). - Linux: gcc/g++.
Run python3 "/wsm_run.py" --mode info to see what the launcher discovered.
Temporary directories
The launcher works in a _wsm__temp/ directory next to the .mo file (_wsm_validate_temp/, _wsm_simulate_temp/, _wsm_diagnose_temp/) and leaves its outputs there. Tell the user, e.g.: "Working in temporary directory _wsm__temp/. This will be deleted afterwards." Pass --tempdir to reuse one directory across models in a session.
Clean up by removing the whole directory — use the user's shell:
rm -rf "/_wsm__temp" # macOS / Linux
# PowerShell: Remove-Item -Recurse -Force "\_wsm__temp"
Picking the model name
- The user may provide a path to a
.mofile, or you may already be working with
one in context.
- Extract the model name: the identifier after
modelon the first non-comment
line, e.g. model FooBar → FooBar. The filename does not always match the model name — parse the actual model/package declaration.
- For packages or nested models, use the top-level model name.
- Pick an instantiable model, not a package, for any kernel call. A
package
cannot be validated or simulated ("Invalid instantiation … is a package") — use a nested model's full dotted name, e.g. Package.Model.
- Pass an absolute path to
--model(relative paths break as the working
directory shifts between calls).
Directory-form (multi-file) libraries
A directory-form library stores one class per file with a package.mo at each level. You cannot validate such a class by handing the launcher only its own .mo file — the class's within Lib; clause needs the whole package loaded, and loading the single file alone fails with Internal error: ... expandLibNode: Unknown library: Lib. Instead point --model at the library folder (or its top package.mo, or any class file inside it) and pass the full dotted class name via --name:
python3 "/wsm_run.py" --mode validate \
--model "/abs/path/InvertedPendulum" \
--name InvertedPendulum.Controller
The launcher resolves any of those forms up to the library's root package.mo and loads the entire package (following package.order) before instantiating --name. It prints a NOTE: telling you which package.mo it loaded. Do not try to work around the unknown-library error by --load-ing individual files.
Reading the JSON output
The kernel writes .out.json into the temp dir. **It is a JSON array — take the first element**, then read:
status.flatten:"Pass"/"Fail"(the primary result forvalidate).status.build:"Pass"/"Fail"— C++ compilation/linking (simulate).- **
…
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: WolframResearch
- Source: WolframResearch/system-modeler-ai-toolkit
- License: MIT
- Homepage: https://www.wolfram.com/system-modeler/
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet — be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.