cadquery-modeling · git:20260806.5752d1d · 2026-08-06 · sha256 b24f3c5cb4f4f9d7

cadquery-modeling git:20260806.5752d1dA

Immutable. This exact content never changes and is served at /api/v1/blob/b24f3c5cb4f4f9d7.

---
name: cadquery-modeling
description: "Create, edit, or debug parametric 3D CAD parts in CadQuery (Python) that export to STEP for SolidWorks. Use when the request involves CadQuery, .step/.stl export, or modelling a physical part — enclosure, bracket, PCB, motor mount, cam, gear. Also use when a STEP will not open in CAD, or geometry looks correct in STL but is invalid as a solid. Enforces verification before export and documented OCC pitfalls."
---

# CadQuery Modeling for Manufacturable CAD

This skill turns natural-language part requests into clean, verified, parametric
CadQuery code whose STEP output reliably opens in SolidWorks. It encodes hard-won
rules from real multi-part product design.

## Core philosophy

1. **Parametric first** — every dimension is a named variable at the top of the file.
2. **Verify before trusting** — a script that printed `[OK]` is NOT proof of success.
   Always check geometry validity and solid count before declaring done.
3. **Avoid OCC fragility** — prefer simple primitives + boolean operations over
   fragile chained features. See `references/occ_pitfalls.md`.
4. **One part, one file** — each part is its own `.py` producing its own STEP/STL.
   Assemblies are done in SolidWorks, not baked into a single STEP.

## Before creating anything: confirm where

Files land in whatever directory Claude Code was started in — that is the single
thing that determines whether the user finds their STEP later. Before creating a
project or the first part, **state the absolute path you are about to write to**,
and stop to confirm if it looks wrong:

- a cloud-synced path (`OneDrive`, `Dropbox`, `iCloud` — note that on Windows the
  Desktop and Documents folders usually ARE OneDrive)
- `Downloads`, a home directory root, or a system folder
- the `claude-cad` toolkit repo itself
- a path containing spaces, parentheses, or non-ASCII characters

If any of those apply, say so and suggest a clean location such as
`C:\cad_project` before writing files. Getting this wrong is silent: everything
succeeds, and the user simply can't find the output.

## The standard workflow

When the user asks for a part, follow this loop:

1. **Match the questions to how specified the request is.** Never invent a
   critical dimension — ask instead. Default to millimeters.
   - **Underspecified** (e.g. "a bracket to hold a 60 mm pipe"): don't guess, and
     don't refuse. Ask one focused batch of questions covering only what you truly
     can't proceed without — typically overall size, thickness/wall, the
     coordinate system/orientation, and any dimension that must match another part
     or a real component. Keep it short; propose sensible defaults the user can
     accept ("I'll assume 4 mm thick unless you say otherwise").
   - **Fully specified**: don't interrogate. Build it, and list any assumption you
     had to make in the final report.
   - If the user asks you to **write a spec first**, produce it as text (coordinate
     system, overall dimensions, every feature with size + position, interfaces)
     and get approval before writing code.
2. **Write the part file** following the structure in
   `references/part_file_structure.md`.
3. **Run it** and read the full terminal output, not just the last line.
4. **Verify** geometry validity, solid count, volume, and bounding box (see below).
5. **Report** the verification numbers to the user and note any assumptions made.

Read `references/occ_pitfalls.md` before writing any code that uses shell, fillet
after shell, countersinks, or lofts — the operations with a history of silent
corruption. Each pitfall now carries a **Verified behaviour** block saying what
the current kernel actually does; the one reliably reproduced silent failure is
shelling a solid whose removed face was filleted (Pitfall 4b).

## Project layout

Always use this structure so STEP files collect in one place for SolidWorks:

```
project/
├── parts/        # one .py per part
│   ├── housing.py
│   └── pcb.py
├── output/       # STEP + STL land here (git-ignored)
└── docs/
    └── assembly_guide.md
```

Resolve the output path **relative to the script file**, not the working
directory. A bare `"../output/..."` breaks the moment the script is run from the
project root instead of from `parts/` — the export silently lands one folder too
high. Always use this pattern:

```python
from pathlib import Path
OUT = Path(__file__).resolve().parent.parent / "output"
OUT.mkdir(parents=True, exist_ok=True)

cq.exporters.export(part, str(OUT / "housing.step"))
cq.exporters.export(part, str(OUT / "housing.stl"))
print(f"[OK] exported to {OUT}")
```

This works whether the user runs `py -3.11 parts/housing.py` from the project
root or `py -3.11 housing.py` from inside `parts/`. Printing the resolved path
also makes it obvious where the files went.

## Mandatory verification block

Every part file MUST verify before export — either with this inline block, or
(preferred) with the `check()` helper from `scripts/diagnose.py` shown after it.
One of the two is required; a bare `[OK]` print is never sufficient. STL is
forgiving and hides geometry errors that survive into the STEP — and CAD import
is no safety net either: SolidWorks has opened a provably invalid STEP without
warning (`references/occ_pitfalls.md`, "Do not count on CAD import to reject
bad geometry").

```python
# ===== Verification (do not skip) =====
from OCP.BRepCheck import BRepCheck_Analyzer

solid = part.val()
shape = solid.wrapped

# 1. Geometry validity — catches silent OCC corruption
analyzer = BRepCheck_Analyzer(shape)
is_valid = analyzer.IsValid()
print(f"[verify] IsValid = {is_valid}")
if not is_valid:
    raise RuntimeError("Invalid geometry — part is unusable; CAD may still open it without warning.")

# 2. Single-body check — catches stray cut/union debris
n_solids = len(solid.Solids())
print(f"[verify] solid count = {n_solids}")
if n_solids != 1:
    raise RuntimeError(f"Expected 1 solid, found {n_solids}.")

# 3. Volume — ASSERT it, don't just print it. Validity and solid count both
#    pass on a part whose hollow/cut silently did nothing; volume is the only tell.
vol = solid.Volume()
print(f"[verify] volume   = {vol:.2f} mm^3")
assert expected_lo <= vol <= expected_hi, (
    f"Volume {vol:.1f} outside expected range — a feature may have done nothing.")
print(f"[verify] bbox     = {solid.BoundingBox()}")
```

### Prefer the diagnostic helper

The block above is the minimum. For real work, use `scripts/diagnose.py`, which
does the same checks but also *classifies* what's wrong and *safely auto-repairs*
the unambiguous cases (e.g. discarding tiny offcut debris from a multibody result):

**Setup (once per project):** copy `scripts/diagnose.py` from this skill into the
project's `parts/` folder, next to the part files. Python puts a script's own
directory on the import path, so `from diagnose import check` then resolves when
running `py -3.11 parts/<name>.py`. Without this copy the import fails with
`ModuleNotFoundError: No module named 'diagnose'`. (`project_init` also keeps a
canonical copy in `claude-cad/` alongside `preflight.py`; the `parts/` copy is the
one imports resolve against — keep them in sync, and `preflight.py` warns if they
drift.)

**Prefer `export_verified()` — it does all three steps and cannot export a bad
part**, because verification raises before the write happens:

```python
from pathlib import Path
from diagnose import export_verified        # diagnose.py must be in parts/

OUT = Path(__file__).resolve().parent.parent / "output"

export_verified(part, OUT, "bottom_housing",
    expect_volume=32000,                    # +/-2% by default, or pass (lo, hi)
    expect_bbox=(94, 65, 27.2),
    inside=[(0, 0, 1)],                     # floor is solid here
    outside=[(47, -12, 10)],                # this port opening is void here
)
```

This verifies, exports STEP + STL, and writes `bottom_housing.verified.txt` beside
them — a durable record of what was checked, since terminal output vanishes when
the window closes. Use the lower-level `check()` / `assert_points()` directly only
for intermediate steps mid-build.

**Always pass `expect_volume`.** Validity and solid-count both PASS on a part
whose `.shell()` silently did nothing — the volume is the only signal that the
cavity never got made (`references/occ_pitfalls.md`, Pitfall 4b). Compute a rough
expected volume before you build, and check against it.

**Use `assert_points` for anything with a position that matters** — ports, holes,
bosses, openings on specific walls. Geometry can be valid, single-bodied, and the
right volume while a feature sits on the *wrong face*; no topological check sees
that. Sample the middle of each opening (expect outside) and the wall beside it
(expect inside).

When a part fails, **don't guess** — follow the symptom→diagnosis→fix decision tree
in `references/diagnosis.md`. Auto-repair only touches safe, unambiguous cases;
invalid topology is reported (not patched) so a real design error is never hidden.

## Verification, in SolidWorks

After import, the user should confirm in SolidWorks:

- **Mass Properties** — center of mass on expected symmetry axes (X/Y ≈ 0 for a
  symmetric part) is the fastest correctness check.
- **Principal moments of inertia** — the relative sizes confirm which axis is
  long/short, catching swapped dimensions.
- The part opens as a **solid body**, not a surface.

See `references/solidworks_checks.md` for the exact menu paths and what each
number tells you.

## Reference files

Load these as needed:

| File | When to read |
|------|--------------|
| `references/occ_pitfalls.md` | **Before** any shell, fillet, countersink, or loft. This is the most important reference. |
| `references/diagnosis.md` | When a part fails verification — the symptom→diagnosis→fix decision tree, and how to auto-repair. |
| `references/part_file_structure.md` | When writing a new part file from scratch. |
| `references/verification.md` | When a STEP won't open, or geometry looks wrong. |
| `references/solidworks_checks.md` | When validating a part inside SolidWorks. |
| `references/environment.md` | When `cadquery` or `OCP` import fails, or on first setup. |

## Scripts

| Script | Purpose |
|--------|---------|
| `scripts/diagnose.py` | **The intelligence layer.** Diagnoses a part (classifies validity / multibody / degenerate issues) and safely auto-repairs what it can. Use `from diagnose import check` inside a build, or run it on a `.step` from the CLI. |
| `scripts/preflight.py` | Project-level: runs and verifies every `parts/*.py`, then writes a committable `VERIFICATION.md` summary at the project root. Copy it into the project's `claude-cad/` folder and run `py -3.11 claude-cad/preflight.py`. |
| `scripts/verify_step.py` | Lightweight standalone check of any STEP/STL: validity, solid count, volume, bbox. |

## Hard rules (never violate)

- Never invent a critical/interface dimension. Ask instead.
- Never declare success on `[OK]` alone — only after the verification block passes.
- Never use `cskHole` on a shelled (thin-wall) face — build a cutter solid
  instead. (Portability rule: the historical failure does not reproduce on the
  current kernel — see Pitfall 1's Verified behaviour — but the cutter pattern
  is explicit, uniform across hole types, and version-proof, at zero cost.)
- Never bake a multi-part assembly into a single STEP unless the user explicitly
  wants a static snapshot; do assemblies in SolidWorks.
- Always default to millimeters and state the unit.
- Always print the absolute output directory after exporting, so the user never
  has to guess where the file went.
- Never treat `IsValid` + single-solid as sufficient. Always compare volume against
  a hand estimate — that is the only check that catches a hollow or cut that
  silently did nothing.
- For any feature whose *position* matters, verify it with point classification
  (`assert_points`), not just topology.