← Blog

AI agents

OpenSCAD vs Adam vs CadQuery: picking a quote-agent core

Saturday 23:14, a klant uploads a SolidWorks 2018 assembly to a 21-person print bureau in Enschede. Whose CAD layer can quote it before Monday?

Jacob Molkenboer· Founder · A Brand New Company· 25 Jan 2026· 9 min
Brass pneumatic tube junction and wooden switchboard with green patch cable and paper docket on ivory linen.

Zaterdag 23:14. The Slack channel #offertes at a 21-person print bureau in Enschede lights up: "Aanvraag #4711 — klant uploaded SLDASM. Sub-parts missing. Manual review needed." Whoever is on call now has a choice. Open SolidWorks, find the missing reference parts, regenerate the assembly, run the volume calc, and quote it before Monday. Or send "we'll get back to you Monday morning" and watch the lead go cold.

That single failure mode is the lens through which we evaluated three parametric-modeling layers for the offerte-agent we shipped for this shop: OpenSCAD, the brand-new Adam (YC W25) open-source AI CAD, and a hand-rolled CadQuery + Claude tool-use loop. The agent handles 940 STL uploads a week. Each one needs geometry analysis, an orientation decision, a support-material estimate, and a quote inside sixty seconds of upload. The parametric layer is the part that decides whether the agent actually understands the file or just measures its bounding box.

The 940-upload operating envelope

940 uploads a week averages to 134 a day, but it doesn't arrive that way. Monday between 09:00 and 13:00 is roughly 280 of them. Friday afternoon spikes when designers send "kan dit nog voor maandag?" Most uploads are STL — a closed mesh, no parametric history. A meaningful fraction (we measured 12% across a six-week sample) arrive as STEP, IGES, or native SolidWorks files, because the klant ran the export at 17:55 and shipped whatever the dialog defaulted to.

The agent has three jobs the parametric layer has to support:

  • Parse whatever the klant sent and produce a volume, bounding box, and oriented support estimate.
  • When the klant replies "kan dit 10% groter?" or "zonder het lipje aan de zijkant?", reparametrize — not rescale the mesh.
  • Persist something on our disk that, if reopened in five years, can rebuild the part.

That third one is the IP question. If the only thing you stored is the mesh the klant uploaded, you have a frozen photograph. If you stored the parametric script the agent generated to interpret it, you have a recipe. A recipe is what trade-secret protection in NL attaches to.

OpenSCAD as the script layer

OpenSCAD is the obvious zero-cost answer. It's a small, deterministic, CSG-only modeller with its own scripting language; the .scad file IS the parametric source. OpenSCAD has been around since 2010 and is genuinely free to run at 940 jobs a week. We measured roughly 0.4 seconds per simple part on a single c7i.large core, so the per-request infra cost is essentially zero.

The problems start the moment a klant uploads anything that wasn't built in OpenSCAD itself.

  • No usable STEP or IGES import. You can import("foo.stl") as a mesh, but you lose all parametric structure. At which point the .scad file is just a 5-line wrapper around a frozen mesh, and the IP-retention argument is gone.
  • No SolidWorks importer. SLDASM and SLDPRT are closed binary formats and OpenSCAD has no path to them.
  • No fillet primitive that holds up under non-trivial geometry. You can fake it with minkowski(), but the kernel chokes on anything substantial.

For the agent, OpenSCAD only works as the parametric layer if you constrain the klant to "upload an STL of a simple part." That isn't the reality of an industrial print bureau. The Saturday-night SLDASM doesn't open. End of story.

Adam, the YC W25 newcomer

Adam launched on Hacker News earlier this week as an open-source AI CAD. The pitch is natural-language-to-geometry with a real B-rep kernel underneath. We spun it up in a sandbox the day of launch and ran 50 aanvraag files through it.

What works: prompts like "make this 10% larger and remove the side tab" do the right thing on parts Adam itself generated. The output is a real solid, not a mesh, which means the source-code-retention story is at least theoretically intact.

What doesn't work yet, as of June 2026:

  • SolidWorks import is not in v0.x. STEP import is there but flaky on AP242 files with PMI annotations — which is what modern SolidWorks exports look like.
  • The "patch" pathway when something breaks is a GitHub issue against a project that's a few months old. Median time-to-fix on a CAD kernel bug at a four-month-old startup is not a number we'd bet a Saturday-night klant on.
  • Self-hosted inference cost depends on which model you wire in. Hosted endpoint puts you back on a vendor SLA.

Adam is the most interesting of the three for the next 18 months. Today it's the riskiest pick for a 21-person shop that needs the pipeline to work tonight.

CadQuery plus a Claude tool-use loop

This is the one we shipped. CadQuery is a Python library on top of OpenCascade (OCCT), the same B-rep kernel that FreeCAD uses. STEP, IGES, BREP, and (via FreeCAD-CLI as a sidecar) SolidWorks files all land in the same Python object model.

The loop, sketched:

from anthropic import Anthropic
import cadquery as cq

TOOLS = [
    {"name": "load_step", "description": "Load a STEP/STP file from disk.",
     "input_schema": {"type": "object",
                      "properties": {"path": {"type": "string"}}}},
    {"name": "bounding_box", "description": "Return XYZ extents in mm.",
     "input_schema": {"type": "object",
                      "properties": {"part_id": {"type": "string"}}}},
    {"name": "rebuild_param",
     "description": "Emit CadQuery Python recreating the part with new params.",
     "input_schema": {"type": "object", "properties": {
         "part_id": {"type": "string"},
         "params":  {"type": "object"}}}},
    # ... volume, orientation, support_estimate, etc.
]

client = Anthropic()
parts  = {}

def run_tool(name, args):
    if name == "load_step":
        parts[args["path"]] = cq.importers.importStep(args["path"])
        return {"part_id": args["path"]}
    if name == "bounding_box":
        bb = parts[args["part_id"]].val().BoundingBox()
        return {"x": bb.xlen, "y": bb.ylen, "z": bb.zlen}
    # ...

def quote(upload_path):
    msgs = [{"role": "user",
             "content": f"Quote this print job: {upload_path}"}]
    while True:
        resp = client.messages.create(
            model="claude-sonnet-4-5",
            tools=TOOLS,
            messages=msgs,
            max_tokens=2048,
        )
        if resp.stop_reason == "end_turn":
            return resp.content[-1].text
        msgs.append({"role": "assistant", "content": resp.content})
        msgs.append({"role": "user", "content": [
            {"type": "tool_result", "tool_use_id": tc.id,
             "content": str(run_tool(tc.name, tc.input))}
            for tc in resp.content if tc.type == "tool_use"
        ]})

The point of this code isn't "Claude is doing CAD." The point is that Claude is choosing which CadQuery primitive to call next, and the geometry math runs in CadQuery — deterministically, on the OCCT kernel, with no hallucination surface. The model decides "load_step then bounding_box then orientation_for_support_minimization." OCCT decides the numbers.

At our measured average of roughly 7,800 input tokens and 1,400 output tokens per aanvraag, the Claude bill works out to about $0.044 per quote at Sonnet 4.5 list pricing ($3/M input, $15/M output — check current pricing before you copy that forward). At 940 uploads a week, that's roughly $41 a week. About €1,950 a year, which a 21-person print bureau spends on koffie in a quarter.

Per-aanvraag cost, honestly

At 940 weekly uploads, the per-request token bill is the least interesting line item. Vendor risk on the Saturday-night failure mode is the line that matters. The three layers, on the metric the shop actually loses sleep over:

  • OpenSCAD: ~€0 per request. Fails on every non-STL upload. No SolidWorks path at all.
  • Adam (today): cost depends on hosted vs. local inference. STEP import partial, SolidWorks none. Patch path is GitHub.
  • CadQuery + Claude: ~€0.04 per request. STEP, IGES, BREP, and SolidWorks (via FreeCAD-CLI sidecar) all work. Patch path is editing the Python.

IP retention as a deliverable

The klant uploads a drawing. The agent quotes it. Six months later the same klant comes back and asks for the same part but in PETG, 10% larger. What did you keep?

If you kept only the STL, you can rescale, but you cannot reproduce design intent. The hole pattern doesn't move correctly, the wall thickness doesn't scale linearly, the fillets aren't fillets anymore. If you kept a CadQuery Python file, you have the recipe. That file is your IP, and it's also part of the value you're selling back to the klant: "we have your part as code, not as a mesh." Try saying that on a sales call to a customer whose lead engineer just left.

OpenSCAD gives you a .scad file but only for parts the agent built from scratch, which on real klant traffic is almost none of them. Adam gives you whatever its output format is, which today is in flux. CadQuery gives you a deterministic .py that any Python engineer can read in 2031.

The Saturday-night SLDASM, who patches it

Warning

If your offerte-agent depends on a vendor's parser to ingest SolidWorks files, your bottleneck is that vendor's bug queue. Plan accordingly.

The honest comparison: when a klant uploads a SolidWorks 2018 assembly at 23:14 on a Saturday, OpenSCAD has nothing to say. Adam files a GitHub issue. The CadQuery loop falls over at the import step with a stack trace pointing at STEPCAFControl_Reader. The difference is what happens next. With CadQuery, the operator on call greps the trace, finds that FreeCAD-CLI converted six of seven sub-parts and failed on the seventh because of an unsupported AP242 PMI extension, and patches the converter call to fall back to a flat STEP export. That patch is 12 lines of Python. With Adam, it's an issue.

This is not a knock on Adam. It's an honest accounting of vendor risk at a 21-person shop that ships quotes overnight.

What we actually built

We went with CadQuery + the Claude tool-use loop. Not because it's elegant — it's mostly glue — but because the failure-mode story holds up. STEP and IGES land natively. SolidWorks routes through a FreeCAD-CLI sidecar that we control. When a klant uploads something the loop has never seen, the operator on call edits the Python and ships, not files a ticket and waits.

When we built the offerte-agent for this print bureau in Twente, the SLDASM-on-Saturday problem broke our pipeline twice in the first month — once on a PMI annotation in AP242, once on an embedded sub-part that came over as a zero-byte placeholder. We solved both by wrapping FreeCAD-CLI as a fallback converter and routing the unconvertable five percent to a human review queue with a one-line Slack ping, which is the patch-path control you actually buy when you ship AI agents into a 24/7 inbox.

A five-minute audit you can run this week

Take one aanvraag from this week. Open the file the klant sent. Write 30 lines of CadQuery — or 30 lines of OpenSCAD, or 30 lines of an Adam prompt — that rebuild the part parametrically from scratch. Time yourself. Then ask: if your offerte-agent had to do this autonomously at 23:14 on a Saturday, would the layer you picked actually have a chance?

Key takeaway

At 940 weekly uploads the per-request token bill is noise. The line that matters is who patches the parametric layer when a klant uploads SolidWorks on a Saturday.

FAQ

Can OpenSCAD ingest SolidWorks files?

No. OpenSCAD has no SolidWorks importer and no usable STEP or IGES parser, so it only acts on parts you authored as .scad scripts or imported as plain STL meshes.

Is Adam production-ready for a print bureau today?

As of June 2026, Adam is a freshly launched YC W25 project. STEP import is partial, SolidWorks is not in v0.x, and the patch path is GitHub issues against a young codebase.

Why CadQuery instead of FreeCAD's Python API directly?

CadQuery has a fluent API designed for parametric scripting and runs on the same OCCT kernel as FreeCAD. We use FreeCAD-CLI only as a sidecar for legacy SolidWorks ingestion.

What does it cost per quote at Claude pricing?

At about 7.8k input and 1.4k output tokens per aanvraag, Sonnet 4.5 list pricing works out to roughly $0.04 per quote. About $41 a week at 940 uploads. Check current pricing before relying on the number.

Why does source-code retention matter for the klant's IP?

A mesh is a frozen photograph; a parametric script is a recipe. Trade-secret protection attaches to the recipe, and the recipe is what lets you rebuild the part in five years when the klant's engineer is gone.

ai agentsautomationcase studytoolingarchitectureintegrations

Building something?

Start a project