How the cadgen Package Handles Model Execution in Text-to-CAD

The cadgen package executes CAD models by transforming Python functions decorated with @step, @dxf, or mesh decorators into a reproducible build pipeline that discovers source definitions, selects generation targets, and submits jobs to either a warm daemon or transient subprocess backend.

When working with the earthtojake/text-to-cad repository, understanding how the cadgen package handles model execution is essential for optimizing build performance and debugging generation workflows. The execution flow begins when you run python model.py and triggers a sophisticated orchestration system involving argument parsing, source discovery, and event-driven backend processing.

The Model Execution Pipeline

The cadgen package implements a multi-stage pipeline that transforms a simple script execution into a deterministic CAD build process.

Entry Point and Argument Parsing

Execution begins in cadgen.authoring, which calls the internal runner cadgen.cli._run_model.run_model_argv. This function builds an argument parser via _build_parser that recognizes flags including --model, --force, --json, and mesh tolerance parameters.

In cli/_run_model.py, the parser processes command-line arguments and normalizes mesh-related values using cadgen.metadata.normalize_mesh_numeric (lines 73-77). These normalized values feed into StepImportOptions used during generation.

Model Discovery and Target Resolution

The catalog.source_from_path function (defined in catalog.py line 71) reads the target script and extracts the decorated function, creating a Source object that describes the model's artifacts. If the source defines only a DXF export (source.dxf_path set with empty source.step_path), the pipeline selects the DXF generation route; otherwise, it defaults to the full STEP pipeline (see _run_model.py lines 91-100).

Generation and Caching

The public façade functions generate_step_targets and generate_dxf_targets (exposed in generation.py) drive the actual build process. These functions consult the internal store cache to skip up-to-date work when force=False, handle mesh-resolution parameters, and manage incremental file writes. The generation engine lives in cadgen._internal.generation and coordinates the entire artifact creation process.

Execution Backends: Daemon vs. Transient Mode

The cadgen package supports two distinct execution strategies selected by cadgen.daemon.executors.submit.

Daemon Mode (Default)

By default, execution requests route through cadgen.daemon.executors.submit to a long-running warm daemon. The daemon client (daemon/client.py) forwards jobs to worker threads managed by daemon/server.py, maintaining state between builds for faster subsequent executions. This mode provides real-time event streaming and is ideal for iterative development.

Transient Mode

When CADGEN_DAEMON=0 is set or the platform cannot support the daemon, the executor spawns a short-lived subprocess. Despite the different runtime characteristics, both backends use identical pipeline code, guaranteeing deterministic artifacts regardless of execution mode. You can verify the backend selection through environment variables or platform capability detection in daemon/executors.py line 62.

Event-Driven Build Reporting

During execution, the system emits model_event events via executors.emit_event (line 106) to provide real-time progress updates. These events flow to either a UI tree renderer for interactive sessions or a line-based sink for transient workers. The event stream includes submitted, running, succeeded, and failed states, enabling hierarchical build-tree visualization in CAD Viewer interfaces.

When the --json flag is present, the CLI outputs structured JSON lines; otherwise, it prints human-readable summaries. Error handling occurs through cadgen._internal.cli_errors.report_cli_error, which catches exceptions and presents clean error messages rather than raw tracebacks (see _run_model.py lines 118-122).

Practical Code Examples

Running a Simple STEP Model


# model.py

from cadgen import step, box

@step
def model():
    # Build a 10 mm cube

    return box(10)

Execute the model:

$ python model.py

This triggers cadgen.authoring, which resolves to generate_step_targets([ "model.py" ]).

Selecting Specific Models in Multi-Definition Files


# multi.py

from cadgen import step, cylinder

@step
def small():
    return cylinder(radius=5, height=20)

@step
def large():
    return cylinder(radius=10, height=40)

Target a specific function:

$ python multi.py --model large

The CLI constructs the target string "multi.py::large" and passes it to the generation engine.

Forcing Rebuilds with Custom Mesh Tolerances

$ python model.py --force --mesh-tolerance 0.01 --mesh-angular-tolerance 0.5

These parameters are normalized and injected into StepImportOptions for the generation backend.

Explicit Daemon Management


# Start the warm daemon (once per session)

$ cadgen daemon start

# Submit a model to the daemon

$ python model.py

The executors.submit function creates a Job instance and forwards the request through the daemon client, with the worker thread handling the actual build and event emission.

Core Architecture Components

The execution flow relies on specific modules within the cadgen package:

  • cli/_run_model.py – Internal runner handling argument parsing, model resolution, and pipeline invocation.
  • generation.py – Public façade exposing generate_step_targets and generate_dxf_targets to orchestration tools.
  • daemon/executors.py – Decision logic for backend selection (daemon vs. transient), job submission, and event emission.
  • daemon/client.py and daemon/server.py – Communication layer managing the warm daemon's job queues and worker threads.
  • authoring.py – Entry point module referenced by model scripts' __main__ blocks.
  • catalog.py and metadata.py – Source resolution and mesh parameter normalization.
  • store/index.py – Persistent index mapping script::function references to stable model IDs and tracking closure states.

Summary

  • The cadgen package transforms decorated Python functions into executable CAD models through cadgen.cli._run_model.run_model_argv.
  • Model discovery uses catalog.source_from_path to resolve script paths into Source objects describing STEP or DXF targets.
  • Generation occurs through generate_step_targets or generate_dxf_targets in generation.py, with built-in caching for incremental builds.
  • Execution modes include a warm daemon (default) for performance or transient subprocesses when CADGEN_DAEMON=0 is set, both handled by daemon/executors.py.
  • Real-time progress reporting uses event emission (model_event) to support both CLI JSON output and interactive UI tree rendering.
  • Error handling routes through report_cli_error to provide user-friendly diagnostics instead of stack traces.

Frequently Asked Questions

What triggers the cadgen model execution pipeline?

Running a Python script containing cadgen decorators (@step, @dxf, @stl, etc.) triggers the pipeline through the script's __main__ block, which imports cadgen.authoring. This module forwards execution to cadgen.cli._run_model.run_model_argv, initiating argument parsing and model discovery.

How does cadgen choose between daemon and transient execution?

The cadgen.daemon.executors.submit function checks the CADGEN_DAEMON environment variable and platform capabilities. If the daemon is available and enabled (default), jobs route to the warm daemon via daemon/client.py. If CADGEN_DAEMON=0 or the platform lacks daemon support, the system spawns a transient subprocess.

Can I force a rebuild without clearing the entire cache?

Yes. Pass the --force flag when running your model script. This bypasses the cache check in generate_step_targets, forcing the generation engine to rebuild artifacts regardless of existing cached states.

How does cadgen handle errors during model generation?

Errors are caught and processed by cadgen._internal.cli_errors.report_cli_error, which formats exceptions into clean, user-readable messages. This prevents raw Python tracebacks from cluttering the CLI output while preserving diagnostic information for debugging.

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 →