An interactive Python REPL for OMNeT++ — run simulations, analyze results, and automate testing from an IPython shell or the command line.
- Run simulations — run all or filtered simulations from a project, sequentially or concurrently, on localhost or an SSH cluster
- MCP server — expose the REPL to AI assistants via the Model Context Protocol
- Build projects — build simulation binaries from Python
- Smoke tests — verify that simulations start and terminate without crashing
- Fingerprint tests — detect behavioral regressions by comparing event fingerprints against a stored baseline
- Statistical tests — detect regressions in scalar results by comparing against stored baseline values
- Chart tests — detect visual regressions by comparing rendered analysis charts against baseline images
- Speed tests — detect performance regressions by comparing CPU instruction counts against a baseline
- Feature tests — verify that projects build and simulations set up correctly with different optional feature combinations
- Sanitizer tests — find memory errors and undefined behavior using AddressSanitizer / UBSan instrumentation
- Release tests — run a comprehensive validation suite for release builds
- Parameter optimization — find simulation parameter values that produce desired results using derivative-free optimization
- Simulation comparison — compare stdout trajectories, fingerprint trajectories, and scalar results between two projects or git commits
- Coverage reports — generate C++ line-coverage reports using LLVM's coverage tools
- Overlay builds — out-of-tree builds using fuse-overlayfs on top of read-only source trees
- SSH cluster execution — distribute simulation tasks across multiple machines using Dask
- GitHub Actions integration — dispatch CI workflows from the REPL
- IDE integration — connect to the OMNeT++ IDE via Py4J
All features are accessible both from the interactive REPL and as
command-line tools (opp_run_simulations, opp_run_fingerprint_tests,
opp_update_correct_fingerprints, etc.).
Requires Python 3.10+.
pip install -e .Optional extras:
pip install -e ".[all]" # install every optional group
pip install -e ".[cluster]" # just one group| Extra | Packages | Purpose |
|---|---|---|
cluster |
dask, distributed | SSH cluster execution via Dask |
chart |
matplotlib, numpy | Chart tests and image export |
mcp |
mcp | MCP server for AI assistant integration |
optimize |
scipy, optimparallel | Parameter optimization |
github |
requests | GitHub API integration |
ide |
py4j | OMNeT++ IDE integration |
all |
(all of the above) | Everything |
# Start the REPL, loading project descriptors
opp_repl --load ~/workspace/omnetpp/omnetpp.opp \
--load "~/workspace/omnetpp/samples/*/*.opp"
# Or load opp_env-managed projects
opp_repl --load "~/opp_env/**/*.opp"
# Multiple --load arguments can be combined
opp_repl --load ~/workspace/omnetpp/omnetpp.opp \
--load "~/workspace/omnetpp/samples/*/*.opp" \
--load ~/workspace/inet/inet.oppOnce inside the REPL:
In [1]: run_simulations(simulation_project=fifo_project)opp_repl [-h]
[-p PROJECT] # set default simulation project by name
[-l {ERROR,WARN,INFO,DEBUG}] # log level (default: INFO)
[--external-command-log-level {ERROR,WARN,INFO,DEBUG}]
[--mcp-port PORT] # MCP server port, 0 to disable (default: 0)
[--load OPP_FILE] # load .opp file(s), repeatable, supports globs
[--handle-exception | --no-handle-exception]
opp_repl is organized around a hierarchy of concepts that mirror the structure of OMNeT++ simulation projects.
Represents a specific OMNeT++ installation on disk. It knows where to
find the opp_run executable, which build modes are available, and how to
compile OMNeT++ itself. Every simulation project references an
OmnetppProject (either explicitly or via a global default).
For local installations the root folder is typically resolved from an
environment variable or an explicit path. For opp_env-managed installations
the opp_env_workspace and opp_env_project parameters tell opp_repl to
route build and run commands through opp_env run.
Represents a simulation model project — a codebase that contains NED modules, C++ sources, and example simulations. Examples include INET, Simu5G, or any of the OMNeT++ sample projects (aloha, fifo, tictoc, …).
A simulation project knows:
- where the sources live —
root_folder,library_folder,bin_folder,ned_folders,cpp_folders,msg_folders - what to build —
build_types("executable"or"dynamic library"),executables,dynamic_libraries - where the simulations are —
ini_file_folders(scanned for*.inifiles) - what it depends on —
omnetpp_project(the OMNeT++ to use),used_projects(other simulation projects like INET)
The project also supports overlay builds (via fuse-overlayfs) for
testing patches without modifying the original source tree, and
opp_env integration for projects managed by the opp_env tool.
Represents a single [Config …] section from one INI file within a
simulation project. It is automatically discovered by scanning the
ini_file_folders of the project.
Key properties:
working_directory— the folder containing the INI file (relative to the project root)ini_file— the INI file name (e.g.omnetpp.ini)config— the section name (e.g."General","PureAlohaExperiment")num_runs— the total number of runs, determined from iteration variables like${x=1,2,3}andrepeat=Nin the INI fileabstract— iftrue, the config is meant to be extended, not run directlysim_time_limit— the simulation time limit from the INI file, if any
Represents a single simulation run — one specific (config, run number) combination that can be executed as a subprocess. A simulation task is fully parameterized: it knows the config, the run number, the build mode, any overridden time limits, etc.
Tasks are created by get_simulation_tasks() which expands each
SimulationConfig into num_runs individual tasks (one per run number).
Both build_project() and run_simulations() accept a mode parameter.
The available modes are:
| Mode | Suffix | Use case |
|---|---|---|
release |
_release |
Normal optimized builds (default) |
debug |
_dbg |
Debug builds for stepping through code |
sanitize |
_sanitize |
AddressSanitizer / UBSan builds |
coverage |
_coverage |
Code coverage instrumented builds |
profile |
_profile |
Performance profiling builds |
A simulation task can be executed by different runners, selected via
the simulation_runner parameter of run_simulations():
subprocess(default) — launches the simulation as a child process.opp_env— routes the command throughopp_env runfor opp_env-managed installations (selected automatically when the project hasopp_env_workspaceset).inprocess— runs the simulation inside the Python process via CFFI (requiresomnetpp.cffi).ide— attaches the IDE debugger to the simulation (selected automatically whendebug=True).
The outcome of running a task — captures the return code, stdout/stderr,
elapsed wall time, error messages, last event number and simulation time,
and result files (.sca, .vec, .elog). Results are classified as
DONE, ERROR, CANCEL, or SKIP.
Running simulations typically involves many tasks at once.
run_simulations() returns a MultipleTaskResults object that summarizes
the overall outcome and provides methods to filter (e.g. get_error_results())
and re-run subsets.
A registry that holds all loaded OmnetppProject and
SimulationProject instances. Projects are registered by loading .opp
descriptor files via --load on the command line or load_opp_file() at
runtime.
opp_repl maintains three global defaults so that most functions can be called without explicitly specifying a workspace or project:
-
Default workspace — a
SimulationWorkspaceinstance created automatically at startup. All.oppfiles loaded via--load(orload_opp_file()at runtime) are registered here. Access it withget_default_simulation_workspace(). -
Default simulation project — set at startup to the loaded project whose root folder contains the current working directory. It can also be set explicitly with
-p PROJECTon the command line orset_default_simulation_project()at runtime. Functions likerun_simulations(),run_smoke_tests(), andbuild_project()use it when nosimulation_projectargument is given. Access it withget_default_simulation_project(). -
Default OMNeT++ project — set automatically when the default simulation project is determined: if the simulation project references an
OmnetppProject(via itsomnetpp_projectparameter), that becomes the default; otherwise the project registered under the name"omnetpp"is used as a fallback. Access it withget_default_omnetpp_project().
At REPL startup, every loaded simulation project is also injected into
the IPython namespace as a convenience variable named
{name}_project (with hyphens and dots replaced by underscores). For
example, loading a project named "inet" creates a variable
inet_project, and "simu5g" creates simu5g_project.
SimulationWorkspace
├── OmnetppProject "omnetpp" (OMNeT++ installation)
├── SimulationProject "inet" (model project)
│ ├── SimulationConfig examples/ethernet/simple -c General (1 run)
│ ├── SimulationConfig examples/wireless/nic -c Wifi (10 runs)
│ │ ├── SimulationTask run #0
│ │ ├── SimulationTask run #1
│ │ └── …
│ └── …
└── SimulationProject "simu5g" (depends on inet)
└── …
Most functions that operate on simulation configs accept regex-based include/exclude filter pairs to narrow down what is selected. The filters are regular expressions matched against the corresponding property; a config is included only when all specified filters match.
| Include filter | Exclude filter | Matches against |
|---|---|---|
filter |
exclude_filter |
full config string representation |
working_directory_filter |
exclude_working_directory_filter |
working directory path |
ini_file_filter |
exclude_ini_file_filter |
INI file name |
config_filter |
exclude_config_filter |
config section name |
run_number_filter |
exclude_run_number_filter |
run number (as string) |
In addition, the simulation_config_filter parameter accepts a
predicate function that receives each SimulationConfig and returns
True/False. By default it excludes abstract and emulation configs.
Setting full_match=True requires the regex to match the entire string
rather than just a substring.
These filters are available on run_simulations(), run_smoke_tests(),
run_fingerprint_tests(), compare_simulations(), and all other
functions that call get_simulation_tasks() internally.
Projects are described by .opp files — small Python expressions that
define either an OmnetppProject or a SimulationProject. They use a
restricted syntax: a single constructor call with keyword-only literal
arguments (strings, numbers, booleans, lists, dicts, None).
Describes an OMNeT++ installation.
OmnetppProject(
name="omnetpp",
)Parameters:
| Parameter | Type | Description |
|---|---|---|
name |
str |
Human-readable name for this OMNeT++ installation |
environment_variable |
str |
OS environment variable pointing to the root folder (default: "__omnetpp_root_dir") |
root_folder |
str |
Explicit root folder path (overrides environment_variable) |
overlay_key |
str |
Enable overlay builds via fuse-overlayfs with this key |
build_root |
str |
Override the overlay build root directory |
opp_env_workspace |
str |
Path to opp_env workspace (for opp_env-managed installations) |
opp_env_project |
str |
opp_env project identifier (e.g. "omnetpp-6.3.0") |
Describes a simulation project (INET, Simu5G, OMNeT++ samples, etc.).
SimulationProject(
name="fifo",
omnetpp_project="omnetpp",
build_types=["executable"],
ned_folders=["."],
ini_file_folders=["."],
)Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
name |
str |
(required) | Human-readable project name |
version |
str |
None |
Version string |
omnetpp_project |
str |
None |
Name of the OmnetppProject to use (resolved lazily) |
root_folder |
str |
auto | Root folder (auto-set to the .opp file's directory) |
folder |
str |
"." |
Project directory relative to root |
bin_folder |
str |
"." |
Binary output directory relative to root |
library_folder |
str |
"." |
Library output directory relative to root |
build_types |
list[str] |
["dynamic library"] |
Build output types: "executable", "dynamic library", "static library" |
executables |
list[str] |
None |
Executable names to build |
dynamic_libraries |
list[str] |
None |
Dynamic library names to build |
ned_folders |
list[str] |
["."] |
Directories containing NED files |
ned_exclusions |
list[str] |
[] |
Excluded NED packages |
ini_file_folders |
list[str] |
["."] |
Directories containing INI files |
used_projects |
list[str] |
[] |
Names of dependent simulation projects |
media_folder |
str |
"." |
Directory for chart test baseline images |
statistics_folder |
str |
"." |
Directory for statistical test baseline results |
fingerprint_store |
str |
"fingerprint.json" |
Path to the JSON fingerprint store |
speed_store |
str |
"speed.json" |
Path to the JSON speed measurement store |
overlay_key |
str |
None |
Enable overlay builds with this key |
build_root |
str |
None |
Override overlay build root |
opp_env_workspace |
str |
None |
Path to opp_env workspace |
opp_env_project |
str |
None |
opp_env project identifier (e.g. "inet-4.6.0") |
github_owner |
str |
None |
GitHub owner/organization for workflow dispatch |
github_repository |
str |
None |
GitHub repository name for workflow dispatch |
github_workflows |
list[str] |
None |
GitHub Actions workflow file names (e.g. ["fingerprint-tests.yml"]) |
# ~/workspace/omnetpp/samples/aloha/aloha.opp
SimulationProject(
name="aloha",
omnetpp_project="omnetpp",
build_types=["executable"],
ned_folders=["."],
ini_file_folders=["."],
)# ~/workspace/inet/inet.opp
SimulationProject(
name="inet",
library_folder="src",
bin_folder="bin",
build_types=["dynamic library"],
dynamic_libraries=["INET"],
ned_folders=["src", "examples", "showcases", "tutorials", "tests/networks"],
ini_file_folders=["examples", "showcases", "tutorials", "tests/fingerprint"],
media_folder="doc/media",
statistics_folder="statistics",
fingerprint_store="tests/fingerprint/store.json",
speed_store="tests/speed/store.json",
github_owner="inet-framework",
github_repository="inet",
github_workflows=[
"fingerprint-tests.yml",
"statistical-tests.yml",
"chart-tests.yml",
],
)# ~/workspace/inet/inet+omnetpp.opp
SimulationProject(
name="inet+omnetpp",
omnetpp_project="omnetpp",
overlay_key="inet+omnetpp",
library_folder="src",
bin_folder="bin",
build_types=["dynamic library"],
dynamic_libraries=["INET"],
ned_folders=["src", "examples", "showcases", "tutorials", "tests/networks"],
ini_file_folders=["examples"],
)# ~/workspace/simu5g/simu5g.opp
SimulationProject(
name="simu5g",
omnetpp_project="omnetpp",
library_folder="src",
bin_folder="bin",
build_types=["dynamic library"],
dynamic_libraries=["simu5g"],
used_projects=["inet"],
ned_folders=["src", "simulations"],
ini_file_folders=["simulations"],
)# ~/opp_env/omnetpp-6.3.0/omnetpp.opp
OmnetppProject(
name="omnetpp-6.3.0-opp_env",
opp_env_workspace="/home/user/opp_env",
opp_env_project="omnetpp-6.3.0",
)# ~/opp_env/inet-4.6.0/inet-4.6.0.opp
SimulationProject(
name="inet-4.6.0-opp_env",
omnetpp_project="omnetpp-6.3.0-opp_env",
opp_env_project="inet-4.6.0",
opp_env_workspace="/home/user/opp_env",
library_folder="src",
bin_folder="bin",
build_types=["dynamic library"],
dynamic_libraries=["INET"],
ned_folders=["src", "examples", "showcases", "tutorials", "tests/networks"],
ini_file_folders=["examples"],
)# Run all simulations from a project
run_simulations(simulation_project=fifo_project)
# Run with a filter and time limit
run_simulations(simulation_project=aloha_project,
filter="PureAloha1", sim_time_limit="1s")
# Run a specific config
run_simulations(simulation_project=aloha_project,
config_filter="PureAlohaExperiment", sim_time_limit="1s")
# Run in debug mode
run_simulations(simulation_project=inet_project,
working_directory_filter="examples/ethernet",
mode="debug", sim_time_limit="10s")
# Re-run failed simulations
r = run_simulations(...)
r.get_error_results().rerun()build_project(simulation_project=inet_project)
build_project(simulation_project=inet_project, mode="debug")Quick sanity checks — run every simulation for a short time to catch crashes and obvious errors.
run_smoke_tests()
run_smoke_tests(simulation_project=aloha_project,
config_filter="PureAlohaExperiment")Fingerprint tests detect unintended behavioral changes by comparing a
hash of selected simulation state (trajectory, packet counts, etc.)
against stored baseline values. The baseline is kept in a JSON store
file configured via the fingerprint_store project parameter.
# Store correct fingerprints (first time, or after intentional changes)
update_correct_fingerprints(simulation_project=inet_project, sim_time_limit="1s")
# Verify against stored values
r = run_fingerprint_tests(simulation_project=inet_project, sim_time_limit="1s")
# Re-run only the failures
r.get_fail_results().rerun()
# Filter to a specific area of the project
run_fingerprint_tests(simulation_project=inet_project,
working_directory_filter="examples/ethernet",
sim_time_limit="10s")
# Update fingerprints for a subset after intentional changes
update_correct_fingerprints(simulation_project=inet_project,
working_directory_filter="examples/ethernet",
sim_time_limit="10s")From the command line:
# Store correct fingerprints for the fifo sample project
opp_update_correct_fingerprints --load "/home/levy/workspace/omnetpp/**/*.opp" -p fifo[0/8] ▶ 7 fifo update fingerprints (concurrently)
[1/8] ⏺ Updating fingerprint . -c TandemQueueExperiment -r 2 for 200s INSERT b654-75cc/tplx
...
[8/8] ◉ 7 fifo update fingerprints (concurrently) Multiple update fingerprints: 7 INSERT in 2.431
# Verify against stored values
opp_run_fingerprint_tests --load "/home/levy/workspace/omnetpp/**/*.opp" -p fifo[00/8] ▶ 7 fifo fingerprint tests (concurrently)
[01/8] ⏺ Checking fingerprint . -c TandemQueueExperiment -r 2 for 200s PASS in 0.015
...
[08/8] ◉ 7 fifo fingerprint tests (concurrently) Multiple fingerprint tests: 7 PASS in 3.01
Statistical tests detect regressions in simulation scalar results by
comparing them against saved baseline values. The baseline is stored
in the statistics_folder of the project.
# Store baseline results (first time, or after intentional changes)
update_statistical_results(simulation_project=inet_project)
# Run tests — compares current results against the baseline
run_statistical_tests(simulation_project=inet_project)
# Filter to a specific area
run_statistical_tests(simulation_project=inet_project,
working_directory_filter="examples/ethernet")Chart tests detect visual regressions in result analysis charts by
comparing rendered images against saved baseline images. The baseline
is stored in the media_folder of the project.
# Store baseline charts (first time, or after intentional changes)
update_charts(simulation_project=inet_project)
# Run tests — compares current charts against the baseline
run_chart_tests(simulation_project=inet_project)
# Filter by working directory or chart name
run_chart_tests(simulation_project=inet_project,
working_directory_filter="showcases")Speed tests detect performance regressions by measuring CPU instruction
counts and comparing them against stored baseline values. Uses the
profile build mode and the speed_store JSON file.
# Store baseline measurements (first time, or after intentional changes)
update_speed_results(simulation_project=inet_project)
# Run tests — compares current measurements against the baseline
run_speed_tests(simulation_project=inet_project)
# Filter to specific simulations
run_speed_tests(simulation_project=inet_project,
working_directory_filter="showcases")Find simulation parameter values that produce desired results by iteratively
running simulations and minimizing the difference from a target. Uses
scipy.optimize with Nelder-Mead (derivative-free, suitable for stochastic
simulations).
Example 1 — Aloha channel utilization. Find the inter-arrival time that maximizes channel utilization in slotted ALOHA. The theoretical maximum is 1/e ≈ 0.368; starting from the overloaded region (0.5 s) the optimizer converges to iaTime ≈ 1.87 s in about 40 evaluations:
optimize_simulation_parameters(
get_simulation_task(config_filter="SlottedAloha1", sim_time_limit="10min"),
expected_result_names=["channelUtilization:last"],
expected_result_values=[0.368],
fixed_parameter_names=[], fixed_parameter_values=[],
fixed_parameter_assignments=[], fixed_parameter_units=[],
parameter_names=["iaTime"],
parameter_assignments=["Aloha.host[*].iaTime"],
parameter_units=["exponential({0}s)"],
initial_values=[0.5], min_values=[0.1], max_values=[20]) ['iaTime'] = [0.5], ['channelUtilization:last'] = [0.129], diff = [0.239]
['iaTime'] = [0.525], ['channelUtilization:last'] = [0.139], diff = [0.229]
...
['iaTime'] = [1.875], ['channelUtilization:last'] = [0.370], diff = [0.002]
...
Best: {'iaTime': 1.873} -> {'channelUtilization:last': 0.367}
Elapsed time: 1.13
Note: because iaTime is declared as volatile in NED with an
exponential() distribution in the INI file, the unit format
"exponential({0}s)" wraps the numeric value so that the command-line
override preserves the distribution. Plain units like "m" or "Mbps"
are appended directly to the value.
Example 2 — WiFi error rate distance (INET). Find the distance at which 54 Mbps WiFi reaches a 30 % packet error rate. The optimizer converges to ≈ 53.2 m in about 28 evaluations:
optimize_simulation_parameters(
get_simulation_task(simulation_project=inet_project,
working_directory_filter="showcases/wireless/errorrate",
config_filter="General", run_number=0, sim_time_limit="1s"),
expected_result_names=["packetErrorRate:vector"],
expected_result_values=[0.3],
fixed_parameter_names=["bitrate"], fixed_parameter_values=[54],
fixed_parameter_assignments=["**.bitrate"], fixed_parameter_units=["Mbps"],
parameter_names=["distance"],
parameter_assignments=["*.destinationHost.mobility.initialX"],
parameter_units=["m"],
initial_values=[50], min_values=[20], max_values=[100]) ['distance'] = [50.0], ['packetErrorRate:vector'] = [0.072], diff = [0.228]
['distance'] = [52.5], ['packetErrorRate:vector'] = [0.226], diff = [0.074]
...
['distance'] = [53.19], ['packetErrorRate:vector'] = [0.300], diff = [0.000]
Best: {'distance': 53.194} -> {'packetErrorRate:vector': 0.300}
Elapsed time: 6.38
Sanitizer tests detect memory errors, undefined behavior, and other
bugs by running simulations with AddressSanitizer / UBSan instrumentation.
Uses the sanitize build mode.
run_sanitizer_tests(simulation_project=inet_project)
# Filter to a specific area with a longer time limit
run_sanitizer_tests(simulation_project=inet_project,
working_directory_filter="examples/ethernet",
cpu_time_limit="10s")Coverage reports show which lines of C++ source code are exercised by
simulations. Uses the coverage build mode and LLVM's coverage tools.
# Generate and open a coverage report in the browser
open_coverage_report(simulation_project=inet_project,
working_directory_filter="examples/ethernet",
sim_time_limit="10s")
# Just generate the report without opening it
generate_coverage_report(simulation_project=inet_project,
working_directory_filter="examples/ethernet",
sim_time_limit="10s")# Run every configured test type sequentially
run_all_tests(simulation_project=inet_project)Dispatch CI workflows on the project's GitHub repository. Requires a
personal access token in ~/.ssh/github_repo_token with repo and
workflow scopes, and the github_owner, github_repository, and
github_workflows parameters in the project's .opp file.
# Dispatch a single workflow
dispatch_workflow("fingerprint-tests.yml")
# Dispatch all configured workflows
dispatch_all_workflows()
# Target a specific project and branch
dispatch_workflow("fingerprint-tests.yml",
simulation_project=inet_project, ref="topic/my-feature")Compare simulation results between two projects or two git commits. The comparison checks stdout trajectories, fingerprint trajectories, and scalar statistical results.
# Compare two projects
results = compare_simulations(
simulation_project_1=inet_project,
simulation_project_2=inet_baseline_project,
working_directory_filter="examples/ethernet",
config_filter="General",
run_number=0)
# Compare two git commits of the same project
results = compare_simulations_between_commits(
inet_project, "HEAD~1", "HEAD",
config_filter="General",
run_number=0)
# Inspect the results
r = results.results[0]
print(r.stdout_trajectory_comparison_result) # IDENTICAL / DIVERGENT
print(r.fingerprint_trajectory_comparison_result) # IDENTICAL / DIVERGENT
print(r.statistical_comparison_result) # IDENTICAL / DIFFERENT
r.print_different_statistical_results(include_relative_errors=True)
# Interactive debugging at the divergence point
r.debug_at_fingerprint_divergence_position()
r.show_divergence_position_in_sequence_chart()Overlay builds use fuse-overlayfs to create a writable layer on top
of a read-only source tree, allowing out-of-tree builds without
modifying the original checkout.
# Projects with overlay_key in their .opp file use overlays automatically.
# Manage overlays manually:
from opp_repl.simulation.overlay import *
list_overlays() # list overlay keys under the build root
cleanup_overlays() # unmount all overlays
clear_build_root() # unmount and remove all overlay dataDistribute simulation tasks across multiple machines using Dask
(requires the cluster extra).
from opp_repl.common.cluster import SSHCluster
cluster = SSHCluster("node1", ["node1", "node2", "node3"])
cluster.start()
# Run simulations on the cluster
run_simulations(simulation_project=inet_project,
scheduler="cluster")load_opp_file("/path/to/project.opp")
load_opp_file("/path/to/workspace/*/*.opp") # glob patterns supportedclean_simulation_results(simulation_project=inet_project)
clean_simulation_results(simulation_project=inet_project,
working_directory_filter="examples/ethernet")opp_repl can expose an MCP (Model Context Protocol) server that
allows AI assistants to execute Python code in the live REPL session.
Start it with --mcp-port 9966 (disabled by default).
- Transport: Streamable HTTP (stateless), endpoint
http://127.0.0.1:{port}/mcp - Tool:
execute_python— runs arbitrary Python code in the IPython session - Resources:
file:///opp_repl/readme(project README),file:///opp_repl/packages(package list),file:///opp_repl/api/{package_name}(auto-generated API reference)
Requires the mcp extra: pip install -e ".[mcp]".
IPython's %autoreload 2 magic is enabled at REPL startup so that
edited Python source files are automatically reloaded before each
command.
At startup the REPL tries to import a Python module named after the
current OS login user (e.g. import levy). All public names from
that module are injected into the REPL namespace. This allows
per-user customization — define helper functions, set project defaults,
etc. — without modifying opp_repl itself. If no such module exists, the
import is silently skipped.
Every loaded simulation project is injected into the REPL namespace as
{name}_project (hyphens and dots replaced by underscores). For
example, inet_project, simu5g_project, aloha_project.
Call stop_execution() (or stop_execution(value)) anywhere in a
REPL script to abort the current cell without a full traceback.
See the project repository for license information.