How to Add New Export Formats to the CAD Skill in text-to-cad: A Complete 8-Step Workflow

Adding a new export format to the CAD skill requires implementing an exporter function in the cadpy package, extending the StepImportOptions data class, exposing the format through the CLI in scripts/step/cli.py, and wiring the exporter into the generation orchestration in generation.py.

The earthtojake/text-to-cad repository generates primary STEP files alongside optional side-car mesh formats like STL, 3MF, and GLB. When extending the system to support additional formats such as OBJ or PLY, developers must follow a predictable four-layer pipeline that ensures consistent CLI exposure, generation orchestration, and documentation. Mastering this workflow for adding new export formats to the CAD skill enables clean integration with the existing side-car processing loop.

Core Implementation

Step 1: Create the Exporter Function

Create a new module under skills/cad/scripts/packages/cadpy/src/cadpy/ (for example, obj.py). The function signature must mirror the existing exporters like stl.py:

from pathlib import Path
from cadpy.types import LoadedStepScene

def export_part_obj_from_scene(
    step_path: Path,
    scene: LoadedStepScene,
    *,
    target_path: Path | None = None,
) -> Path:
    """Export the supplied `scene` as an OBJ file.

    * `step_path` – the original STEP file (used for error messages).
    * `scene` – the fully-loaded step scene produced by `load_step_scene`.
    * `target_path` – optional explicit output location; if omitted a path is
      derived from the STEP file name.
    """
    # Use a geometry library (e.g., trimesh, pywavefront) to write OBJ

    return target_path

The STL exporter at skills/cad/scripts/packages/cadpy/src/cadpy/stl.py serves as the reference implementation for error handling and path derivation logic.

Step 2: Extend the Configuration Data Class

The StepImportOptions dataclass in skills/cad/scripts/packages/cadpy/src/cadpy/catalog.py carries side-car flags from the CLI to the generation engine. Add a new field for your format:

from dataclasses import dataclass
from typing import Optional

@dataclass
class StepImportOptions:
    stl: Optional[str] = None
    three_mf: Optional[str] = None
    glb: Optional[str] = None
    obj: Optional[str] = None          # ← NEW FIELD

    mesh_tolerance: Optional[float] = None
    mesh_angular_tolerance: Optional[float] = None

This dataclass acts as the configuration contract between the CLI layer and the generation pipeline.

Interface Integration

Step 3: Add CLI Arguments

Edit skills/cad/scripts/step/cli.py to expose the new option. Existing STL, 3MF, and GLB flags are defined around lines 48-62:

parser.add_argument(
    "--obj",
    metavar="OUTPUT",
    help="Export an OBJ side-car to this relative .obj path.",
)

Update the _step_import_options_from_args function to populate the field:

return StepImportOptions(
    stl=args.stl,
    three_mf=args.three_mf,
    glb=args.glb,
    obj=args.obj,          # ← NEW

    mesh_tolerance=args.mesh_tolerance,
    mesh_angular_tolerance=args.mesh_angular_tolerance,
)

Step 4: Wire into the Generation Pipeline

Inside skills/cad/scripts/packages/cadpy/src/cadpy/generation.py, the generate_step_targets function builds a list of _ArtifactJob instances. Locate the side-car handling block around lines 1700-1800 and add your exporter:

if spec.obj_path:
    jobs.append(_ArtifactJob(
        name="OBJ",
        func=lambda s=spec, sc=scene: export_part_obj_from_scene(
            s.step_path, sc, target_path=Path(s.obj_path)
        ),
    ))

The lambda closure captures the spec and scene variables to ensure the exporter receives the correct paths when executed.

Documentation and Quality Assurance

Step 5: Update Export References

Document the new format in skills/cad/references/supported-exports.md:


## OBJ

Export a Wavefront OBJ file. Useful for downstream tools that require explicit vertex/face listings.

The CLI flag added in Step 3 automatically appears in the generated --help output.

Step 6: Add Automated Tests

Create a test case under tests/python/skills/cad/ following the pattern of existing format tests:

  1. Run scripts/step with --obj on a minimal sample model.
  2. Assert the file is created with the expected .obj suffix.
  3. Validate the output contains proper OBJ syntax (vertex and face definitions).

Name the file test_step_obj.py to maintain consistency with test_step_stl.py.

Validation and Deployment

Step 7: Verify End-to-End

Run the complete generation workflow locally:

python scripts/step path/to/sample_model.py --obj meshes/sample.obj --verbose

Confirm that:

  • The primary STEP file is produced.
  • The OBJ side-car appears next to the STEP file.
  • scripts/inspect operates on the STEP file without interference from the side-car.

Step 8: Continuous Integration Validation

Execute the CI test suite via scripts/test/test.sh to ensure the new Python tests pass and no regressions occur in existing STL, 3MF, or GLB export paths. The test matrix automatically validates all configured export formats.

Summary

Frequently Asked Questions

What is the minimum code required to add a basic export format?

You must modify four files: create an exporter module in cadpy/, add a field to StepImportOptions in catalog.py, add a flag in step/cli.py, and append an _ArtifactJob in generation.py. No changes are required to the core STEP generation logic, as side-car exports run after the primary CAD file creation.

How does the _ArtifactJob pattern handle multiple simultaneous exports?

The generate_step_targets function appends each requested format to a jobs list as separate _ArtifactJob instances. These execute sequentially after the primary STEP generation, allowing users to request STL, 3MF, GLB, and your new format in a single command without interference between exporters.

Where should mesh tolerance settings be configured for new formats?

Mesh tolerances are stored in StepImportOptions alongside format-specific paths. Your exporter function receives the scene object already loaded, but should respect mesh_tolerance and mesh_angular_tolerance if performing additional tessellation. Access these values via the spec object passed to your lambda in the _ArtifactJob definition.

How do I ensure backward compatibility when adding CLI flags?

Use Optional[str] type hints with None defaults in both the CLI argument parser and the StepImportOptions dataclass. This ensures existing scripts that do not specify the new flag continue to function without raising AttributeError or KeyError exceptions during option parsing.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →