Corrects the modeling skill: an edge of the face a shell removes is rounded after the shell, a slot along Y is dimensioned horizontally, long shallow arcs measure to about 0.1%, and a boolean retry warning can hide wrong geometry when the volume does not match.
12 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.
- 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 from the sketch plane along -normal. A hole sketch at z=0 under a part drills into empty space and still reports success, so put the sketch on the top face.
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 curvesl1, a1, l2, a2and pointsp1-p4,a1.center,a2.center.- 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"}}
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, so two concentric circles give a solid disc. 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. |
solid.cylinder |
radius or diameter, height |
base is the centre of the bottom (default origin), axis defaults to Z. Expressions work in base. Always pass operation. |
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, with no distance limit and no error, 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. Fillet first, except an edge of a removed face (see Order in SKILL.md). |
solid.hole |
position:[x,y,z] on a face + 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. |
solid.pattern.rectangular |
features, dir1, count1, spacing1 (+ dir2, count2, spacing2) |
Spacing takes expressions and follows parameters. |
solid.pattern.circular |
features, axis ("Z" or {origin, dir}), 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], plane (XY/XZ/YZ, a construction plane, or {origin, normal}) |
Follows parameters. Mirror and pattern features cannot be mirrored or patterned again. |
-
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. -
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
-
Several parameter changes: use one
batchofparameters.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. Examples are 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. 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. Seen: on a box with filleted corners, a shell and a rounded rim, a standoff joined and its pilot hole cut as two cylinders, patterned 2x2, left material in the holes at some standoff heights. A boss with its hole as one ring profile (two concentric circles, extrude the ring) built correctly at every height tried (3 to 20 mm). Another kind,tool displacement, moves a tool by about 2e-4 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: parameters, timeline errors, bodies |
sketch.inspect |
5 KB per small sketch |
parameters.list {"filter":"feature"} |
3 KB |
measure {} |
1 KB: volume, bbox, COM, face/edge/vertex counts |
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. |