The model writes the model.
Code is the model. A SimpleCAD model is a marimo notebook โ a plain .py file and the only source of truth. Each feature is one cell, each dimension a scad.var. An agent edits text; the BRep follows, cell by cell, with a fact card after every step.
Name the edge, not its index.
Select by meaning. Agents cannot click. QL selects topology by what it is โ type, length, position โ and asserts how many it must find. The faces a fillet makes are tagged, so the next feature asks for fillet.flange_edge, not face #14.
Errors are feedback.
Verifier first. When the kernel refuses, the SDK says why in numbers: the operation, what it measured, the room it had, and how to fix it. An agent reads it, changes one value, and moves on โ no stack-trace archaeology.
Change the intent, not the geometry.
Parameters and guards. Every dimension is a parameter and every assumption is a guard. Change bolt_count and the notebook rebuilds; push the bolt circle past the rim and the guard refuses before the kernel ever sees it.
Solved, not placed.
Assemblies. Assemblies are constraints โ revolute joints, gear meshes, bearing seats โ solved strictly. Gears, bearings and fasteners come from scad.std as real parts. Sub-assemblies are notebooks too, composed with scad.use.
Simulation survives the next revision.
One source, every solver. One package exports AP242 STEP, editable FreeCAD and MJCF. Boundary faces keep their interface.* tags through Gmsh into CalculiX, so the load case finds its faces again after every change to the model.
One notebook, many parts.
Notebooks compose. scad.use runs a part notebook with its own id and parameters, so one link_bar.py becomes crank, coupler, rocker and ground. The assembly is just another notebook, and a per-cell cache makes every rerun incremental.
Design becomes design.
Describe what the part must do. Let the model write, verify and revise the CAD.