Skip to main content

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

  1. 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.
  2. Terminate the JSON string with a newline (\n).
  3. 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.
  4. All commands are validated against an internal JSON Schema before execution.
  5. 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 the fixed_inner_diameter_mm property over the mandrel_diameter_mm parameter 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_mm and y_mm parameters 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:

  1. Send {"action": "start"} to initialize.
  2. Send {"action": "submit_global", "payload": {...}} with global parameters.
  3. Send {"action": "submit_section", "payload": {...}} to define the section parameters.
  4. Send {"action": "submit_layer", "payload": {...}} iteratively for each layer (from the inside out).
  5. Send {"action": "finish_section"} to close the current section and loop back to step 3 for the next section.
  6. 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 standard load command.

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_doe currently 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:

FieldRequiredTypeDescription
variablesYesarray (1-2 items)Continuous input variables to sweep. Each item must have name, path, min_val, and max_val.
attributeNoobjectCategorical A/B split. Must have path, val_a, and val_b.
output_metricNostringKPI column to fit the quadratic surface to. Defaults to "sec0_bending_stiffness_EI_Nm2".
output_csvNostringAbsolute path to save the full raw results as a CSV file.

Available output metrics (prefix sec{N}_ for section index N):

  • bending_stiffness_EI_Nm2
  • torsional_stiffness_GJ_Nm2
  • axial_stiffness_EA_N
  • burst_pressure_mpa
  • display_linear_density_kg_per_m
  • kink_radius_brazier
  • tensile_failure_load_N
  • torque_failure_Nm
  • crush_pressure_atm
  • brazier_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:

CodeCondition
MODEL_NOT_LOADEDload or wizard_step has not been called yet.
MISSING_PARAMETERvariables array is empty.
INTERNAL_ERRORUnhandled 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:

CodeCondition
NO_DOE_RESULTSrun_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)