- Les motifs rectangulaire et circulaire prennent bodies et nomment leurs copies source (2), (3)…, en sautant les noms pris - Motif de features : nouveau BodyN, comme le miroir ; noms lus dans created_bodies - Miroir d'une copie : suffixe ajouté ; body.rename pour des noms stables ; renvoi à #8194 Co-authored-by: P'tite Tête <asso@ptitetete.com>
15 KiB
SolidCraft command reference for agents
These are the shapes of the commands a part build needs, so an agent rarely has to call list_commands. The worked example at the end runs in CI (skill_reference_example_builds_as_documented in crates/mcp/src/tests.rs).
- Lengths are in mm.
- Lengths take a unit suffix, in parameters and in feature fields:
"16 in"is 406.4 mm, andlength:"1 in"works insolid.box.measurestill reports mm. - Angles inside expressions take units:
"30 deg". - Any numeric field can be an expression that names parameters:
"w/2 - wall - 6".
Sketch planes: where sketch (x, y) lands in the world
plane |
sketch x | sketch y | normal (+distance) |
|---|---|---|---|
"XY" |
+X | +Y | +Z |
"XZ" |
+X | -Z | +Y |
"YZ" |
+Y | +Z | +X |
{origin, x_dir, y_dir} |
x_dir | y_dir | x_dir x y_dir |
offset: "expr"onsketch.createmoves the plane along its normal and follows parameters.- Front wall (-Y) of a part centred on the origin:
- Sketch on
{"plane":"XZ","offset":"-d/2"}. - Draw a feature at height z at sketch y = -z.
- A cut with a positive distance goes into the wall.
- Sketch on
- Top face: sketch on
{"plane":"XY","offset":"h"}. - Hole direction:
solid.hole {sketch}drills into the part from the face nearest the sketch. A hole sketch at z=0, or below the part, drills up into the bottom face. Put the sketch on the face the hole starts from.
Ids
- Numbering: every creator returns
created: {points, curves, constraints, dimensions}. Ids are stable and numbered per sketch. - Curves:
l1,c1,a1. - Points:
p1,l1.start,l1.end,c1.center,a1.center, and the sketch origin"origin". - Rectangles:
sketch.rectangle.*also returnssides {bottom,right,top,left}andcorners {bottom_left,...}.rectangle.centeradds 2 construction diagonals, so each corner joins 3 lines. Its centre point isp5.sketch.fillet {point}therefore fails on its corners. Use{a:"l1", b:"l4", radius}or the 3Dsolid.fillet.
- Slots:
sketch.slot.overallandsketch.slot.center_to_centercreate 2 lines, 2 arcs and 4 points, plusa1.centeranda2.center. The ids count on from what the sketch already has: in an empty sketchl1, a1, l2, a2andp1-p4, after arectangle.two_pointl5, a1, l6, a2andp5-p8.- The
lengthrole ofslot.overallis the overall length. The arc centres are at ±(length/2 - width/2). - After
lengthandwidth, 3 dof remain. To remove them, dimensionorigintoa1.centerhorizontally and vertically, andorigintoa2.centervertically. For a slot along Y the solver refuses that last dimension as over-constraining; dimensiona2.centerhorizontally instead. sketch.slot.center_pointcreates no centre point. Dimension an arc centre instead.
- The
- Circles:
sketch.circle.centercreatesc1andc1.center, and noppoint. - Dimensions share the
kcounter with constraints. - Constraints can add curves: a constraint about an axis, such as
sketch.constraint.symmetrywithline:"y", adds a construction line and so takes the nextlid. Readcreatedbefore you count further. - Over-constraining is refused with
that conflicts with the sketch: neither entity can move to satisfy it. For example, symmetry already makes two circles equal.
Dimensions
{"command":"sketch.dimension","params":{"entities":["origin","c1.center"],"type":"horizontal","value":"w/2 - wall - 6"}}
{"command":"sketch.dimension","params":{"entities":["c1"],"type":"diameter","value":"6"}}
{"command":"sketch.dimension","params":{"entities":["l1"],"value":"w"}}
{"command":"sketch.dimension","params":{"entities":["l1","c1"],"value":"2"}}
{"command":"sketch.dimension","params":{"entities":["c1","c2"],"value":"3"}}
A line, a point or another circle with a circle or arc measures to its edge (0 is tangent, or the point on the circle); two circles measure between their edges (the overlap when they cross, the thinnest wall when one is inside the other). Give the centre point (c1.center) for the distance to the centre.
Distances are unsigned. Draw the geometry on the correct side first, and the dimension keeps it there.
sketch.draw.dimensioned creates a shape and its dimensions in one undo step. The dimension roles depend on the creator:
| Creator | Roles |
|---|---|
line (exactly 2 points) |
length, angle |
rectangle.* |
width, height |
circle.* |
radius or diameter |
arc.center_point |
radius, sweep |
slot.center_to_center, slot.overall |
length, width |
polygon.* |
radius |
{"command":"sketch.draw.dimensioned","params":{"command":"sketch.rectangle.center","params":{"center":[0,0],"corner":[35,25]},"dimensions":{"width":"w","height":"d"}}}
Features
| Command | Minimal params | Traps |
|---|---|---|
solid.extrude |
distance |
profiles defaults to every region, with a region inside another as a hole in it: two concentric circles give a ring. Pick regions with [{"point":[x,y]}] or [index]. Other options: operation (new/join/cut/intersect/auto), direction (positive/negative/symmetric), through_all: true, start_offset. A cut that misses reports success. |
solid.box |
length, width, height |
center:[x,y,z] or corner. The quickest way to block out a part. body_name names the body it makes. With operation:"cut", targets:["Top"] cuts only the bodies listed, so the cutter can pass through other bodies. |
solid.cylinder |
radius or diameter, height |
base is the centre of the bottom (default origin), axis defaults to Z. Expressions work in base. To tie a cylinder standing on a flat face to the part, give base as numbers on that face and add references: [{edge:[x,y,z], distance}] (up to two straight edges of the face, as for solid.hole): the base centre then sits at those distances from the edges and follows them. Always pass operation. body_name and targets work as for solid.box. |
sketch.slot.overall / sketch.slot.center_to_center |
p0, p1 (overall ends / arc centres), width |
Ids and dof are in the "Ids" section above. |
solid.fillet / solid.chamfer |
edges:[[x,y,z]], radius / distance |
The pick snaps to the nearest edge. A pick farther than 5% of the body's size from every edge is refused, so check that the face count changed. One pick takes the whole tangent chain: a rounded rim needs 1 point, not 8. |
solid.shell |
faces:[[x,y,z]], thickness |
A point on each face to remove, or its name from body_topology. Fillet first, except an edge of a removed face or a fillet between curved faces (see Order in SKILL.md). Bodies with lofted or swept faces are refused (offset: only bodies with planes, cylinders, cones, spheres and tori): hollow a loft with a smaller loft and operation: cut. |
solid.hole |
position:[x,y,z] on a face (numbers or length expressions such as ["40", "width/2", "t"], which the hole then follows) + diameter, or sketch (+ points) |
clearance:"M3". depth defaults to through all. type is one of simple/drilled/counterbore/countersink. A countersink needs cs_diameter and cs_angle; a counterbore needs cb_diameter and cb_depth. position is a fixed point; to tie it to the part, add references: [{edge:[x,y,z], distance}] (up to two straight edges of the face): the centre then sits at those distances from the edges and follows them. |
solid.pattern.rectangular |
features, dir1, count1, spacing1 (+ dir2, count2, spacing2) |
Spacing takes expressions and follows parameters. |
solid.pattern.circular |
features, axis ("Z", {origin, dir} whose origin may be length expressions the pattern follows, or {face: [x,y,z]} / {edge: [x,y,z]} on a cylinder wall or circular edge, which the pattern follows), count |
angle defaults to 360 deg. A full pattern keeps the COM on the axis, so check its radius with a top-view screenshot. |
solid.mirror |
features:[names] or bodies:[names], plane (XY/XZ/YZ, a construction plane, or {origin, normal} whose origin may use length expressions) |
Follows parameters. A mirror or pattern feature cannot be listed in features of another mirror or pattern, but bodies can mirror the body it made. The mirror is a new body with the first free default name: Body1, Body2 from features, and Side (2), Side (3) from bodies:["Side"]. Read the name from created_bodies. With combine:true, a mirror that overlaps the original joins it and makes no new body. features copies only the features listed, so a later cut is left out unless you list it too. bodies copies the finished body. To name the mirror, use body.rename {"body":"Side (2)","name":"Side_L"}. The new name stays when parameters change. |
-
Names: name every feature (
"name":"Standoff") and keep names unique across sketches and features.timeline.roll_to {"feature":"Plate"}picks the first match, which can be the sketch. -
Counts as parameters:
parameters.add {"name":"n","expression":"6","unit":""}creates a unitless parameter, and"count":"n"uses it in a pattern. -
Names of pattern and mirror copies:
solid.pattern.rectangularandsolid.pattern.circulartakebodiesas well asfeatures, and name copies likesolid.mirrordoes.solid.pattern.circular {"bodies":["Groove end"],"axis":"Z","count":3}keeps the original and makes the copiesGroove end (2)andGroove end (3). A name already taken is skipped: withGroove end (2)present, the copies areGroove end (3)andGroove end (4). Withfeatures, the pattern makes a newBodyN, as in thesolid.mirrorrow. Read the names fromcreated_bodies. Mirroring a copy adds a suffix:Groove end (2)mirrored isGroove end (2) (2). The pattern commands list no body-name parameter, so usebody.renamefor stable names. There is no way yet to refer to every copy at once, for example insolid.combine(#8194). -
Holes on a parametric bolt circle:
- Cut one hole with
solid.cylinder {"diameter":6.6,"height":"T + 2","base":["bcd/2",0,-1],"operation":"cut","name":"BoltHole"}. - Repeat it with
solid.pattern.circular {"features":["BoltHole"],"axis":"Z","count":"n"}.
Both the radius and the count follow their parameters.
- Cut one hole with
-
Parameter changes: for one change, call
set_parameter {"name":"L","value":"120 mm"}. For several, use onebatchofparameters.changesteps instead of oneset_parametercall each. -
Primitive booleans: a
solid.boxorsolid.cylindercut that touches curved faces of the target can fail withthe exact fallback ... takes planar faces only. Use a sketch profile and an extrude cut instead, for example a slot sketch rather than a box plus 2 cylinders.
Worked example: parametric plate with 4 counterbored holes (1 batch)
{"commands":[
{"command":"parameters.add","params":{"name":"L","expression":"80 mm"}},
{"command":"parameters.add","params":{"name":"W","expression":"50 mm"}},
{"command":"parameters.add","params":{"name":"T","expression":"6 mm"}},
{"command":"parameters.add","params":{"name":"inset","expression":"8 mm"}},
{"command":"sketch.create","params":{"plane":"XY","name":"PlateSketch"}},
{"command":"sketch.draw.dimensioned","params":{"command":"sketch.rectangle.center","params":{"center":[0,0],"corner":[40,25]},"dimensions":{"width":"L","height":"W"}}},
{"command":"sketch.finish","params":{}},
{"command":"solid.extrude","params":{"distance":"T","name":"Plate"}},
{"command":"solid.fillet","params":{"edges":[[40,25,3],[-40,25,3],[40,-25,3],[-40,-25,3]],"radius":5,"name":"Corners"}},
{"command":"sketch.create","params":{"plane":"XY","name":"HolePts","offset":"T"}},
{"command":"sketch.point","params":{"point":[32,17]}},
{"command":"sketch.dimension","params":{"entities":["origin","p1"],"type":"horizontal","value":"L/2 - inset"}},
{"command":"sketch.dimension","params":{"entities":["origin","p1"],"type":"vertical","value":"W/2 - inset"}},
{"command":"sketch.finish","params":{}},
{"command":"solid.hole","params":{"sketch":"HolePts","diameter":3.4,"type":"counterbore","cb_diameter":6.5,"cb_depth":3.3,"name":"Hole"}},
{"command":"solid.pattern.rectangular","params":{"features":["Hole"],"dir1":[-1,0,0],"count1":2,"spacing1":"L - 2*inset","dir2":[0,-1,0],"count2":2,"spacing2":"W - 2*inset","name":"Holes"}}
]}
Expected volume:
- Plate:
L*W*T - 4*r²(1-π/4)*T - Each hole:
π*1.7²*(T-3.3) + π*3.25²*3.3 - Total: 23335.2 mm³, with 22 faces.
After set_parameter L=120 the volume is 35335.2 mm³, and the holes stay in the corners.
Reading measure
- Tolerance: analytic and measured volumes agree to about 0.001-0.01%, so treat a gap that small as a match. Long shallow arcs measure worse, about 0.1% (R 1000 mm over 20 degrees).
- Face counts: compare the logical
faces, not the largerkernel.faces. - Reply types:
set_parameterreturnsrecomputedas a number. A batch reply echoes every step. - Boolean warning: a feature
warningsuch asBoolean retry: temporary coincident-face separation up to 2.050000e0 mm per facemeans the kernel nudged faces that coincide. A join flush on a face, such as a cylinder joined onto the floor of a shelled box, or a tapered cut that starts on a face, does not log it. When the volume still matches your number the warning is harmless. When it does not, the retry may have left the geometry wrong, with no error. A standoff built as a joined cylinder with a cut pilot hole, patterned together, reportstool displacement(moving a tool by about 2e-4 mm) but its volume agrees with the analytic growth; a boss with its hole as one ring profile (two concentric circles, extrude the ring) builds without a warning at every height tried (3 to 20 mm).
Reply cost (0.8, plate example)
| Call | Size |
|---|---|
list_commands {} |
Over 100 KB. Never call it unfiltered; filter on a distinctive word such as "hole" or "slot". |
body_topology |
25-45 KB |
inspect_design {} |
12 KB, and it grows with the sketches |
inspect_design {"measure":false,"sketches":false} |
4 KB for one part: parameters, timeline errors, bodies. About 65 B more per body (14 KB at 210 bodies) |
sketch.inspect |
5 KB per small sketch |
parameters.list {"filter":"feature"} |
3 KB |
measure {} |
about 0.9 KB per body: volume, bbox, COM, face/edge/vertex counts. On a large design, execute inspect.measure {"bodies":[...]} measures only the listed bodies |
sketch.solve |
under 100 B: dof, status, profile count |
screenshot {"source":"model","width":480,"height":320} |
one small image. Without source, a bridged server returns the whole app window and ignores the size. |
Errors
| Error text | Fix |
|---|---|
... is not available right now: no sketch is being edited |
Run sketch.create or sketch.edit {sketch} first. |
unknown sketch entity 'p1' |
Use the ids from created. A circle's centre is c1.center. |
the corner must join exactly two lines |
It is a rectangle.center corner. Use the {a, b} form. |
`cs_diameter` must be a number or an expression |
Countersinks need cs_diameter and cs_angle, even with clearance. |
unsupported dimension role for this creator |
Check the roles table above. |
<Feature> cannot be patterned or mirrored yet |
Pattern the original feature, for example one 2x2 rectangular pattern. |
an edge is a point [x,y,z], {point} or {body, index} |
An edge pick contained an expression. Use plain numbers. |
boolean Cut: the operation failed ... planar faces only |
See "Primitive booleans" above. |