CLI API Documentation
The VirtuCath CLI API provides a pure, persistent REPL (Read-Eval-Print Loop) interface for interacting with the application programmatically over standard input/output (stdin/stdout). This mode is designed for full headless operations, enabling machine learning training, dataset generation, and direct interaction via AI agents or external scripts.
The API runs continuously, holding the loaded MuJoCo model and Flowdown engine state in memory between commands. It communicates exclusively using single-line JSON strings.
Starting the API
Run the application (either the python script or the compiled executable) with the --cli-api argument:
python main.py --cli-api
# OR
./VC_redist.x64.exe --cli-api
Once running, the program will silently wait for JSON commands on stdin. Logs are written to api_cli.log in the working directory to keep stdout clean.
Verbose Mode:
You can append the --verbose flag (e.g., python main.py --cli-api --verbose) to stream internal simulation engine logs directly to standard error (stderr). This is highly recommended when debugging physics divergence or command failures.
Usage Protocol
- Send a single line of valid JSON to
stdin. This can be a single command object{...}or an array of command objects[{...}, {...}]for batch execution. Note: Even when sending an array, the entire payload must be compacted onto a single string line without embedded newlines. - Terminate the JSON string with a newline (
\n). - The program processes the command and responds with a single line of JSON on
stdout, followed by a newline. If sending a batch array, it will respond with a single line of JSON per command. - All commands are validated against an internal JSON Schema before execution.
- If a command causes an error (or fails schema validation), the response will be explicitly structured to include an
"error_code"for deterministic programmatic handling.
Example Error Response (Schema Validation):
{
"status": "error",
"error_code": "SCHEMA_VALIDATION_ERROR",
"message": "Command failed validation: 'timeout_s' must be of type number",
"path": ["timeout_s"]
}
Security Note: All inputs are strictly parsed as JSON and type-casted internally. Do not use Python eval() or send arbitrary code.
API Commands
1. export_schema
Outputs a comprehensive JSON Schema defining all available commands, their expected parameters, required fields, and types. This command enables self-discoverability for zero-prompt AI agents to learn the API's constraints dynamically.
Request:
{
"command": "export_schema"
}
Response (Success):
{
"status": "success",
"schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "VirtuCath CLI API Request",
...
}
}
2. load
Loads a catheter configuration into the simulation engine and initializes the mechanics.
Request:
{
"command": "load",
"config": "C:/path/to/catheter.json"
}
Note: config can be an absolute file path, a path relative to the working directory, or a complete nested JSON object representing the configuration. Absolute paths are highly recommended.
Dimension Mode Priority Note: When passing a raw configuration JSON directly to the CLI, if
"dimension_mode": "OD_ID_FIXED"is specified within the catheter definition, the API will strictly enforce thefixed_inner_diameter_mmproperty over themandrel_diameter_mmparameter when evaluating the internal layer flowdown mechanics.
Configuration Validation Note: When a configuration is loaded, its pullwire geometric constraints are strictly validated. Specifically, the radial extent of the pullwires (
radial_offset_mm+lumen_radius_mm+liner_wall_thickness_mm) must not exceed the outer radius of the catheter section to which they are attached.
Response (Success):
{
"status": "success",
"message": "Catheter loaded successfully.",
"static_kpis": {... }
}
3. get_static_kpis
Retrieves the static mechanical properties (e.g., Critical Buckling Loads, Sectional Stiffness) of the currently loaded model. You can optionally request specific keys to minimize the payload size.
Note: If is_manual_stiffness is flagged for a section in the configuration, certain geometric KPIs derived from the cross-section (like linear_density_kg_per_m) are bypassed and will return null.
Request:
{
"command": "get_static_kpis",
"keys": ["sectional_stiffness"]
}
Note: The keys array is optional. If omitted, all static KPIs are returned.
Response (Success):
{
"status": "success",
"static_kpis": {... }
}
4. get_dynamic_kpis
Retrieves the current state of the simulation without advancing time. You can optionally request specific keys.
Request:
{
"command": "get_dynamic_kpis",
"keys": ["tip_position_mm", "physics_stable"]
}
Note: The keys array is optional. If omitted, all dynamic KPIs are returned.
Response (Success):
{
"status": "success",
"dynamic_kpis": {
"physics_stable": true,
"tip_position_mm": [4.9, 0.0, -120.5]
}
}
Note: The physics_stable flag allows agents to immediately recognize if the latest parameters caused the simulation to diverge (e.g., NaN velocities).
5. set_environment
Enables or disables gravity along a specific axis (x, -x, y, -y, z, -z).
Request:
{
"command": "set_environment",
"gravity_enabled": true,
"gravity_axis": "-z"
}
Response (Success):
{
"status": "success",
"message": "Gravity set to enabled along axis '-z'"
}
6. reset_simulation
Instantly resets the MuJoCo simulation state to neutral/zero-deflection and flushes accumulated kinematics without needing to reload the entire model config from disk. Extremely useful for rapidly starting a new sequence in bounded optimization loops.
Request:
{
"command": "reset_simulation"
}
Response (Success):
{
"status": "success",
"message": "Simulation reset successfully.",
"dynamic_kpis": {... }
}
7. step_simulation
Advances the physics simulation by a precise duration. Useful for algorithmic agents that need to observe continuous motion. Optionally accepts target X/Y deflections to update before stepping.
Request:
{
"command": "step_simulation",
"duration_s": 0.01,
"x_mm": 5.0,
"y_mm": 0.0
}
Note: x_mm and y_mm are optional. If omitted, the simulation will step towards the last known target.
Response (Success):
{
"status": "success",
"message": "Stepped 0.01s.",
"dynamic_kpis": {... }
}
8. render_simulation
Captures a static frame of the current MuJoCo simulation state headlessly.
Request:
{
"command": "render_simulation",
"view": "custom",
"azimuth": 45.0,
"elevation": -30.0,
"distance": 0.5,
"lookat": [0.0, 0.0, -0.2],
"width": 800,
"height": 600,
"output_path": "C:/path/to/save/simulation_frame.png"
}
Note: view can be iso, front, side, top, or custom. If custom, you must specify azimuth, elevation, and distance. lookat is optional. Defaults to 800x600. Absolute paths are highly recommended for output_path.
Response (Success):
{
"status": "success",
"message": "Simulation rendered to /path/to/save/simulation_frame.png"
}
9. set_pullwires
Dynamically actuates the pullwires to achieve a specific spatial deflection at the catheter tip and steps the physics simulation until the tip settles (velocity drops below a threshold) or times out. Returns the dynamic KPIs of the settled state.
API Ambiguity Note: The
x_mmandy_mmparameters refer to the target spatial position (deflection amplitude) of the distal tip in the simulation world, not the linear displacement (length) of the tendon pulled.
Note on Deflection Modeling: Catheters are modeled as cantilevers rigidly fixed at the base. Therefore, if you are designing and simulating a deflectable distal section, it is highly recommended to model the proximal shaft as a rigid, minimal-length stand-in (e.g., 50-100 mm) rather than its full anatomical length. This significantly improves simulation stability and focus.
Request:
{
"command": "set_pullwires",
"x_mm": 5.0,
"y_mm": 0.0,
"timeout_s": 15.0
}
Note: timeout_s is optional and defaults to 10.0 seconds of simulation time.
Response (Success):
{
"status": "success",
"message": "Pullwires set and simulation settled.",
"dynamic_kpis": {
"is_settled": true,
"tip_position_mm": [4.9, 0.0, -120.5],
"tendon_forces_N": { "0": 1.2, "1": 0.0,... },
...
}
}
10. calculate_flowdown
Interacts with the Flowdown Engine to iteratively calculate pre-reflow and post-reflow stackup dimensions.
Important Conceptual Note: The flowdown calculator is a secondary, manufacturing-focused tool. It is designed to be used after the catheter geometry is modeled and simulated to determine what raw, pre-reflow extrusions to procure in order to achieve the desired final design. It is not strictly required for the physics simulation itself, which runs off the final composite stackup.
This command allows AI agents to optimize designs by passing in manual layer overrides (e.g., fixed wall thicknesses or inner diameters).
Request:
{
"command": "calculate_flowdown",
"section_index": 0,
"layer_overrides": {
"0": { "is_manual": true, "fixed_wall_mm": 0.05 },
"1": { "is_manual": false, "gap_below_mm": 0.2 }
}
}
Note: section_index defaults to 0. layer_overrides uses the layer index as the key. Available override properties are is_manual, fixed_wall_mm, fixed_id_mm, gap_below_mm, and gap_above_mm. To change the base mandrel size, set mandrel_diameter_mm in the top-level catheter_definition of your loaded configuration. By default, polymer layers have a 0.15mm radial pre-reflow gap below them to simulate loose fitment prior to reflow which affects final OD if not actively accounted for. Override gap_below_mm to 0.0 to enforce a strict flush fit.
Response (Success):
{
"status": "success",
"stackup": [
{
"name": "Mandrel",
"pre_od_mm": 1.5,
...
},
...
]
}
11. generate_graphics
Headlessly generates 3D renderings of the catheter components (such as Braid/Coil technical illustrations and Peelaway diagrams) and saves them as images to the specified directory. This allows AI agents to retrieve visual feedback without a GUI.
Request:
{
"command": "generate_graphics",
"output_dir": "/path/to/save/images"
}
Note: The model must be loaded first. The directory will be created if it does not exist.
Response (Success):
{
"status": "success",
"message": "Graphics generated successfully.",
"saved_files": [
"/path/to/save/images/braid_render.png",
"/path/to/save/images/peelaway_render.png"
]
}
12. get_materials
Retrieves the full list of materials available in the local material library.
Request:
{
"command": "get_materials"
}
Response (Success):
{
"status": "success",
"materials": [
{
"name": "SS 304V",
"material_family": "Metal",
"thermoplastic": false,
"density_g_cm3": 8.0,
...
},
...
]
}
13. add_temporary_material
Adds a custom material to the library in-memory only for the duration of the API session. This material can then be referenced by name in subsequent calculate_flowdown or load commands without permanently altering the user's materials.json file.
Request:
{
"command": "add_temporary_material",
"material": {
"name": "Custom Agent Polymer",
"material_family": "PEBA",
"thermoplastic": true,
"density_g_cm3": 1.05,
"modulus_of_elasticity_mpa": 150.0,
"tensile_strength_mpa": 45.0,
"poissons_ratio": 0.45
}
}
Response (Success):
{
"status": "success",
"message": "Temporary material 'Custom Agent Polymer' added to memory.",
"material": {... }
}
14. get_license_info
Retrieves read-only information about the active application license, including Hardware ID, expiration status, and license type.
Request:
{
"command": "get_license_info"
}
Response (Success):
{
"status": "success",
"license_info": {
"type": "Team License (1 Year)",
"status": "Active",
"expires_at": "2027-10-31",
"days_remaining": "365 days",
"hwid": "UUID:12345678-ABCD-...",
"key_masked": "00000000-XX1234"
}
}
15. generate_reports
Headlessly generates structured reports (e.g., JSON summaries, PDFs, Excel/CSV logs depending on implementation) for the currently loaded configuration and saves them to the specified directory.
Request:
{
"command": "generate_reports",
"output_dir": "/path/to/save/reports"
}
Note: The model must be loaded first. The directory will be created if it does not exist.
Response (Success):
{
"status": "success",
"message": "Reports generated successfully.",
"saved_files": [
"/path/to/save/reports/catheter_report.json"
]
}
16. validate_config
Performs pre-flight validation checks on a configuration without loading it into the physics engine. Useful for verifying geometric constraints like ensuring layer stackups do not exceed the specified overall outer diameter.
Request:
{
"command": "validate_config",
"config": "C:/path/to/catheter.json"
}
Response (Success):
{
"status": "success",
"valid": false,
"message": "Configuration loaded but has validation warnings.",
"warnings": [
"Section '1': Sum of layer thicknesses (5.200 mm) exceeds overall_diameter_mm (4.000 mm)."
]
}
17. calculate_kink_safety
Calculates the safety factor against kinking (Brazier failure) for each flexible section given a target bend radius in millimeters for the currently loaded configuration.
Request:
{
"command": "calculate_kink_safety",
"radius_mm": 15.0
}
Response (Success):
{
"status": "success",
"message": "Calculated kink safety factors.",
"target_radius_mm": 15.0,
"overall_safe": true,
"safety_factors": {
"1": 3.25,
"2": null,
"3": 1.15
}
}
18. get_config
Retrieves the full JSON configuration object currently loaded in the simulation engine. This allows an AI agent to inspect the current state (or a default load), tweak specific parameters (like a layer thickness or pullwire offset), and re-issue a load command without having to reconstruct the entire document from scratch.
Request:
{
"command": "get_config"
}
Response (Success):
{
"status": "success",
"config": {
"schema_version": "3.0.0",
"catheter_definition": {
"name": "MyCatheter",
...
}
}
}
19. wizard_step
Guides an AI agent through building a new catheter configuration step-by-step, mimicking the UI's Setup Wizard. It manages an internal state machine (Global Setup -> Section Setup -> Layer Setup -> Review). It performs real-time validation at each step (e.g., rejecting a layer if it causes the flowdown OD to exceed the global OD constraint).
Workflow:
- Send
{"action": "start"}to initialize. - Send
{"action": "submit_global", "payload": {...}}with global parameters. - Send
{"action": "submit_section", "payload": {...}}to define the section parameters. - Send
{"action": "submit_layer", "payload": {...}}iteratively for each layer (from the inside out). - Send
{"action": "finish_section"}to close the current section and loop back to step 3 for the next section. - Send
{"action": "finish_wizard"}. This automatically hydrates the built configuration, calculates KPIs, loads it into the simulation engine, and returns the full"static_kpis"just like a standardloadcommand.
Request (Example Layer Submission):
{
"command": "wizard_step",
"action": "submit_layer",
"payload": {
"name": "Braid Layer",
"material_name": "PEBAX 35D",
"reinforcement_type": "Braid",
"thickness_mm": 0.1,
"reinforcement_settings": {
"ppi": 80,
"num_carriers": 16,
"wire_shape": "Round",
"wire_material_name": "SS 304V",
"round_wire_diameter_mm": 0.05
}
}
}
Response (Example Validation Error):
{
"status": "error",
"message": "Layer rejected. Predicted Flowdown OD (4.150mm) exceeds global target (4.000mm)."
}
DOE / Response Surface Commands
The following two commands expose the Response Surface Analysis Module programmatically. A catheter configuration must be loaded first (via load or wizard_step) before calling these commands.
20. run_doe
Runs a headless Design of Experiments (DOE) sweep over one or two continuous design parameters (with an optional A/B categorical split attribute). For each design point, the static KPIs are recalculated from scratch using the composite mechanics models and the results are aggregated into a response surface. A quadratic polynomial is then fitted to the specified output metric so you can query predicted values at arbitrary input combinations.
Design Matrix:
- 1 variable: 5-point linear sweep (min, 25%, mid, 75%, max).
- 2 variables: 3-level full factorial (9 runs - the 3x3 Face-Centered CCD equivalent).
- Attribute (A/B): The entire continuous DOE is duplicated for each attribute value, doubling the run count.
Path Specification: Variables and attributes reference a location inside the config using a JSON path array. Each element is either a string key or an integer array index. The path must resolve to a leaf value in the active catheter configuration. Use get_config first to inspect the structure if needed.
Note:
run_doecurrently supports static KPI sweeps only (no live MuJoCo dynamic simulation per run). If you need dynamic simulation data across design points, use the GUI's Response Surface Analysis Module.
Request:
{
"command": "run_doe",
"variables": [
{
"name": "Wall Thickness",
"path": ["catheter_definition", "sections", 0, "layers", 0, "thickness_mm"],
"min_val": 0.1,
"max_val": 0.5
},
{
"name": "Braid PPI",
"path": ["catheter_definition", "sections", 0, "layers", 1, "reinforcement_settings", "ppi"],
"min_val": 40,
"max_val": 120
}
],
"attribute": {
"path": ["catheter_definition", "sections", 0, "layers", 1, "reinforcement_settings", "wire_material_name"],
"val_a": "SS 304V",
"val_b": "MP35N"
},
"output_metric": "sec0_bending_stiffness_EI_Nm2",
"output_csv": "C:/path/to/results/doe_sweep.csv"
}
Parameters:
| Field | Required | Type | Description |
|---|---|---|---|
variables | Yes | array (1-2 items) | Continuous input variables to sweep. Each item must have name, path, min_val, and max_val. |
attribute | No | object | Categorical A/B split. Must have path, val_a, and val_b. |
output_metric | No | string | KPI column to fit the quadratic surface to. Defaults to "sec0_bending_stiffness_EI_Nm2". |
output_csv | No | string | Absolute path to save the full raw results as a CSV file. |
Available output metrics (prefix sec{N}_ for section index N):
bending_stiffness_EI_Nm2torsional_stiffness_GJ_Nm2axial_stiffness_EA_Nburst_pressure_mpadisplay_linear_density_kg_per_mkink_radius_braziertensile_failure_load_Ntorque_failure_Nmcrush_pressure_atmbrazier_critical_moment_Nm
Response (Success):
{
"status": "success",
"message": "DOE complete: 18 runs, metric='sec0_bending_stiffness_EI_Nm2'.",
"total_runs": 18,
"output_metric": "sec0_bending_stiffness_EI_Nm2",
"runs_summary": [
{
"run": 1,
"x1": 0.1,
"x2": 40,
"attr": "SS 304V",
"sec0_bending_stiffness_EI_Nm2": 0.000412,
"error": null
}
],
"surface_model": {
"fitted": true,
"r2_score": 0.9987,
"predictions": {
"x1": [0.1, 0.144, "..."],
"x2": [40, 48.9, "..."],
"z": [[0.000412, "..."], "..."]
}
},
"output_csv": "C:/path/to/results/doe_sweep.csv"
}
Error Codes:
| Code | Condition |
|---|---|
MODEL_NOT_LOADED | load or wizard_step has not been called yet. |
MISSING_PARAMETER | variables array is empty. |
INTERNAL_ERROR | Unhandled exception during the sweep. |
21. get_doe_results
Returns the raw per-run data table from the most recent run_doe call. This is useful to retrieve the full result set (including all KPI columns, not just the surface-fitted metric) without repeating the sweep. Results are cached in memory until the next run_doe call.
Optionally, you can filter the returned columns to reduce payload size.
Request:
{
"command": "get_doe_results",
"columns": ["x1", "x2", "sec0_bending_stiffness_EI_Nm2", "sec0_kink_radius_brazier"]
}
Note: columns is optional. If omitted, all columns are returned.
Response (Success):
{
"status": "success",
"last_metric": "sec0_bending_stiffness_EI_Nm2",
"total_runs": 18,
"columns": ["x1", "x2", "sec0_bending_stiffness_EI_Nm2", "sec0_kink_radius_brazier"],
"rows": [
{
"x1": 0.1,
"x2": 40,
"sec0_bending_stiffness_EI_Nm2": 0.000412,
"sec0_kink_radius_brazier": 8.3
}
]
}
Error Codes:
| Code | Condition |
|---|---|
NO_DOE_RESULTS | run_doe has not been called in this session. |
22. exit or quit
Safely stops the simulation engine, deallocates memory, and closes the application.
Request:
{
"command": "exit"
}
Response (Success):
{
"status": "success",
"message": "Exiting CLI API."
}
(The program will then terminate)