Simulation Orchestrator logo

Simulation Orchestrator

Community
HeshamFS
simulation-orchestrator

Orchestrate multi-simulation campaigns — generate parameter sweep configurations (grid, linspace, or Latin Hypercube sampling), initialize and track batch job campaigns, monitor job completion status, and aggregate results with summary statistics across all runs. Use when running a parameter study across dt, kappa, or other simulation inputs, managing dozens or hundreds of simulation configurations, combining outputs from completed batch runs to find the best result, or automating the generate-run-collect workflow for systematic studies, even if the user only says "I need to try many parameter combinations" or "how do I organize a sweep."

Overview

PublisherHeshamFS
Repositorymaterials-simulation-skills
Skill namesimulation-orchestrator
Stars
83
Forks
6
Bundled files
24
LicenseApache-2.0
Links
  • Markdown instructions

    A SKILL.md file the model loads on demand, so it only costs tokens when a request actually matches.

  • Works with any LLM

    AI skills are plain Markdown, not provider-specific code, so this works with GPT, Claude, Gemini, Grok, or a local model.

  • 24 bundled files

    Scripts, templates, and references the model can read while it works. Files are read-only and never executed.

  • Open source

    Published by HeshamFS on GitHub. Read the source before you install it.

Installation

Install the Simulation Orchestrator AI skill in TypingMind to use it with any LLM, or drop it into another agent that reads SKILL.md.

1

Install in TypingMind

TypingMind installs a skill straight from its GitHub folder — it reads SKILL.md, bundles the resource files, and stores the result locally.

  1. Open the app and go to Plugins → Skills.
  2. Choose "Install from GitHub".
  3. Paste the skill folder URL below and confirm.
    https://github.com/HeshamFS/materials-simulation-skills/tree/main/skills/simulation-workflow/simulation-orchestrator
  4. Enable the skill in any chat where you want it available.
Plugins → Skills → Add skill → From GitHub URL, then paste the folder URL and press Continue.
2

Install in another agent

Any agent that reads the Agent Skills format can use this skill — copy the folder into that agent's skills directory.

Claude Code — .claude/skills
git clone --depth 1 https://github.com/HeshamFS/materials-simulation-skills.git /tmp/materials-simulation-skills
mkdir -p .claude/skills
cp -r /tmp/materials-simulation-skills/skills/simulation-workflow/simulation-orchestrator .claude/skills/simulation-orchestrator
Restart Claude Code after copying so it picks up the new skill.

Use it in TypingMind

Enable Simulation Orchestrator in any TypingMind chat and the model takes it from there. Its name and description sit in the system prompt, and the moment a request matches, the model loads the full instructions itself — you never invoke it by hand, and it costs no tokens until it is actually used.

The model loads Simulation Orchestrator on its own as soon as a request matches it.

Works with any AI model

AI skills are plain Markdown instructions rather than provider-specific code, so Simulation Orchestrator is not tied to the model it was written for. Install it once in TypingMind and use it with GPT-5, Claude, Gemini, Grok, DeepSeek, Mistral, Llama, or a local model you run yourself — all on your own API keys.

  • Loaded only when it is needed

    The system prompt carries just the name and description. The instructions are fetched on the first matching request, so an idle skill costs nothing.

  • Switch models mid-chat

    Because the skill is instructions rather than code, changing model does not break it — the next model reads the same SKILL.md.

Skill instructions

This is the SKILL.md content the model loads. Read it before installing — a skill is instructions your model will follow.

Simulation Orchestrator

Goal

Provide tools to manage multi-simulation campaigns: generate parameter sweeps, track job execution status, and aggregate results from completed runs.

Requirements

  • Python 3.10+
  • No external dependencies (uses Python standard library only)
  • Works on Linux, macOS, and Windows

Inputs to Gather

Before running orchestration scripts, collect from the user:

InputDescriptionExample
Base configTemplate simulation configurationbase_config.json
Parameter rangesParameters to sweep with boundsdt:[1e-4,1e-2],kappa:[0.1,1.0]
Sweep methodHow to sample parameter spacegrid, lhs, linspace
Output directoryWhere to store campaign files./campaign_001
Simulation commandCommand to run each simulationpython sim.py --config {config}

Decision Guidance

Choosing a Sweep Method

Need every combination (full factorial)?
├── YES → Use grid (warning: exponential growth with parameters)
└── NO → Is space-filling coverage needed?
    ├── YES → Use lhs (Latin Hypercube Sampling)
    └── NO → Use linspace for uniform sampling per parameter
MethodBest ForSample Count
gridLow dimensions (1-3), need exact cornersn^d (exponential)
linspace1D sweeps, uniform spacingn per parameter
lhsHigh dimensions, space-fillinguser-specified budget

Campaign Size Guidelines

ParametersGrid Points EachTotal RunsRecommendation
11010Grid is fine
210100Grid acceptable
3101,000Consider LHS
4+1010,000+Use LHS or DOE

Script Outputs (JSON Fields)

ScriptOutput Fields
scripts/sweep_generator.pyconfigs, parameter_space, sweep_method, total_runs
scripts/campaign_manager.py --action initcampaign_id, total_jobs, config_dir, command_template
scripts/campaign_manager.py --action statuscampaign_id, status, jobs, progress, total_jobs, created_at
scripts/campaign_manager.py --action listjobs (array of job records)
scripts/job_tracker.pyjob_id, status, start_time, end_time, exit_code
scripts/result_aggregator.pysummary (incl. minimize), statistics, best_run, failed_runs

Note on swept parameter names: sweep_generator.py writes each swept value into the base config by key path. A bare name (e.g. kappa) overwrites a top-level key; a dot-notation name (e.g. parameters.kappa) targets a nested key. The swept key path must match where the solver reads the value — sweeping kappa against a config that nests parameters.kappa would add an unused top-level key and silently leave the base value in place. See references/sweep_strategies.md.

Workflow

Step 1: Generate Parameter Sweep

Create configurations for all parameter combinations:

bash
python3 scripts/sweep_generator.py \
    --base-config base_config.json \
    --params "dt:1e-4:1e-2:5,kappa:0.1:1.0:3" \
    --method linspace \
    --output-dir ./campaign_001 \
    --json

Step 2: Initialize Campaign

Create campaign tracking structure:

bash
python3 scripts/campaign_manager.py \
    --action init \
    --config-dir ./campaign_001 \
    --command "python sim.py --config {config}" \
    --json

Step 3: Track Job Status

Monitor running jobs:

bash
python3 scripts/job_tracker.py \
    --campaign-dir ./campaign_001 \
    --update \
    --json

Step 4: Aggregate Results

Combine results from completed runs:

bash
python3 scripts/result_aggregator.py \
    --campaign-dir ./campaign_001 \
    --metric final_energy \
    --json

result_aggregator.py minimizes by default: best_run is the run with the lowest metric value (and summary.minimize is true). If higher is better (e.g. yield, accuracy, throughput), pass --maximize so best_run becomes the highest value:

bash
# Higher is better -> select the maximum
python3 scripts/result_aggregator.py \
    --campaign-dir ./campaign_001 \
    --metric yield \
    --maximize \
    --json

Decision guidance: If higher is better (yield, accuracy, throughput), pass --maximize; otherwise the reported best_run is the minimum.

CLI Examples

bash
# Generate 5x3=15 runs varying dt (5 values) and kappa (3 values)
python3 scripts/sweep_generator.py \
    --base-config sim.json \
    --params "dt:1e-4:1e-2:5,kappa:0.1:1.0:3" \
    --method linspace \
    --output-dir ./sweep_001 \
    --json

# Generate LHS samples for 4 parameters with budget of 20 runs
python3 scripts/sweep_generator.py \
    --base-config sim.json \
    --params "dt:1e-4:1e-2,kappa:0.1:1.0,M:1e-6:1e-4,W:0.5:2.0" \
    --method lhs \
    --samples 20 \
    --output-dir ./lhs_001 \
    --json

# Check campaign status
python3 scripts/campaign_manager.py \
    --action status \
    --config-dir ./sweep_001 \
    --json

# List jobs (read-only), optionally filtered by status
python3 scripts/campaign_manager.py \
    --action list \
    --config-dir ./sweep_001 \
    --status-filter failed \
    --json

# Get summary statistics from completed runs (minimize: best = lowest)
python3 scripts/result_aggregator.py \
    --campaign-dir ./sweep_001 \
    --metric final_energy \
    --json

# Maximization metric: best = highest value (yield, accuracy, throughput)
python3 scripts/result_aggregator.py \
    --campaign-dir ./sweep_001 \
    --metric yield \
    --maximize \
    --json

Conversational Workflow Example

User: I want to run a parameter sweep on dt and kappa for my phase-field simulation. I want to try 5 values of dt between 1e-4 and 1e-2, and 4 values of kappa between 0.1 and 1.0.

Agent workflow:

  1. Calculate total runs: 5 x 4 = 20 runs
  2. Generate sweep configurations:
    bash
    python3 scripts/sweep_generator.py \
        --base-config simulation.json \
        --params "dt:1e-4:1e-2:5,kappa:0.1:1.0:4" \
        --method linspace \
        --output-dir ./dt_kappa_sweep \
        --json
  3. Initialize campaign:
    bash
    python3 scripts/campaign_manager.py \
        --action init \
        --config-dir ./dt_kappa_sweep \
        --command "python phase_field.py --config {config}" \
        --json
  4. After user runs simulations, aggregate results:
    bash
    python3 scripts/result_aggregator.py \
        --campaign-dir ./dt_kappa_sweep \
        --metric interface_width \
        --json

Error Handling

ErrorCauseResolution
Base config not foundInvalid file pathVerify base config file exists
Invalid parameter formatMalformed param stringUse format name:min:max:count or name:min:max
Output directory existsWould overwriteUse --force or choose new directory
No completed jobsNo results to aggregateWait for jobs to complete or check for failures
Metric not foundResult files missing fieldVerify metric name in result JSON

Integration with Other Skills

The simulation-orchestrator works with other simulation-workflow skills:

parameter-optimization          simulation-orchestrator
        │                              │
        │ DOE samples ────────────────>│ Generate configs
        │                              │
        │                              │ Run simulations
        │                              │
        │<──────────────────────────── │ Aggregate results
        │                              │
        │ Sensitivity analysis         │
        │ Optimizer selection          │

Typical Combined Workflow

  1. Use parameter-optimization/doe_generator.py to get sample points
  2. Use simulation-orchestrator/sweep_generator.py to create configs
  3. Run simulations (user's responsibility)
  4. Use simulation-orchestrator/result_aggregator.py to collect results
  5. Use parameter-optimization/sensitivity_summary.py to analyze

Verification checklist

Before trusting a campaign's best_run or summary statistics, record concrete evidence for each item:

  • Confirmed the swept key path actually changed the value the solver reads: opened at least one generated config_NNNN.json and verified the swept parameter (e.g. parameters.kappa) holds the expected value at the expected nesting level, not a duplicate unused top-level key (sweep_generator.py writes by key path).
  • Reconciled job accounting from result_aggregator.py --json: recorded summary.total_jobs, summary.completed, and summary.failed, and confirmed completed + failed == total_jobs. Any shortfall means runs were silently skipped (missing result file or extract_metric returned None) and must be investigated, not ignored.
  • Confirmed completed > 0 and that the recorded summary.metric matches the field the solver actually writes. A typo'd or absent metric makes extract_metric return None, yielding zero completed runs with no error.
  • Recorded summary.minimize and confirmed it matches the intended direction (default minimize; --maximize for yield/accuracy/throughput) before quoting best_run.
  • Did NOT treat job_tracker.py "completed" as physical success: it flags a job completed purely from a result-file's existence and stamps exit_code 0 — independently checked the run's real exit status / solver logs for non-zero codes or NaN/Inf output.
  • Applied an outlier/sanity check to the metric values (e.g. Tukey 1.5x IQR from references/aggregation_methods.md) and confirmed best_run.value is physically plausible, not a crashed run that emitted a spurious extremum.
  • For LHS sweeps, recorded the --seed used and saved manifest.json (parameter bounds, total_runs, parameter_space) so the sample set is reproducible.

Common pitfalls & rationalizations

Tempting shortcutWhy it's wrong / what to do
"The job tracker says completed, so the run succeeded."job_tracker.py marks "completed" whenever a result file exists and hard-codes exit_code 0 — it never reads the actual exit code. A crashed run that wrote a partial result file looks identical to a clean one. Check the solver's real exit status and output validity.
"completed is high, so I have all my results."Jobs with a missing result file or a metric that extract_metric can't read are silently skipped — neither counted as completed nor failed. Reconcile completed + failed against total_jobs; a gap means lost runs.
"Aggregation returned a best_run, so that's the optimum."By default the aggregator minimizes. If higher is better you must pass --maximize, or best_run is the worst point. Always record summary.minimize and confirm the direction.
"I swept kappa, so the runs vary."sweep_generator.py writes by key path. If the base config nests the value under parameters.kappa but you sweep the bare name kappa, every config keeps the original nested value and gains an unused top-level key — the sweep is scientifically meaningless. Sweep the exact dotted path the solver reads.
"The metric name is close enough."A misspelled or absent metric makes extract_metric return None for every run, so completed is 0 and statistics are empty — with no error raised. Verify the metric matches the solver's output field exactly.
"Grid covers everything, so use it for all my parameters."Grid is n^d — it explodes exponentially (4 params x 10 = 10,000 runs). For 4+ dimensions use lhs with a deliberate budget; reserve grid for 1-3 parameters.
"LHS is random, so I don't need to record anything."LHS is reproducible only with a fixed --seed. Without recording the seed (and manifest.json), the sample set cannot be regenerated or defended.

Security

Input Validation

  • Metric names (result_aggregator.py --metric) are validated against [a-zA-Z_][a-zA-Z0-9_.]* to prevent traversal or injection via crafted keys
  • Swept parameter names (sweep_generator.py --params) are validated against [a-zA-Z_][a-zA-Z0-9_]*(.[a-zA-Z_][a-zA-Z0-9_]*)* (dot notation for nested keys); invalid names are rejected
  • campaign_manager.py validates command templates to reject shell chaining operators (;, |, &, backticks, $)
  • --params format strings are parsed and validated (name:min:max:count with finite numeric bounds — NaN/Inf rejected — min < max, and positive integer counts capped at 100,000); at most 32 parameters per sweep
  • --method is validated against a fixed allowlist (grid, linspace, lhs)
  • --samples is validated as a positive integer with an upper bound (max 1,000,000)
  • --action is validated against a fixed allowlist (init, status, list); for the read-only list action, --status-filter is validated against pending, running, completed, failed

File Access

  • sweep_generator.py reads a single base config file (JSON) specified by --base-config and writes generated configs to --output-dir
  • result_aggregator.py enforces a 10 MB file-size limit per result file, maximum JSON nesting depth, and strict numeric type checking (rejects bool, NaN, Inf)
  • All string values from result files are sanitized (truncated, control characters stripped) before surfacing them
  • Config paths interpolated into shell commands are validated against a safe-character allowlist and escaped with shlex.quote()

Tool Restrictions

  • Read: Used to inspect script source, references, base configs, and campaign status files
  • Write: Used to save generated sweep configs, campaign manifests, and aggregated results; writes are scoped to the user's working directory
  • Grep/Glob: Used to locate campaign files, result files, and search references
  • The skill's allowed-tools excludes Bash to prevent the agent from executing arbitrary commands when processing untrusted simulation outputs

Safety Measures

  • No eval(), exec(), or dynamic code generation
  • All subprocess calls use explicit argument lists (no shell=True)
  • Reduced tool surface (no Bash) limits the agent to read/write operations only
  • Command templates are validated but never executed by the skill itself; execution is the user's responsibility

Limitations

  • Not a job scheduler: Does not submit jobs to SLURM/PBS; generates configs and tracks status
  • No parallel execution: User must run simulations externally (can use GNU parallel, SLURM, etc.)
  • File-based tracking: Status tracked via files; no database or real-time monitoring
  • Local filesystem: Assumes all files accessible from local machine

References

  • references/campaign_patterns.md - Common campaign structures
  • references/sweep_strategies.md - Parameter sweep design guidance
  • references/aggregation_methods.md - Result aggregation techniques

Version History

  • v1.1.4 (2026-10-19): Preserve failure evidence and unknown exit codes, reject corrupt outputs, and retain small physical statistics without rounding.

See CHANGELOG.md for the authoritative, dated history. Summary:

  • v1.1.3 (2026-06-24): Added a Verification checklist and a Common pitfalls & rationalizations section grounded in the scripts' real behavior (result-file-only "completed" detection, silent skip of unreadable metrics, minimize-by-default direction, key-path merge semantics)
  • v1.1.1 (2026-06-23): Dot-notation nested overrides in sweep_generator.py, input-validation hardening (--params name/finite/count caps, --samples bounds), documented --maximize and the list action, corrected Script Outputs table and worked-example numbers
  • v1.1.0 (2026-03-26): Standardized metadata, evaluation suite, security review, CHANGELOG
  • v1.0.0 (2026-02-25): Initial release with sweep, campaign, tracking, and aggregation

Bundled files

The model reads these on demand while the skill is loaded. They are exposed as readable files and are never executed.

Frequently asked questions

What does the Simulation Orchestrator AI skill do?

Orchestrate multi-simulation campaigns — generate parameter sweep configurations (grid, linspace, or Latin Hypercube sampling), initialize and track batch job campaigns, monitor job completion status, and aggregate results with summary statistics across all runs. Use when running a parameter study across dt, kappa, or other simulation inputs, managing dozens or hundreds of simulation configurations, combining outputs from completed batch runs to find the best result, or automating the generate-run-collect workflow for systematic studies, even if the user only says "I need to try many parame...

Why use Simulation Orchestrator on TypingMind?

Because you install it once and use it with any model. Simulation Orchestrator is plain Markdown rather than provider-specific code, so the same skill runs on GPT-5, Claude, Gemini, Grok, or a local model — and you can switch model mid-chat without it breaking. TypingMind runs on your own API keys, so you pay providers directly instead of a per-seat subscription, and your skills and chats stay in your own storage.

How do I install Simulation Orchestrator in TypingMind?

Open Plugins → Skills → Install from GitHub in TypingMind and paste https://github.com/HeshamFS/materials-simulation-skills/tree/main/skills/simulation-workflow/simulation-orchestrator. TypingMind reads its SKILL.md and bundles its files and installs it as a skill you can enable per chat.

Which AI models can use Simulation Orchestrator?

Any model you connect in TypingMind. AI skills are plain Markdown instructions rather than provider-specific code, so GPT, Claude, Gemini, Grok, and local models can all load this skill when a request matches it.

How many AI models can I use with Simulation Orchestrator?

As many as you like. As long as a model supports skills, you can use Simulation Orchestrator with it — GPT, Claude, Gemini, Grok, DeepSeek, Mistral, Llama and more — all on TypingMind with your own API keys.

Is the Simulation Orchestrator AI skill free?

Yes. It is published on GitHub by HeshamFS under the Apache-2.0 license. You only pay your own AI provider for the tokens you use.

What are AI skills?

An AI skill is a reusable instruction bundle that teaches an AI model how to do one specific task. It follows the open Agent Skills format: a SKILL.md file with a name and description, plus any scripts, templates or reference files the model may need. The model reads the instructions only when your request matches the skill, so an installed skill costs nothing until it is used.

How are AI skills different from plugins or MCP servers?

A plugin or MCP server gives a model new tools to call — code that runs somewhere and returns a result. An AI skill gives the model knowledge and process instead: how to approach a task, which steps to follow, what good output looks like. Skills are plain Markdown, so they need no server, no API key and no runtime, and they work with any model.

View all

Set up your own AI workspace now

Get notified about new features and future giveaways by subscribing to our newsletter 👇