# OpenRocket The OpenRocket module bridges the Java-based OpenRocket simulator with the RocketSmith pipeline. It provides MCP tools for rocket design, simulation, motor database queries, and component tree generation. ## MCP Tools | Tool | Description | |------|-------------| | `openrocket_new` | Create a new `.ork` design file with a named rocket | | `openrocket_component` | CRUD operations on rocket components; supports `override_mass_kg` for post-print calibration | | `openrocket_component` (action="read") | Generate a hierarchical component tree from an `.ork` file with mm-scaled dimensions, static stability, agent annotations, and ASCII side profile; writes `gui/component_tree.json` to the project directory. Optional `out_path` overrides the output location. | | `openrocket_flight` | Assign a motor and create a simulation configuration; writes flight JSON files to `/flights/`. Optional `out_dir` overrides the output directory. | | `openrocket_database` | Query the motor and component preset databases with filters | ## Component Tree Generation `openrocket_component` (action="read") is the primary handoff between the OpenRocket agent and downstream agents (manufacturing, cadsmith). It: 1. Opens the `.ork` file via `orhelper` and the OpenRocket JAR. 2. Walks the component hierarchy, converting all dimensions from metres to millimetres. 3. Parses each component's comment field for `== agents ==` annotations (see below). 4. Computes static stability via the Barrowman method. 5. Renders an ASCII side profile of the rocket. 6. Writes `gui/component_tree.json` to the project directory (or `out_path` if provided). The output `ComponentTree` contains: ``` ComponentTree schema_version: int source_ork: str project_root: str generated_at: str (ISO 8601) rocket_name: str stages: list[Stage] name: str components: list[Component] cg, cp: QuantityField (mm) stability_cal: float max_diameter: QuantityField (mm) ``` Each `Component` carries typed `dimensions`, `mass`, `material`, `human_notes`, an optional `agent` annotation, and recursive `children`. ## Stability Calculations Static stability is computed in `stability.py` using the Barrowman method: - **CG** -- walks all components, accumulating `mass * absolute_position` to find the centre of gravity. - **CP** -- invokes OpenRocket's `BarrowmanCalculator` via JPype to compute the centre of pressure. - **Stability margin** -- `(CP - CG) / max_diameter`, reported in calibers. A value of 1.0--1.5 is nominal. The `StabilityResult` dataclass holds `cg_m`, `cp_m`, `max_diameter_m`, and `stability_cal`. ## Dimension Models All dimension models use `pintdantic` (`QuantityModel` / `QuantityField`) so values carry physical units (default: mm). A discriminated union `Dimensions` selects the correct model via the `kind` field. | Model | `kind` | Key Fields | |-------|--------|------------| | `NoseConeDimensions` | `nose_cone` | `shape`, `length`, `base_od`, `wall` | | `TubeDimensions` | `tube` | `length`, `od`, `id`, `motor_mount` | | `TransitionDimensions` | `transition` | `shape`, `length`, `fore_od`, `aft_od`, `wall` | | `FinSetDimensions` | `fin_set` | `fin_type`, `count`, `root_chord`, `tip_chord`, `span`, `sweep`, `thickness` | | `RingDimensions` | `ring` | `od`, `id`, `thickness` | | `RecoveryDimensions` | `recovery` | `diameter`, `length`, `packed_length`, `packed_diameter` | | `GenericDimensions` | `generic` | `length`, `width`, `height`, `mass` | The mapping from OpenRocket type names (e.g. `TrapezoidFinSet`) to dimension `kind` is handled by `dimension_kind()` using the `_TYPE_TO_DIMENSION_KIND` lookup table. ## Agent Annotations Component comments in the `.ork` file can contain structured agent data below an `== agents ==` delimiter. The format is: ``` Human-readable notes go here. == agents == fate: print reason: Body tube is always a standalone printed part for AM updated_by: manufacturing updated_at: 2026-04-10T12:00:00+00:00 dfam_shoulder_length_mm: 30.0 ``` Two functions in `manufacturing.models` handle this: - `parse_comment(comment)` -- splits a comment string into `(human_notes, AgentAnnotation)`. Returns `(None, None)` for empty comments. - `serialize_comment(human_notes, annotation)` -- rebuilds the comment string from parts. This format ensures agent annotations survive `.ork` regeneration -- human notes above the delimiter are preserved, and the agent section is re-parsed on each `openrocket_component` (action="read") call. ## ASCII Art Rendering `openrocket_component` (action="read") includes an ASCII side profile in its output. The rocket's external profile (nose cone, body tubes, fins, transitions) is rendered as a text-art diagram, giving a quick visual sanity check without needing a GUI. The ASCII renderer lives in `openrocket/ascii/` and produces a proportional side view based on the component dimensions extracted from the `.ork` file.