Appendix
Ask's tools
The tools Ask can call while it works on your part, grouped as Ask sees them (catalogue P18-20261031-tool-cut).
Understand
inspect
Read current Part features, profiles, planar faces and Bodies with signed IDs and saved RGB/opacity; report "bom", "project" or "cut_sheets" reads that instead.
- Use when: resolving an existing edit target or checking current geometry and sketch state. Example: inspect {} for the Part, inspect {"report":"bom"} for the bill of materials, "project" for a guided step, "cut_sheets" for the laser sheets.
- Don't: guess identities from feature rows, colour or an old response; use measure for local material and look for images.
- Returns: current feature names, Body IDs, faces, open profiles, bounds, volume, sketch state and per-hole fastener checks.
measure
Measure each solid piece, material inside a world-space box (min/max XYZ in mm), or material along a ray (from, dir, optional length).
-
Use when: a ray answers through or blind, wall thickness and tool access in one call; a box gives local volume and bounds; omit both for per-piece bounds and volume. In development, passage (exact Cut Loft feature name) or passageIndex selects a bounded water space: checks saved installed Bodies and component envelopes, port connectivity including 0.05 mm end probes, and sampled free sections. Optional flowLMin assumes a steady incompressible flow and reports Q/A section speeds only. Do not mix passage fields with box or ray fields. stack (sizes in one chain to a gap between mated parts, each adds true or false with tolerance_mm, default 0.1) gives a tolerance stack-up instead: nominal gap, worst-case and RSS limits, the dominant size and pass, review or fail against minimum_gap_mm (default 0, no clash), the same check as Measure's Stack-up.
-
Don't: infer a hole's location from total volume alone, claim CFD, pressure loss, delivered flow, minimum wall thickness, enclosure sealing or a guaranteed global throat from a passage check; narrow restrictions between stations can be missed. Do not keep checking: at most about three read-only checks per change, then decide.
-
Returns: piece bounds/volume; box volume, occupancy and bounds; or ray material runs [entry, exit] mm, total and first_hit; or stack_up.
-
Called as:
edit {tool: "measure", args: "{…}"}
| Argument | Type | Required | Meaning |
|---|---|---|---|
box |
BoxArgs | no | Measure the solid inside this box; omit box and from for each piece's bbox and volume |
from |
[Double] | no | A ray's start, [x, y, z] in mm, e.g. a hole's mouth; give with dir instead of box |
dir |
[Double] | no | The ray's direction, [dx, dy, dz], e.g. [0, 0, -1] down a hole from the top |
length |
Double | no | How far along the ray in mm; default right through the Part |
passage |
String | no | Development: exact Cut Loft feature representing the fluid volume; omit ray/box fields. Checks actual saved assembly obstructions and bounded connectivity |
passageIndex |
Int | no | Development: zero-based Cut Loft feature index; overrides passage name |
flowLMin |
Double | no | Optional assumed steady incompressible flow, 0–10,000 L/min. Mean section speed only; not delivered flow, pressure loss or CFD |
stack |
[StackLinkArgs] | no | A tolerance stack-up instead of geometry: the sizes in one chain to a gap between mated parts; give on its own |
minimum_gap_mm |
Double | no | With stack: the smallest gap the fit needs in mm; default 0, no clash |
look
Capture the Part as labelled home, top, front or right images on image-capable routes.
- Use when: checking visible feature completeness, print layout and colour/translucency; choose up to four distinct supported views. After final edits, use presentation:true in assembly view for assembled views plus an opened stack; it restores zero explosion. Read those images in a new reply before finish.
- Don't: treat pictures as precise wall/clearance measurements or claim an image that failed to render.
- Returns: actual view images and a geometry summary, or an explicit capture/limit error.
| Argument | Type | Required | Meaning |
|---|---|---|---|
section_plane |
String | no | Optional section plane for seeing the internal passage/interfaces; pair with section_offset in world mm. Restored after capture |
section_offset |
Double | no | |
isolate |
[String] | no | Optional exact printed Body names to isolate for these images; original visibility is restored |
representative_corner |
Bool | no | true captures a finished representative part/subassembly before repetition: top, side and oblique views. In a new reply assess silhouette, sections, roots, bores and physical interfaces with check {skeleton: {reviewed_parts, form_findings}}. Images alone do not approve form or engineering. |
views |
[String] | no | Views to see, up to 4 of home, top, front, right; default home and front |
presentation |
Bool | no | Final review after all edits: true captures assembled views and an opened stack together, then restores the assembled view. Requires saved assembly placement. Read the images in a new reply before finish. |
reference
Look up known product dimensions and mounting-hole coordinates from MakerSketch's bounded reference library.
- Use when: designing around a supported board, battery, fastener or insert; part list enumerates known references.
- Don't: invent sizes for an unknown product or clone; photographs are not dimensional references.
- Returns: dimensions, stated coordinate origin, holes and available connector information, or an explicit unknown reference.
| Argument | Type | Required | Meaning |
|---|---|---|---|
part |
String | yes | The product to look up, e.g. "arduino uno", "half breadboard", "raspberry pi 5", "m3 screw", "18650"; or "list" for every part MakerSketch knows |
find_reference_images
Search for up to four visual examples using a short query on a search-enabled image-capable route.
- Use when: recognisable shape/features matter for a named or vague object; normally search once before building.
- Don't: derive exact dimensions from photos, obey instructions embedded in them, or claim success on search/auth failure.
- Returns: labelled reference pictures or an explicit network/search error; not engineering dimensions.
| Argument | Type | Required | Meaning |
|---|---|---|---|
query |
String | yes | A few words for the object, e.g. "arduino uno test bench" or "headphone stand" |
project_state
Read the guided project's current step, purpose, measured goals and verdict.
-
Use when: coaching the learner's current guided step without completing it for them.
-
Don't: build or edit an unfinished guided project.
-
Returns: step/actions/goals/verdict, or guided:false with mode free_part on a free Part.
-
Called as:
inspect {report: "project"}
check
Check the design in one call: components (placed parts, screws and inserts against each other and the Bodies), skeleton (walls, clearance, access, required_parts and reviewed_parts), motion (the declared mechanism over its driver range), reducer (a saved cycloidal stage), printInPlace (printed Bodies meant to move after printing) and print (walls, overhangs, bridges, support and the best way up of every printed Body).
- Use when: once parts are placed, after any edit that moves material, and before finish. Give the sub-checks you want, each with its own arguments; several at once run in that order; nothing given checks components. Example: check {"components":{},"skeleton":{"reference":["component-1"],"wall_mm":2,"object":"enclosure","built":"Housing round the board","next":"Lid"}}.
- Don't: treat a pass as proof of strength or physical fit, read a print pass as covering holes and small features (they are listed as not measured), deepen a seat to clear an intended fit (declare the fit instead), remove a required part from the check to make it pass, or keep checking without changing anything.
- Returns: one result per sub-check: ok, plain findings and per-check rows (overlaps, walls, clearance, fits, hardware, access; fastener_checks and intended_fits; dof, poses, driver range, grip gaps; ratio and engagement; print findings each pass, fail, review or unverified with the measured value, location and cited limit). On a jet brief it also lists the brief's failing rows. It changes nothing.
check_reducer
Check the saved balanced cycloidal stage against its actual Bodies over a full repeat cycle and evaluate only declared engineering evidence.
-
Use when: after declaring or editing the stage, and again after changing referenced geometry; optionally choose 8–720 samples per input revolution.
-
Don't: treat a sampled digital pass as physical validation, fatigue/efficiency/thermal/vibration/wear proof or bearing catalogue life.
-
Returns: structured ratio/direction, closure, per-disc engagement/collision/fit, balance residual, engineering pass/fail/not-rated, assumptions, missing inputs and remaining physical checks.
-
Called as:
check {reducer: {…}}
| Argument | Type | Required | Meaning |
|---|---|---|---|
stepsPerInputRevolution |
Int | no | Actual-solid samples per input revolution, 8 to 720; default 24 |
check_print_in_place
Check printed Bodies meant to move after printing, where they are modelled with Z 0 as the bed: a piece with nothing to print on, faces that touch or overlap and fuse, gaps under 0.3 mm, and an underside printed on the Body it moves against.
-
Use when: after building a hinge, ball joint, chain or any parts that print together and move apart, and again after any edit near the joint.
-
Don't: treat a pass as proof it moves: holding the part in and its range of motion are not measured, and a print test still decides.
-
Returns: ok (no fail rows) and rows in the report form: state pass, fail, review or unverified, check, bodies, value_mm or value_mm2, at_mm, rule and message. It changes nothing.
-
Called as:
check {printInPlace: {}}
check_print
Check every printed Body as Make prints it, the same check as Make's Print check: wall thickness, overhangs, bridges, support and the best way up, against the process's design limits.
-
Use when: before finish on anything printed, and after an edit that changes a printed Body. process is fdm (the default) or sls, or give material (pla, abs, pc, peek, pa12, tpu-sls) and its process follows. Example: check {"print":{"process":"fdm"}}.
-
Don't: treat a pass as a slicer's result or as covering holes and small features (they come back unverified), argue a fail away instead of thickening, chamfering or turning the part, or apply FDM overhang rows to an SLS part.
-
Returns: process, ok (no fail), summary, and findings in order per Body: wall, overhang or bridge, support, orientation (its turn_deg when a turn needs materially less support), then hole and feature as unverified. Each finding has check, status (pass, fail, review, unverified), measured, unit, limit, rule, location_mm in the Part and words. It changes nothing.
-
Called as:
check {print: {…}}
| Argument | Type | Required | Meaning |
|---|---|---|---|
process |
String | no | fdm (the default) or sls |
material |
String | no | Instead of process: pla, abs, pc, peek, pa12 or tpu-sls; its process follows |
catalog
Search and inspect verified purchased components, standard hardware, their lightweight envelopes and named mechanical interfaces.
-
Use when: designing around a supported fastener, heat-set insert, bearing, motor, linear guide or magnet; search first, then read every part you will place in one call: ids ["bearing.mr63", "shaft.3mm", "seal.rotary-3x10x6-nbr"] (up to 16) returns each part's size, ports with their kinds, required parameters and compatibility, which is all placing needs. detail full (with id or ids) adds sourced dimensions, provenance and accuracy; geometry true the reference solid. Magnets are one builder per shape (magnet.disc, magnet.block, magnet.ring): place with the measured size as parameters, and pair two for a lid by mating pole_face to pole_face. Search one part per query ("M2.5 nut", then "M2.5 screw"). Every result is in the catalogue and placeable by its id. For a screw, id plus stack_mm and into (the nut or insert id, or tap) checks its length and names the next stock length. Example: catalog {"ids":["bearing.mr63","shaft.3mm"]}.
-
Don't: read parts one call at a time, ask for detail full before you need a dimension, treat a family name as a complete part, omit a required parameter, turn maximum envelopes into nominal sizes, or claim that catalog inspection placed geometry, or call a part missing that a search returned.
-
Returns: stable IDs and exact variants; or parts [{id, name, size, interfaces [{id, kind}], required_parameters, compatibility}] (missing names unknown ids); or with detail full one entry's sourced dimensions, provenance, simplified geometry, mounting interfaces and compatibility notes.
-
Called as:
edit {tool: "catalog", args: "{…}"}
| Argument | Type | Required | Meaning |
|---|---|---|---|
geometry |
Bool | no | With id: include reference geometry/polygons only when needed; dimensions and interfaces are always included |
query |
String | no | Plain-language component search, such as NEMA 17, MGN12H, 608 bearing or M3 screw; omit when inspecting an id |
family |
String | no | Optional exact family filter |
id |
String | no | Stable catalog id returned by search: its size, interfaces with kinds, required parameters and compatibility (what placing needs) |
ids |
[String] | no | Several stable catalog ids (up to 16) read in one call, each as id gives it |
detail |
String | no | With id or ids: full adds sourced dimensions, provenance and accuracy; default short |
stack_mm |
Double | no | With a sized screw id: the thickness it passes through before its thread mates, in mm; checks its length and names the next stock length |
into |
String | no | With stack_mm: the catalog id of the nut or heat-set insert the screw ends in, or tap |
component_check
Check exact frozen component envelopes against other components and manufacturing Bodies, including sourced bounded MGN12 carriage travel, and check every placed metric screw as a fastened joint.
-
Use when: finding an obstructed or overlapping purchased component, or a screw that isn't fastened right, before building or printing; optionally select one returned finding to highlight its references and swept range. Give stack (and minimum_gap_mm) to judge the gap between a mated pair by tolerance stack-up too, reported as stack_up. fastener_checks judges each screw where it sits: its head (or washer) seated on at least 75% of its annulus, a clearance hole through the parts it clamps, its thread held by a coaxial nut, insert or 1.5 × d of tapped plastic, room past its tip and a straight driver path. No overlap is not a seated screw: fix a failed seat by moving the screw onto its face or building the face up to the head.
-
Don't: claim clearance, service, tool or cable access where the catalog has no sourced envelope; treat a clear result as a tolerance or motion-dynamics certification. Catalogue parts bring their own fit (screws, nuts and inserts a thread, bearings a bearing seat, shafts and pins a press fit, cross pins through a shaft): an overlap within that fit's allowance is listed in intended_fits, not findings. Never enlarge a pocket to clear a fit; a finding that remains goes deeper than the fit allows.
-
Returns: deterministic structured findings with involved component/Body ids and overlap volume (a fastener finding for each screw that fails), intended_fits for overlaps a fit explains, and fastener_checks per screw (seated_fraction, receiver, engagement_mm, tip_clearance_mm, driver_clearance_mm, problems); no saved feature, boolean or manufacturing-export change.
-
Called as:
check {components: {…}}
| Argument | Type | Required | Meaning |
|---|---|---|---|
scope_id |
String | no | Optional exact assembly occurrence UUID. Checks that subtree against neighbours outside it too; omit for whole assembly. |
select |
String | no | Optional exact finding id returned by a previous check; highlights that issue in the 3D view |
clear_selection |
Bool | no | Clear the current analysis highlight; defaults false |
stack |
[StackLinkArgs] | no | Optional tolerance stack-up for a mated pair: the sizes in one chain to the gap between them; reported as stack_up |
minimum_gap_mm |
Double | no | With stack: the smallest gap the fit needs in mm; default 0, no clash |
bom
Read the bill of materials derived directly from placed purchased and standardized component instances.
-
Use when: checking exact quantities, variants, selected parameters, revisions, instance identities and source links before ordering or explaining a design.
-
Don't: add learner-made Bodies, infer unplaced hardware, omit hidden components, or describe the BOM as separately saved editable data.
-
Returns: stable grouped procurement lines; hidden instances remain and removed instances disappear because the result is recomputed from the Part.
-
Called as:
inspect {report: "bom"}
design_recipe
Search and inspect an offline mechanical construction library and pinned licensed hardware dimensional tables.
-
Use when: planning joints, bearings, fasteners, drives, linkages, shaped structures and printable interfaces. Search with query/limit 1–12 and optional exact dimension family/size/standard filters; inspect a returned recipe or dimension-record id. Recipe inspection defaults to an overview; request detail full for the selected pattern’s construction, checks and examples, then inspect only needed dependency IDs. Inspect returns lengths_mm, the normalized source lengths. Fit takes a dimension-record id, case-sensitive parameter, signed allowance_mm and allowance_basis per_side or total to calculate a fabrication dimension; it does not cut geometry. Layout places a parallel-shaft gear train before you build it, instead of working angles out by hand: train {module, envelope [u, v] (the space's sizes square to the shafts, from 0,0), margin_mm, shafts in mesh order [{name, gears [teeth along the shaft], part (a catalogue id on that axis, such as dc.540-3.17, whose body counts), at [u, v] for the one fixed shaft, angle_deg: one angle, a list to try, or left out to try every 5°, where the shaft sits seen from its neighbour nearer the fixed one, CCW from +u}]}; each shaft's last gear meshes the next one's first. Example: design_recipe {"action":"layout","train":{"module":0.6,"envelope":[110,60],"shafts":[{"name":"Motor","gears":[18],"part":"dc.540-3.17"},{"name":"Countershaft","gears":[54,20]},{"name":"Output","gears":[60],"at":[70,25]}]}}.
-
Don't: treat a reference pattern as an executable generator, substitute table geometry for a verified purchased variant, apply fabrication allowances silently, claim unsupported motion or global parameter links, or read a reference status as physical qualification.
-
Returns: bounded search matches, a recipe overview/selected full pattern, or an exact dimensional record with pinned provenance and licensing; a layout's fits and verdict (what sticks out and by how much when nothing fits), each shaft's at_mm and angle, centre distances and each gear's and part's bounds. A read-only lookup; it never edits geometry or places hardware. Numerical records retain raw field names and their original unit meanings.
-
Called as:
edit {tool: "design_recipe", args: "{…}"}
| Argument | Type | Required | Meaning |
|---|---|---|---|
detail |
String | no | inspect returns an overview by default; full loads the selected recipe's construction, checks and examples. Dependencies stay summaries and exact dimension records are inspected individually |
action |
String | no | search finds patterns/data; inspect reads an exact id and normalized lengths_mm; fit calculates one fabrication size without editing geometry; layout places a parallel-shaft gear train in its space |
train |
GearTrainArgs | no | Layout only: the gear train and the space it must fit |
query |
String | no | Construction or hardware to find, such as bearing retention, split clamp, M3 socket screw, belt tensioner or ribbed bracket |
id |
String | no | Exact recipe or dimension-record id returned by search |
limit |
Int | no | Maximum search matches per category, 1–12; default 8 |
family |
String | no | Search only: exact dimension family, e.g. bearing, capped_bearing, socket_head, clearance, hex_nut, heat_insert, washer. Does not filter recipes |
size |
String | no | Search only: exact full source size, e.g. M3-0.5 or #4-40. No substitution if absent |
standard |
String | no | Search only: exact standard or supplier table, e.g. iso4762, din6885 or table_b |
parameter |
String | no | Fit only: case-sensitive positive length field from inspected lengths_mm; bearing D is OD, d is bore, B is width |
allowance_mm |
Double | no | Fit only, required: signed allowance in mm; positive enlarges the selected source dimension, negative shrinks it. No automatic process allowance |
allowance_basis |
String | no | Fit only, required: per_side doubles allowance for opposed faces; total adds it once (diametral allowance or depth change) |
checkpoint
Check the assembled skeleton before detail: overlapping pieces, walls and clearance around references, support for magnets/inserts and port/card access. Continue the accepted brief after reviewing the findings.
-
Use when: once every piece is built and placed in its assembled place with key hardware placed. reference names a Body or a placed component instance_id; wall_mm is the intended wall (default 2); access lists {name, at [x,y,z] at the port or card's outer edge, dir pointing out}; a reference Body named for a board with drawn ports (Pi Zero, Pi 5) and laid flat as its drawing adds those ports itself, so list only others. Drawing-based catalogue boards use their transformed PCB datum for sampled ports; unsupported connector/cable envelopes remain unchecked. object says what it is: enclosure (a case round a board or device) gets the case rules (rules: wall, board edge, lid, port opening allowance and screw boss rows, each pass, fail, review or unverified with the measured value and the rule), hollow walls and ports; bracket (screwed to a wall, loaded out from it) checks its wall screws sit in the top third of the leg, up being up (default [0,0,1]); stand, mechanism or other get neither (the default is enclosure only when a reference is a board). Run it at least once in every build before finish. Clearance is the real distance between solids. Designed fits (catalogue hardware in its holes, fits declared with assembly {action: fit}) count as intended, not clashes. Retain required_parts [{name,kind:body/component,reference:exact intended Body name or catalog_id,count,after:[role names],repeat_of:[representative role names]}] a piece at a time: add a role when you start that piece, never the whole list up front. The ledger and refused finishes name the next piece from what exists, the moving train (shafts, gears, carrier, their bearings) before the casing round it and fastener detail, whatever order roles were added in; the brief's missing parts are named either way. This inserts nothing. Updates retain roles/counts/dependencies and may substitute a role's kind and reference (a catalog_id, or a bought Body in the Part); replaced_by:[role names] splits one role across several. Call checkpoint to inspect the retained list. After representative images and a current clean component_check, record reviewed_parts [role names] and form_findings [unresolved shape/interface issues] in a new reply. If an unrelated interface blocks the whole-assembly check, the refusal supplies scope_id values: check each representative occurrence locally before assessing it. Scoped evidence never clears repetition or whole-assembly acceptance. [] means no observed issues, not engineering certification. Manual creation and copying obey the same dependencies. For waterjets inspect motion.waterjet-drive and retain checkpoint {waterjet} before geometry, then repeat its material probes after housing edits; once the housing is refined, measure each passage Cut, look {section_plane, section_offset} on the world plane through the shaft axis and in a new reply record waterway {passages, transition, findings}; required_parts rotor criteria measure blade count/diameter/swept clearance. built and next are short plain sentences: what exists and what comes next.
-
Don't: declare the whole parts list before building, treat a required_parts declaration as physical acceptance, run the physical check after detailing instead of before, deepen a slot or loosen a seat only to clear a contact that is meant (declare the fit instead), or treat a pass as proof of strength, printability, motion or real fit.
-
Returns: ok, plain findings and per-check rows (overlaps, walls, clearance, fits, hardware, access, wall_screws). A waterjet layout check before geometry is not physical acceptance. This check does not pause the build; repair useful findings and finish the requested design.
-
Called as:
check {skeleton: {…}}
| Argument | Type | Required | Meaning |
|---|---|---|---|
waterjet |
WaterjetArgs | no | A waterjet: retain this layout before solids, then repeat after housing edits. Stations are downstream distances from axis_origin. Checks intake placement and sampled enclosing material, not hydraulic performance. |
waterway |
WaterwayArgs | no | Waterjet housing refinement: assess the refined water path (may share a call with waterjet; the app takes the section along the shaft axis when none is current). Straight cuts alone are a block-out, not the shaped intake. Edits make it stale. |
required_edits |
[AdditionArgs] | no | Before additions to a finished Part, retain each new Body or local Add/Cut; rerun checkpoint after building to verify actual material. |
required_parts |
[RequiredPartArgs] | no | Add the role for the piece you are starting (with its after roles), a piece at a time, never the whole list up front; the ledger names the next piece from what exists, moving train first, casing last. Identical stock quantities are allocated in declaration order. Later calls add roles or substitute references; roles, counts and dependencies stay. No geometry is created. |
reviewed_parts |
[String] | no | Required Body role names assessed AFTER representative images in a new reply, with form_findings |
form_findings |
[String] | no | Unresolved silhouette, root/blend, bore and interface issues seen in the representative parts; [] means none seen |
reference |
[String] | no | Reference Body names or exact placed component instance_id values from inspect; use the catalogue board instance instead of redrawing its PCB |
wall_mm |
Double | no | The case's intended wall in mm; default 2 |
object |
String | no | enclosure gets the case rules (hollow walls, ports and cards); bracket (screwed to a wall, loaded out from it) gets the wall-screw lever-arm check; stand, mechanism or other neither. Defaults to enclosure only when a reference is a board |
up |
[Double] | no | Bracket only: the world direction that is up on the wall in this pose, default [0,0,1]; a bracket printed on its side with its leg along +Y is [0,1,0] |
access |
[AccessArgs] | no | Ports and cards that must be reachable |
built |
String | yes | One plain sentence: what the skeleton is, piece by piece |
next |
String | yes | One plain sentence: the detail you'll add next |
Sketch
sketch
Open Top/XY, Front/XZ or Right/YZ, a parallel planar face at its world position at_mm (Top's z, Front's y, Right's x) with outward, or reopen with edit/editIndex.
-
Use when: creating a profile or changing an existing sketch's geometry in place; inspect faces/feature identity first. Give a face by at_mm, its world coordinate, never a sign flip: the face at y = 40 is Front at_mm 40. offset is only for copying inspect's faces: it runs along the plane's normal, Top +Z, Right +X, but Front −Y, so Front offset −40 is y = 40.
-
Don't: invent a sloped-plane API; editIndex overrides edit name, and plane remains required but is ignored for reopening. A plane in negative space (Front with a positive offset) is refused.
-
Returns: the open sketch name/state and plane_at, the plane's world position ("y = 40 mm"); switching sketches may finish the previous one.
-
Called as:
edit {tool: "sketch", args: "{…}"}
| Argument | Type | Required | Meaning |
|---|---|---|---|
plane |
String | yes | Origin plane: top (XY), front (XZ) or right (YZ) |
at_mm |
Double | no | Sketch on a flat face by where it is in the world, in mm: Top's z, Front's y, Right's x (y = 92 is at_mm 92 on Front). Use this, not offset |
offset |
Double | no | Only to copy an inspect face: distance along the plane's normal, Top +Z, Right +X, Front −Y (Front offset −40 is y = 40) |
outward |
Double | no | With a face: 1 if the face looks along the plane's +axis, -1 if along -axis |
edit |
String | no | Reopen an existing sketch instead, by its name ("Sketch 2") from inspect's features; plane is then ignored |
editIndex |
Int | no | Reopen the sketch at this zero-based index in inspect's features; takes precedence over edit |
draw
Execute complete 2D command lines in the open sketch, including closed outlines, circles, text and window/delta stretch.
-
Use when: drawing profiles; circle 10,10 3 means radius3, not diameter. Changing existing lines (reopen the sketch with edit first):
offset 5 x,y x,y exitcopies the whole joined outline 5 mm away (a point on it, then a point on the side to copy to);gap x,y x,y 5makes two lines parallel and exactly 5 mm apart (a point on the line that stays, then on the line that moves). Never redraw geometry to move it. Circular arcs use the complete pline JSON example in modelling instructions: vertices with p:[x,y], outgoing bulge and closed:true. -
Don't: invent interactive a/b/l polyline aliases, coordinate-triple bulges or 3D commands. Use complete structured pline JSON for arcs, and text rather than letters constructed from lines.
-
Returns: closed-profile indices to use in subsequent operations, or a specific command error.
-
Called as:
edit {tool: "draw", args: "{…}"}
| Argument | Type | Required | Meaning |
|---|---|---|---|
commands |
[String] | yes | AutoCAD-style command lines, every input on one line, e.g. rectang 0,0 40,20, circle 20,10 3, line 0,0 10,0 10,5 c. In a reopened sketch use stretch {"window":[[x0,y0],[x1,y1]],"delta":[dx,dy]} to resize in place. To change lines already in the sketch (reopen it with sketch edit first), never redraw them: offset 5 x,y x,y exit copies the whole joined outline 5 mm away (first point on a line of it, second on the side to copy to); gap x,y x,y 5 makes two lines parallel and exactly 5 mm apart (a point on the line that stays, a point on the line that moves). |
outline
Copy a parallel face's actual outer/opening contours into the already open destination sketch, with optional per-side fit and translation.
-
Use when: matching a plate/lip to existing geometry; select all/outer/openings, inward/outward and fit or clearance in mm.
-
Don't: refill a wrong cut (undo it instead), or claim live associativity or automatic recentering. Fit edits omit source/placement fields and require unchanged copied entities.
-
Returns: frozen ordinary editable sketch geometry; sketch stays open, circles remain recognisable.
-
Called as:
edit {tool: "outline", args: "{…}"}
| Argument | Type | Required | Meaning |
|---|---|---|---|
body |
String | no | Name of the source Body's extrusion or generated feature; omit only for one Body |
bodyIndex |
Int | no | Explicit signed source Body identity from inspect, taking precedence over body |
plane |
String | no | Source face plane, parallel to the already open destination sketch |
offset |
Double | no | Source face offset in mm; source and destination may be on different parallel planes |
outward |
Double | no | Face outward side, 1 or -1; defaults to 1 |
at |
[Double] | no | Optional [x,y] point on face material to select one disconnected coplanar face |
loops |
String | no | Contours to copy: all by default, outer for plates, openings for a locating lip |
fit |
String | no | none copies exact loops; press 0.1, snug 0.2, loose 0.4 mm per side |
clearance |
Double | no | Custom clearance per side in mm, overrides fit |
direction |
String | no | inward shrinks each chosen contour, outward grows it |
translation |
[Double] | no | Explicit in-plane [dx,dy] translation in mm; default [0,0] preserves world alignment |
feature |
String | no | Edit only fit by name while copied entities remain unchanged; give fit/clearance/direction and omit all source, contour and placement fields |
index |
Int | no | Zero-based feature index for editing fit; takes precedence over name |
Solid
part
Build one whole part (one Body, named by its role) from a short feature script in one call: the normal way to build a part, gears included; a hole or boss named after a planned port binds it.
- Use when: building any printed part once its sizes are known. role is the part's name ("Servo mount"). features run in order in the part's own frame, each one you could make by hand; the schema lists each feature's arguments. A part's first gear step makes the gear Body, a later one with offset (mm up Z) adds a compound gear. Each hole or boss step is a port named by its name (else bore, shaft_end or mount); the bottom and top faces are base and top, a revolve's axis is axis and axis_end; a step named after one of this role's planned ports realises it. Add mate {to_part, at?, port?, to_port?, offset_mm?, angle_deg?, flip?} to place the part in the same call (ports left out are chosen by kind; a failed mate leaves the part built, with the mate to make in findings). The plan's first role is the ground: no mate, it sits where it is drawn. An extrude or revolve takes the shapes of the script's last sketch; the other steps act on this part's Body. A sketch's draw lines are command lines (rectang, circle, line, polygon) or a command with JSON parameters: pline {"vertices":[{"p":[13.5,12],"bulge":1},{"p":[10.5,12]}],"closed":true}. A turned part straddles its axis: sketch it on front with offset -R and outward -1 so it stays in positive space. Example: part {"role":"Servo mount","features":[{"feature":"sketch","plane":"top","draw":["rectang 0,0 40,30"]},{"feature":"extrude","distance":6,"op":"new"},{"feature":"hole","plane":"top","offset":6,"outward":1,"centers":[[5,5],[35,5],[5,25],[35,25]],"diameter":3.4,"through":true},{"feature":"fillet","radius":3,"edges":"sides"}],"mate":{"port":"base","to_part":"Hull bottom","to_port":"top"}}.
- Don't: build a part feature by feature with sketch/extrude/hole calls, put two Bodies in one script (one new per part; a second new is refused), give a world position (the script is in the part's own frame, resting on Z 0, beside other parts at positive X/Y), or retry the same failing numbers: read the failing step named in the error and change it.
- Returns: role, body_id, bbox_mm: {min,max,size}, volume_mm3, pieces, features_built, ports [{name, kind}], placement (the mate's result when mate was given) and findings (below Z 0, negative X/Y, separate pieces, a mate that failed with the call to make) measured from the built Body; one undo step. A failing step fails only this part: the error names the step, its feature and arguments, and the Part is as it was.
| Argument | Type | Required | Meaning |
|---|---|---|---|
role |
String | yes | The part's name, from the design's roles: Housing tube, Nozzle, Servo mount |
features |
[PartFeatureArgs] | yes | 1 to 64 steps run in order in the part's own frame; the first extrude or revolve (op new) makes its Body, later steps add to, cut or round it |
mate |
PartMateArgs | no | Place the part in the same call: one of its ports (a hole's name, bore, base, axis) on a partner's port, as the mate tool does |
mate
Place a part by aligning one of its ports to a partner's port: the only way to place anything but the ground. The partner's port may be named, or given inline as to_point [x,y,z] and to_axis in assembled mm (a brief's axis or seat centre): it becomes the partner's snap point and moves with it, so no datum edit or anchor is needed first.
- Use when: placing any part once it and its partner have ports. part and to_part are a Body's name, a placed part's instance id (component-1) or catalogue id, or a construction role with no Body (the ground: its datums and planned ports). port, to_port and at are optional: the engine tries every pair of ports whose kinds mate, both ways round, and keeps the first that sits clear of the partner on or above 0 (the reply's resolved says which were used); at names a port or datum on the partner to place nearest. The ground role sits where it is drawn: a mate of it changes nothing. A port is a catalogue interface (mounting_face, shaft_axis), a realised port, a planned port of a role or a ground datum (transom). Kinds that mate: face to face, shaft end into bore, bore onto bearing seat, spline to spline, pivot to pivot, passage to passage; flip turns the part round. Face to face keeps the port's +X and turns Y and Z over (a half turn about X, never a mirror). offset_mm moves it along the partner port's axis, angle_deg turns it about that axis. along instead puts the port that far along to_port's axis, in mm or an expression of the plan's parameters (impeller_len + 2), read once: place a stack's parts on its axis this way, never by to_point, and read the reply's axis (each part's span, the gaps, mm left before each datum). joint says how it moves there: turns (about the partner port's axis: a gear on its axle, a carrier in its bearings) or fixed (a gear keyed to its shaft, a cap on its carrier); say it for every gear, carrier and shaft, since a snap point from to_point has no kind for the engine to read. travel_deg, given alone with part and to_part once a servo is mated, sets the servo's Travel limit [low, high] in degrees about centre. Example: mate {"part":"component-1","port":"mounting_face","to_part":"Housing","to_port":"motor_mount","offset_mm":0}.
- Don't: give a world origin or rotation for a mated part, mate the ground to a part, mate a part to one placed from it (a loop: the mechanism solver owns loops and second supports), or guess port names: inspect or catalog lists them.
- Returns: part, port, to_part, to_port, fit, origin_mm and rotation_degrees as placed, resolution, with along the axis {part, parts, gaps, datums: mm from to_port's origin}, and findings with fixes (parts overlapping on the axis, kinds that don't mate, a fit that doesn't match, an overlap beyond the fit's allowance, a planned port not yet realised); one undo step. The part follows its partner: a feature edit or parameter change re-solves it, a removed port keeps its last pose with a finding.
| Argument | Type | Required | Meaning |
|---|---|---|---|
part |
String | yes | The part to place: a Body's name, a placed part's instance id (component-1) or catalogue id |
port |
String | no | Its port: a catalogue interface (mounting_face, shaft_axis) or a realised port (hub_bore); leave it out and the engine picks the port whose kind fits |
to_part |
String | yes | The partner: a Body, a placed part, or a construction role with no Body (the ground) |
to_port |
String | no | The partner's port: a catalogue interface, a realised or planned port (motor_mount), or a ground datum (transom); leave it out and the engine picks the pair that sits clear |
to_point |
[Double] | no | Instead of to_port: where this part's port sits on the partner, [x,y,z] in assembled mm (a gear's axis point, a bearing seat's centre). No datum or snap point needed first |
to_axis |
[Double] | no | With to_point: the direction the port faces there, [x,y,z]; default [0,0,1] |
at |
String | no | A port or datum on the partner to place nearest, when the ports are left out |
offset_mm |
Double | no | Distance along the partner port's axis in mm, a dimension from the brief (a 1 mm gasket); default 0 |
along |
String | no | With to_port, instead of offset_mm: how far along its axis the port sits, mm or an expression of the plan's parameters (impeller_len + 2); the reply gives each part's span on the axis, the gaps and what is left before each datum |
angle_deg |
Double | no | Turn about the partner port's axis in degrees; default 0 |
flip |
Bool | no | true turns the part round: faces and splines already meet face to face, shafts already enter bores |
joint |
String | no | turns: it turns on the partner about the port's axis (a gear on its axle, a carrier in its bearings, a planet on its pin); fixed: held to it (a gear keyed to its shaft, a cap on its carrier). Say it for every gear, carrier and shaft; left out, the ports' kinds decide |
travel_deg |
[Double] | no | For a mated servo, on its own with part and to_part: its Travel limit [low, high] in degrees about centre, within the catalogue's travel; moves nothing |
fit_around
Derive a housing round the parts placed on an axis, or on a gear train's parallel axes: the tube or lobed case that clears them, keeping the material its planned ports need (seats, bosses, flanges, duct sections), as the role's Body.
-
Use when: once the axis stack (shaft, bearings, seal, impeller, motor) is placed by mates and the housing role has planned ports. role is the housing's planned role; axis is one of its ports of kind axis (origin at the open end, +Z along the stack) or a datum; wall_mm is the printed wall. Obstacles default to every Body and bought part on the axis, each turning Body's full-turn sweep (clearance tip_gap), the widest turning part's way in from the open end and driver room past every screw and insert; obstacles lists Body names or instance ids to use instead. A bore, bearing seat or passage port keeps a seat round the part placed at it; a mount face keeps a flange, with bosses on the mated part's bolt pattern. intake names a Body (the curved passage loft) joined to the tube, its cut lofts opened into it. A gear train's housing: axes lists its other shaft axes, parallel to axis; each gear gets a lobe (its measured tip circle, running clearance and wall), smooth arcs join the lobes, the case runs along the axes over the widest gear stack, a part that fits a seat's bore (a shaft, a bearing) passes through the wall, each bearing seat keeps a boss, and split true parts it into the role's Body and its cover along the shafts, never across them, at the plane through axis and the last of axes (input and output; split_through names another two), with locating pins: a seat on that plane splits through its bore, one off it stays whole in one half, and one the plane cuts off its axis is a finding. A bearing seat inside the case (a ring round a carrier hub) is kept as a ring of wall round its bearing, joined to the case only where the ring meets the wall: give it a web with part or edit when the reply says it is cut off. Example: fit_around {"role":"Housing","axis":"jet_axis","wall_mm":2.4,"intake":"Intake"}; a train: fit_around {"role":"Gearbox","axis":"input_axis","axes":["idler_axis","output_axis"],"wall_mm":2.4,"split":true}.
-
Don't: give sizes the plan holds (seats, bosses and flanges come from the ports and the parts mated to them), call it before the stack is placed by mates, fit around a role built by part (delete that Body first), build a gear housing as a rectangle extruded and shelled (fit it over the train's axes), or expect ports off the axes to be built: skipped_ports lists them for part or edit.
-
Returns: role, body_id, bbox_mm, volume_mm3, pieces, min_wall_mm, obstacles, preserves, skipped_ports, ports (realised against planned), axes and halves for a train, and findings (a design conflict where a port's material meets a sweep or tool room, a boss cut off, a thin wall, a turning part wider than its way in, a train's gears trapped in one piece, separate pieces); one undo step. After a plan edit, call it again to rebuild the housing.
-
Called as:
edit {tool: "fit_around", args: "{…}"}
| Argument | Type | Required | Meaning |
|---|---|---|---|
role |
String | yes | The housing's planned role (Housing): its planned ports give the seats, bosses, flanges and duct sections |
axis |
String | yes | The stack's axis: one of the role's ports of kind axis (jet_axis), origin at the open end, or a datum |
axes |
[String] | no | A gear train's other shaft axes, parallel to axis (ports of kind axis or datums): the housing wraps every gear in a lobe |
split |
Bool | no | true parts the housing into two located halves along the shafts, at the plane through axis and the last of axes (input and output), so the gears go in |
split_through |
[String] | no | Two of the train's axes the parting plane runs through instead of the first and last; implies split |
wall_mm |
Double | yes | The printed wall in mm |
obstacles |
[String] | no | Body names or placed-part instance ids to fit around instead of everything on the axis; omit for the default |
intake |
String | no | A Body (the curved passage loft) joined to the tube, its cut lofts opened into it |
extrude
Extrude specified open profiles by distance in mm as New, Add or Cut, optionally symmetric, optionally with a draft in degrees (walls lean in going away from the sketch; negative leans out); name names it in the same Undo step.
-
Use when: making a prismatic feature; choose an existing body/bodyIndex only for Add/Cut and explicitly use op new for an independent Body. An Add (extrude, revolve or pattern) that sits flush on a Body's face joins it; don't overlap it into the Body to fuse.
-
Don't: Cut before material exists or without a target body/bodyIndex, confuse profile indices with signed Body IDs, or supply a target for New.
-
Returns: features, bounds, volume and any warning; finishes an open sketch first.
-
Called as:
edit {tool: "extrude", args: "{…}"}
| Argument | Type | Required | Meaning |
|---|---|---|---|
distance |
Double | yes | Distance in mm |
profiles |
[Int] | no | Open profile indices to extrude together; default the newest |
op |
String | no | new for the first solid; add or cut only once a solid exists (cut makes holes in it) |
symmetric |
Bool | no | Half the distance each side of the sketch |
draft |
Double | no | Draft in degrees: the walls lean in this much as they go away from the sketch (negative leans out; holes lean the other way). 0 or omitted: straight walls |
body |
String | no | Target Body name from inspect for Add/Cut, such as Base or Lid piece; otherwise inferred from the sketched face. Omit for New |
bodyIndex |
Int | no | Explicit signed Body identity; overrides body name |
name |
String | no | Name for a New Body, such as Base or Lid; same Undo step |
revolve
Turn one open profile by degrees about an axis line in its sketch (default the sketch's vertical axis through its origin), using New/Add/Cut; name names it in the same Undo step.
-
Use when: a rotational shape where it belongs: axis {point:[x,y],direction:[x,y]} in sketch mm. An upright part centred at world (X,Y): sketch on right at offset X (outward 1), draw the half-section from sketch x = Y outward, axis {point:[Y,0],direction:[0,1]}.
-
Don't: a profile that crosses the axis, or Body-target parameters; verify resulting positive-space and Z0 placement.
-
Returns: features, bounds and volume, or a profile/operation refusal.
-
Called as:
edit {tool: "revolve", args: "{…}"}
| Argument | Type | Required | Meaning |
|---|---|---|---|
degrees |
Double | yes | Angle in degrees, 360 for a full turn |
profile |
Int | no | Open profile index; default the newest |
op |
String | no | new, add or cut |
name |
String | no | Name for a New Body, such as Wheel; same Undo step |
axis |
RevolveAxisArgs | no | The line to turn about, in the profile's sketch coordinates; default the sketch's vertical axis through its origin |
loft
Create or replace an editable solid joining 2–32 changing convex sections, straight or around a bend (one arc, or a turn per section); New, targeted Add or Cut.
-
Use when: For changing grips, domes, tapered transitions and hull forms use aligned ellipses [centre u,centre v,radius u,radius v], or 3–128 convex polygon vertices, either winding, with the same count and corner correspondence in each section. Offsets strictly increase along Top +Z, Front -Y or Right +X; keep the complete result in positive XYZ and rest a new printable Body on Z0; an Add may overshoot below Z0 while building if a Cut in the same Body trims it flush, because the finished Body is what's judged. New takes name; Add/Cut take body (the Body's name, such as Housing) or bodyIndex. Replace sections by feature/index, or edit the span. Inspect returns saved section dimensions. For a Top loft, use shell before details for a linked minimum-wall cavity with top/bottom opening. Sections may change shape and shift (an ellipse to an offset circle for a duct): each span joins as the convex solid between its two sections. For a continuous curved passage use bend (0 or ±0.1–170 degrees): offsets are arc stations, sections share a centre and matching corners, and each section turns normal to the centreline in the plane u/normal directions: one circular arc, or give sections their own turn (degrees since the previous section, adding up to bend) for a bend of tangent arcs and straight runs, each slab with its own radius. The first centre anchors the path. Conventions: each plane's u, v and normal in world axes: top u +X, v +Y, normal +Z; front u +X, v +Z, normal −Y; right u +Y, v +Z, normal +X. A section's u, v and offset are measured from the feature's datum (from the origin without one), so with a datum at the start no sign flips; offsets strictly increase along the normal, and on a bent path each offset is the distance along the centreline. bendDirection (bend_direction in a part step) is the way the path leans and turns in the plane, degrees from +u toward +v: 0 is +u, 90 is +v. startAngle (start_angle) is how far the path already leans from the normal toward bendDirection at the first section; negative leans the other way. bend is the whole turn: positive turns further toward bendDirection, negative back toward the normal and past it, so the last section heads startAngle + bend from the normal toward bendDirection. Worked example, a jet intake on right (the water runs +X, aft; bendDirection 90 is up) from a hull mouth, ramping 18° up, onto a pump axis tilted 6° down aft: startAngle 18, bend -(18 + 6) = -24, the sections' turns 0 then -24, so it rises 18° for 40 mm, then turns on R 78 to head 6° below +X: {"name":"Jet intake","roles":["Intake"],"parameters":[{"name":"ramp","expression":"18"},{"name":"tilt","expression":"6"},{"name":"r","expression":"78"}],"datums":[{"name":"mouth","position":["40","30","0"]}],"features":[{"name":"Water","body":"Intake","op":"new","plane":"right","datum":"mouth","startAngle":"ramp","bendDirection":"90","bend":"-(ramp+tilt)","sections":[{"offset":"0","ellipse":["0","0","13","13"]},{"offset":"40","turn":"0","ellipse":["0","0","13","13"]},{"offset":"40+r*(ramp+tilt)pi/180","turn":"-(ramp+tilt)","ellipse":["0","0","13","13"]}]}],"clearances":[],"requirements":[]}. Its centreline ends at mouth + [40cos(18) + 78*(sin(18) + sin(6)), 0, 40sin(18) + 78(cos(6) - cos(18))] = mouth + [70.30, 0.00, 15.75]: put the pump axis datum there with direction [cos(6), 0, -sin(6)], written as those expressions. So a water intake leaves the hull as a ramp under about 30°, runs straight, then turns one arc onto the pump axis at a centreline radius of at least 1.5 × the hydraulic diameter, and measure {passage} reads it. Set span before bend. A bend has no twist. Use New for a solid envelope and a smaller matching bent Cut reaching both ports for a water passage. A section offset alone does not guarantee 3D wall thickness: measure the walls and actual obstructions. The bend result reports nominal centreline/inside radius and smallest control section, not CFD or installed free area. For impeller or propeller blades, augers and twisted forms give twist (degrees, -360 to 360, first to last section, counter-clockwise seen along the normal) and twist_center [u,v] (the hub's axis): loft each blade as an Add to the hub with the same twist, its sections turned about the hub (120° apart for three blades).
-
Don't: cut a round bore or bearing seat (hole, kind counterbore, is one call) or add a plain cylinder; claim smooth splines, concave sections, automatic constant wall thickness, loft edge fillets or STEP export, or fake a twist with stacked thin slabs. Transitions are straight; add intermediate sections for curvature. Shell can't hollow a twisted or bent loft. A Cut needs to extend through the intended opening; review floor and wall clearance independently. An Add must overlap its Body: add the piece that joins first.
-
Returns: One editable History feature and stable Body identity, atomic failure on invalid geometry or broken descendants. Ordinary Add/Cut/Holes, assembly, STL and 3MF operate on the resulting solid.
-
Called as:
edit {tool: "loft", args: "{…}"}
| Argument | Type | Required | Meaning |
|---|---|---|---|
feature |
String | no | Existing Loft feature name to replace; omit for new |
index |
Int | no | Existing Loft feature index to replace |
plane |
String | no | Parallel section plane: Top XY/+Z, Front XZ/-Y, Right YZ/+X |
sections |
[LoftSectionArgs] | no | 2–32 ordered convex sections. Replace the full section list when editing; aligned ellipses are compact for grips, domes and changing forms |
op |
String | no | new (default), add or cut. Add/Cut require explicit existing bodyIndex; immutable on edit |
bodyIndex |
Int | no | Explicit signed target Body ID for Add/Cut; omit for New |
twist |
Double | no | Degrees the sections turn from first to last, -360 to 360, counter-clockwise seen along the normal (twisted blades, augers); needs twistCenter |
twistCenter |
[Double] | no | [u, v] in mm: the axis twisted sections turn about, such as the hub centre |
bend |
Double | no | Total centreline bend in degrees: 0 straight, or ±0.1–170; one even arc, or the sum of the sections' turns. Offsets are arc stations; centred matching sections turn normal to the curve. No simultaneous twist |
startAngle |
Double | no | Degrees the centreline already leans from the plane normal at the first section, toward bendDirection, -170 to 170; sections stay square to the path, so a ramp leaves its plane at a slant |
bendDirection |
Double | no | Which way the path leans and bends: degrees in the plane from +u toward +v, default 0 (+u); 90 is +v |
name |
String | no | Name the new feature in the same Undo step |
construction
Build an authored, parameter-linked native construction from shared datums and changing sections; no fixed product template.
-
Use when: draft saves plan once with roles, parameters, datums and optional skeleton; features may be empty. Later calls send only what changed: a draft with instance_id, expected_revision and patch rows, each {parameter, datum, port, passage or zone: its row} to add or replace it by name, or {remove: kind, name} to drop one (a port as Role.name); every row a patch doesn't name stays as saved. features replaces one unbuilt part's list. Skeleton edits preserve every input and its full range. The layout stays revisable: write datums from parameters, build the first piece now, and move the layout later with update, which rebuilds built parts and re-places the parts mated to them. After a part is built a draft may add parameters, datums, ports and unbuilt parts' features, but never moves built geometry. Inspect lists saved plans/revisions. layout/preview/insert may also take plan {name,parameters:[{name,expression}],datums:[{name,position:[x,y,z expressions],optional direction [x,y,z], numbers or expressions}],features,clearances,requirements, optional skeleton, optional ports [{name,role,kind,datum,toward or axis [x,y,z], numbers or expressions}], optional passages [{name,inlet,outlet,through:[],parts:[roles],flow_l_min}] (stations are Role.portName or a datum name; for water, declare the ports and one passage through them right after planning, e.g. ports [{name:"in",role:"housing",kind:"passage_port",datum:"intake",toward:"pump"},{name:"out",role:"housing",kind:"passage_port",datum:"pump",axis:[1,0,0]}] and passages [{name:"water",inlet:"housing.in",outlet:"housing.out",through:[],parts:["housing"]}]), optional zones [{name,min:[x,y,z expressions],max}], world boxes round real mounts, seats and bosses, where the wall round a passage isn't judged}. The first role (or the skeleton's ground) is the ground: built where it is drawn, on the origin, never mated onto another part; every datum is one of its ports (Palm.drive_axis): an axis with a direction, a plain datum (+Z up) any port may sit on without. Feature/clearance rows have name, body role, op new/add/cut, plane top/front/right, optional datum, sections and optional bend (0 straight, or ±0.1–170), startAngle (-170 to 170) and bendDirection, expressions in degrees as Loft's Bend, Start angle and Bend direction; a bent path's sections stay centred with matching corners. One circular arc, or give sections a turn expression (degrees since the previous section, 0 for a straight run) for tangent arcs and straight runs whose bend defaults to their total. Construction has no twist or spline path: use loft directly for twisted blades. Sections have offset expression plus exactly one ellipse [u,v,ru,rv], roundedRectangle [u,v,width,height,radius], or convex points in either winding; all dimensions are expression strings. Reuse named variables and datum_x/y/z instead of repeating coordinates. Expressions take sqrt, abs, sin, cos, tan, asin, acos, atan, atan2(y, x), hypot, min and max, angles in degrees: write a derived position as an expression (e.g. [0, -dcos(tilt), h + dsin(tilt)]), never a decimal worked out by hand; every reply echoes the resolved datums and parameters in mm. Retained limits are {name,expression,minimum,maximum}. Final empty volumes use op cut and a body role, or * for all native bodies. Optional skeleton {ground,hinges,balls,inputs}: hinges {name,a,b,datum,axis,diameter,spanA,spanB, optional equal_to naming another hinge this one turns equally with (a differential's outputs; neither is then a free input)}, balls {name,a,b,datum}, inputs {joint,body,range}; before the joints exist give the ground alone with empty hinges, balls and inputs. Body references are roles, joint positions share geometry datums; unit axis is numbers or expressions, diameter/spans are expressions, input ranges fixed radians. layout samples ideal joint closure before solid evaluation. preview checks geometry too without editing. Insert requires part with exactly one body role for a multi-part plan; first insert takes plan, subsequent insert calls use instance_id and part, and may carry expected_revision and patch rows for the datums and ports that part needs, saved before it builds: no draft call first. Each part is a separate visible Undo entry. Pending parts have no saved geometry. update uses instance_id plus parameters [{name,expression}], rebuilding only already-built owned geometry; once complete, owned joints follow too. IDs, requirements and input ranges persist. Cases: bound connector-height cuts to declared plug envelopes; preserve floor, upper bridges and lid seat. Derive lid contour, inset and seat from the same shell datums and inspect closed fit. For an approved whole-Part replacement, save a complete new draft, call construction {action: rebuild_preview, instance_id}, explain its concrete consequences, and apply the exact assembly {action: change_accept} ticket only after approval. Purchased components and their world poses persist; native geometry, sketches and setups are replaced in one undo step. Native detail is preserved when inserting another part; regeneration refuses to overwrite native edits. check validates current geometry/declared voids and ideal closure. New bodies are lowered to Z0 for fabrication and placed back at design height in assembly. Conventions: each plane's u, v and normal in world axes: top u +X, v +Y, normal +Z; front u +X, v +Z, normal −Y; right u +Y, v +Z, normal +X. A section's u, v and offset are measured from the feature's datum (from the origin without one), so with a datum at the start no sign flips; offsets strictly increase along the normal, and on a bent path each offset is the distance along the centreline. bendDirection (bend_direction in a part step) is the way the path leans and turns in the plane, degrees from +u toward +v: 0 is +u, 90 is +v. startAngle (start_angle) is how far the path already leans from the normal toward bendDirection at the first section; negative leans the other way. bend is the whole turn: positive turns further toward bendDirection, negative back toward the normal and past it, so the last section heads startAngle + bend from the normal toward bendDirection. Worked example, a jet intake on right (the water runs +X, aft; bendDirection 90 is up) from a hull mouth, ramping 18° up, onto a pump axis tilted 6° down aft: startAngle 18, bend -(18 + 6) = -24, the sections' turns 0 then -24, so it rises 18° for 40 mm, then turns on R 78 to head 6° below +X: {"name":"Jet intake","roles":["Intake"],"parameters":[{"name":"ramp","expression":"18"},{"name":"tilt","expression":"6"},{"name":"r","expression":"78"}],"datums":[{"name":"mouth","position":["40","30","0"]}],"features":[{"name":"Water","body":"Intake","op":"new","plane":"right","datum":"mouth","startAngle":"ramp","bendDirection":"90","bend":"-(ramp+tilt)","sections":[{"offset":"0","ellipse":["0","0","13","13"]},{"offset":"40","turn":"0","ellipse":["0","0","13","13"]},{"offset":"40+r*(ramp+tilt)pi/180","turn":"-(ramp+tilt)","ellipse":["0","0","13","13"]}]}],"clearances":[],"requirements":[]}. Its centreline ends at mouth + [40cos(18) + 78*(sin(18) + sin(6)), 0, 40sin(18) + 78(cos(6) - cos(18))] = mouth + [70.30, 0.00, 15.75]: put the pump axis datum there with direction [cos(6), 0, -sin(6)], written as those expressions.
-
Don't: Treat this as an automatic designer or motion solver; force an object into a fixed sample; claim full clearance from undeclared volumes; silently change requirements; regenerate over native edits or external dependants. Use ordinary CAD for unsupported geometry. Convex sections are sampled straight or tangent-arc bend transitions, not arbitrary splines or automatic root fillets.
-
Returns: Optional wheelbase_mm, steering_lock_deg, wheel_travel_mm and track_mm measure ideal outputs even in a layout with pending roles. Preview also samples planned-body interference before insertion; hardware remains separate. Saved editable native features, pending_parts and construction_complete (geometry only), stable body IDs, resolved dimensions/datums, per-body volumes and final clearance results. Failed preview/insert/update changes nothing. Use look, component_check and mechanism/check_motion separately; geometric acceptance is not strength or physical fit.
-
Called as:
plan {construction: {…}}
| Argument | Type | Required | Meaning |
|---|---|---|---|
track_mm |
Double | no | Requested wheel-centre track, wheelbase, inner lock and independent suspension travel can be checked in the ideal layout before pending parts are built |
wheelbase_mm |
Double | no | |
steering_lock_deg |
Double | no | |
wheel_travel_mm |
Double | no | |
action |
String | yes | draft saves/edits without geometry; layout checks ideal joints; inspect/check/preview read only; rebuild_preview validates a complete new draft replacing all native geometry, preserving purchased components, then issues an approval ticket; insert builds one part; update rebuilds built parts; starter lays out a known pattern in an empty Part, as Insert does (its skeleton draft and ground) from parameters by name |
starter |
String | no | starter only: water_jet takes parameters pump_height (where the pump axis crosses the transom, mm), tilt, ramp (degrees), bend_radius and bore (mm) |
plan |
ConstructionPlanArgs | no | Supply once to create a draft with roles/datums/joints and empty features. Use instance_id thereafter |
instance_id |
String | no | Saved construction UUID for subsequent part insertions, inspect/check/update or update preview |
part |
String | no | Exact body role to build. Insert creates only this part; required for every multi-part plan. Preview may also select one part |
parameters |
[ConstructionParameterArgs] | no | Named parameter expression changes for update or update preview; already built geometry follows, pending parts remain unbuilt |
expected_revision |
Int | no | Required for editing an existing draft or an insert with patch; use the last returned revision |
datums |
[ConstructionDatumArgs] | no | draft only: add named datums; existing ones can be replaced only before any part is built |
features |
[ConstructionShapeArgs] | no | draft only: replace the complete feature list of one unbuilt part, beginning with its new feature. Other parts stay unchanged |
skeleton |
ConstructionSkeletonArgs | no | draft only: add or revise joints, before parts are built or while some are still unbuilt, preserving all existing input roles and ranges. A design that moves needs its joints before any part is built |
ports |
[ConstructionPortArgs] | no | draft only: replace the complete list of planned ports (same fields as plan.ports) |
passages |
[ConstructionPassageArgs] | no | draft only: replace the complete list of passages (same fields as plan.passages) |
zones |
[ConstructionZoneArgs] | no | draft only: replace the complete list of zones (same fields as plan.zones) |
patch |
[ConstructionPatchArgs] | no | draft edit or insert, instead of the whole lists: rows that each add or replace one parameter, datum, port, passage or zone by name, or remove one; every row not named stays as saved. An insert saves them, then builds |
shell
Hollow an original upward Top extrusion, Top loft or Gear, opening top or bottom. Wall is a minimum against sides and the closed cap; loft transitions may retain extra material.
-
Use when: before posts, cuts or holes; bottom opens a shaped cover underneath. The cavity follows source section/outline and height edits. Edit Shell by feature/index and changed thickness/opening.
-
Don't: claim a constant-wall offset on a loft, assume usable interior clearance without inspecting it, or hollow imported/copied/split Bodies. A wall edit also changes the closed cap.
-
Returns: minimum wall, opening, features and volume, or an atomic collapsed-cavity/dependency refusal.
-
Called as:
edit {tool: "shell", args: "{…}"}
| Argument | Type | Required | Meaning |
|---|---|---|---|
wall |
Double | no | Minimum wall and closed-cap thickness in mm; loft transitions may retain extra material. Defaults to the project minimum, otherwise 2 mm |
open |
String | no | Face to leave open; bottom makes a cover with its opening underneath |
body |
String | no | Name of the original extrusion, Top loft or Gear Body from inspect; omit when the Part has one Body |
feature |
String | no | Edit this Shell feature by its name from inspect; supply only the values to change |
index |
Int | no | Edit Shell at this zero-based feature index; takes precedence over feature name |
bodyIndex |
Int | no | Explicit signed Body identity; takes precedence over body name. Shell before modifiers on an original upward Top extrusion, Top loft or Gear |
enclosure
Build a real editable rounded housing and removable lid, or coordinate a saved enclosure's width or depth using assembly_id and exactly one absolute dimension. Preserves one central lid through-hole vent at fixed size and edge offsets; other recipe edits refuse.
-
Use when: create a curved open housing and separate locating lid with outside dimensions, wall/floor, cornerRadius, lidThickness, lipHeight, clearance and optional screwBosses. To resize a saved recipe with at most one central lid vent feature, use assembly_id from inspect.enclosure_recipes and exactly one absolute width or depth in mm; all other parameters stay fixed. Creation defaults apply only when assembly_id is omitted. For a new rounded electronics case with a removable locating lid, use enclosure when its supported construction fits the request. It creates an actual curved housing, open cavity and separate lid as ordinary editable features, with optional four wall-fused screw bosses. Defaults are width80, depth50, housing height28, wall/floor2.4, cornerRadius10, lidThickness2.4, lipHeight3 and per-side clearance0.3 mm. Height excludes the lid plate; assembled height is height plus lidThickness. Both pieces print on Z0 beside one another; the lip prints upward and the lid flips over for assembly. It saves an Enclosure assembly with Housing and Lid occurrences and the closed lid placement. The returned view stays assembly; choose the Housing or Lid authoring owner before geometry edits. The lip has corner reliefs for the bosses and is not a seal. screwBosses defaults true and uses the catalogue's sourced M3×3 heat inserts, 4.1 mm pockets (0.1 mm explicit diametral compensation) and 3.4 mm lid clearance bores; calibrate by coupon before claiming a fitted case. origin is optional nonnegative [x,y]; omit it for automatic placement beside existing solids. Review cavity, lid clearance, bores and access, then add requested ports or specific interfaces with targeted tools. Do not use the recipe for unrelated parts or claim a global parameter link. For a saved enclosure recipe, inspect its enclosure_recipes entry and call enclosure with assembly_id and exactly one absolute width or depth to coordinate that dimension. One appended simple through-hole vent from the lid underside is preserved at the same size and left/bottom offsets if clear of the lip and screw supports. Other edits or dependencies require ordinary feature edits; a refused resize changes nothing. Never create a replacement enclosure to resize one.
-
Don't: use for unrelated parts, guess fit-critical hardware, promise a seal or globally linked parameters, or claim nominal insert pockets or 3.4 mm lid bores establish calibrated print fit. The boss-relieved locating lip is interrupted. Ask for missing hardware dimensions before fitting a specific product.
-
Returns: ordinary editable features and stable Housing/Lid occurrences, two printable Bodies on Z0, closed assembly placement and one undo step. Width or depth edits coordinate the housing, lid, lip, bosses, holes and insert references. Unsupported recipe edits or dependencies refuse without changes; this is not a general parameter system.
-
Called as:
edit {tool: "enclosure", args: "{…}"}
| Argument | Type | Required | Meaning |
|---|---|---|---|
assembly_id |
String | no | Existing enclosure assembly UUID from inspect. With this, supply exactly one width or depth (absolute mm) to coordinate a saved recipe, optionally with one central lid through-hole vent; omit to create an enclosure |
width |
Double | no | Outside X width in mm; default 80 |
depth |
Double | no | Outside Y depth in mm; default 50 |
height |
Double | no | Outside housing height excluding the lid plate, in mm; default 28. Assembled height adds lidThickness |
wall |
Double | no | Uniform housing wall and floor thickness in mm; default 2.4 |
cornerRadius |
Double | no | Rounded main-outline corner radius in mm; default 10 |
lidThickness |
Double | no | Separate lid plate thickness in mm; default 2.4 |
lipHeight |
Double | no | Locating lip height in mm; default 3. The lip has boss clearances and is not a seal |
clearance |
Double | no | Per-side lip clearance in mm; default 0.3. A fabrication assumption until test printed |
screwBosses |
Bool | no | Add four wall-fused screw bosses and matching lid holes; default true. Uses the catalogue's M3×3 heat-set inserts, 4.1 mm installation pockets and 3.4 mm lid clearance. Calibrate the explicit 0.1 mm compensation |
origin |
[Double] | no | Optional housing lower-left print origin [x,y] in nonnegative mm, Z0. Omit to place beside existing solids automatically |
heat_insert
Plan, install and recheck a sourced metric heat-set insert with a real editable pocket and purchased reference.
-
Use when: Search catalog for heat set insert; select exact id. plan requires explicit diametral hole_compensation_mm, screw_length_mm, clamped_thickness_mm, tool_diameter_mm and tool_reach_mm. apply also requires plane/offset/outward, center [u,v], bodyIndex. Custom metric variants require all dimensions and source_url. check reviews saved pockets after edits.
-
Don't: ordinary machine screws threaded directly into printed plastic; guessing an insert by thread size; reducing sourced wall, burying heads, leaving protruding tips or calling an inaccessible installation acceptable. Use purchased metal threads, heat inserts or captive nuts. Supplier-prescribed screws in purchased servo cases remain supplier-specific.
-
Returns: Plan dimensions or one atomic pocket/reference insertion, checked for continuous wall, floor, screw depth, nearby Bodies and tool approach. Choices and source persist with the feature. Full-length engagement and clearance policies are geometric checks, not physical strength certification. Install before obstructing mating parts; inspect assembled travel separately.
-
Called as:
edit {tool: "heat_insert", args: "{…}"}
| Argument | Type | Required | Meaning |
|---|---|---|---|
instance |
String | no | For replan: exact existing insert component instance. Supply new screw_length_mm and clamped_thickness_mm; preserves fit/process settings and refuses unsafe pocket changes atomically |
action |
String | no | plan computes sizes; apply cuts/places; replan updates an existing insert for a changed screw/stack atomically; check reviews saved pockets |
id |
String | no | Exact heatset.* variant ID from catalog; never a generic M3 size |
custom_name |
String | no | Custom variant only: a standard name such as M3 × 6 heat-set insert, never a brand; omit with id |
source_url |
String | no | Custom variant only: source drawing URL; supplied dimensions remain unverified |
thread_mm |
Double | no | |
pitch_mm |
Double | no | |
length_mm |
Double | no | |
outside_diameter_mm |
Double | no | |
nominal_hole_mm |
Double | no | |
minimum_wall_mm |
Double | no | |
hole_compensation_mm |
Double | no | Required explicit diametral compensation added ONCE to nominal installation hole; 0 keeps nominal. Calibrate by coupon |
wall_mm |
Double | no | Wall from insert knurl envelope; at least manufacturer minimum. Omit to use sourced minimum |
floor_mm |
Double | no | Material below blind pocket; at least 1.2 mm, default 1.5 |
screw_length_mm |
Double | no | Required screw length under its head, in mm |
clamped_thickness_mm |
Double | no | Required actual distance from under-head seating plane to insert mouth, including washers and recesses |
tip_gap_mm |
Double | no | Gap beyond screw tip, minimum 0.5, default 1 mm |
tool_diameter_mm |
Double | no | Required heated tool maximum diameter over the approach length, at least insert OD |
tool_reach_mm |
Double | no | Required unobstructed heated-tool approach length |
clearance_mm |
Double | no | Gap to neighbouring bodies/tool, minimum 0.2, default 0.5 mm |
plane |
String | no | Apply only: top, front or right |
offset |
Double | no | |
outward |
Double | no | Apply only: outward face normal +1 or -1 |
center |
[Double] | no | Apply only: one center [u,v] in face coordinates |
bodyIndex |
Int | no | Apply only: explicit signed Body identity from inspect |
fillet
Round or 45-degree chamfer supported extrusion side/top/base/all edges, optionally scoped to feature names/featureIndices.
-
Use when: an edge-group treatment as the last step, after holes and cuts; inspect applied radius because requested sizes may be clamped.
-
Don't: change another extrusion or promise arbitrary topology; Shell supports side rounds, not top/base rounds. Use point for a checked single pinned edge.
-
Returns: actual radius_applied and geometry summary, or a refusal. dependent_feature_failure identifies newly broken features; changed:false means nothing was saved, so do not undo.
-
Called as:
edit {tool: "fillet", args: "{…}"}
| Argument | Type | Required | Meaning |
|---|---|---|---|
edges |
String | yes | sides (the vertical edges), top, base or all |
radius |
Double | yes | Radius (or chamfer size) in mm; clamped to what fits |
feature |
[String] | no | Only these extrusions' edges, by name from inspect's features ("Extrude 2"); default every extrusion |
chamfer |
Bool | no | true for a flat 45° chamfer instead of a round |
featureIndices |
[Int] | no | Only extrusions at these zero-based indices in inspect's features; takes precedence over feature |
hole
Create or edit one Holes feature on a planar face using centres or sketch-circle profiles, bore/preset and optional head recess.
-
Use when: simple, counterbore or countersink fastener bores, and bearing seats in one call: kind counterbore, head_diameter the bearing's outside diameter plus its fit, head_depth its width, diameter the shaft clearance, through; through follows Body height, depth is blind; edit by feature/index with only changed fields.
-
Don't: put a screw where a straight tool can't reach its head (a countersunk or counterbored head needs about 100 mm of straight room for a screwdriver; under 40 mm none fits), face heads into a closed frame, use blind holes through a plate, confuse feature index with bodyIndex, assume insert presets fit every manufacturer, or use a round bore for an arbitrary slot.
-
Returns: applied sizes, editable feature list, geometry summary and per-hole mouth_open, tool_clearance_mm, breaks_through and min_wall_mm with hole_warnings.
-
Called as:
edit {tool: "hole", args: "{…}"}
| Argument | Type | Required | Meaning |
|---|---|---|---|
feature |
String | no | Edit this existing Holes feature by name from inspect, instead of making a new one; only supply the values to change |
plane |
String | no | Drill on a flat face: top (XY), front (XZ) or right (YZ) |
offset |
Double | no | Face's distance along the plane normal, in mm |
outward |
Double | no | Face looks along the plane normal (1) or against it (-1) |
centers |
[[Double]] | no | Hole centres as pairs of face coordinates in mm; use profiles instead to take circle centres from a sketch |
profiles |
[Int] | no | Circular sketch profile indices whose centres locate the holes |
preset |
String | no | M2.5 clearance or M3 clearance. For threaded retention in printed plastic use heat_insert instead of a pilot or hole-only insert preset |
diameter |
Double | no | Bore diameter in mm; overrides the preset |
through |
Bool | no | true drills through the target Body, following height edits; false drills to depth |
depth |
Double | no | Blind depth in mm. Supplying depth selects a blind hole unless through is true |
kind |
String | no | simple, counterbore (flat head recess) or countersink (conical head recess) |
head_diameter |
Double | no | Head recess diameter in mm |
head_depth |
Double | no | Head recess depth in mm; countersink angle follows diameter and depth |
body |
String | no | Target Body name from inspect, such as Base or Lid piece; otherwise inferred from the first centre's face |
bodyIndex |
Int | no | Explicit signed Body identity; takes precedence over body name |
index |
Int | no | Edit the Holes feature at this zero-based index in inspect's features; takes precedence over feature |
split
Divide one Body by origin plane, distance below top, or a swept finished face-sketch outline into two independent Bodies.
-
Use when: dividing the same existing Body; distinguish from_top distance from world-plane offset and re-inspect resulting signed IDs.
-
Don't: replace a requested split with an unrelated second solid; sketch offset expands the actual outline, not its bounding box.
-
Returns: one editable Split and a new piece beside +X on Z0; shell before Split.
-
Called as:
edit {tool: "split", args: "{…}"}
| Argument | Type | Required | Meaning |
|---|---|---|---|
body |
String | no | Body name from inspect's bodies, e.g. Base or Split piece; omit only for a single Body |
plane |
String | no | Origin plane: top, front or right; defaults top |
offset |
Double | no | Distance in mm: below top when from_top is true, origin-plane coordinate otherwise; with sketch expands its outline (zero keeps the drawn shape) |
from_top |
Bool | no | true stores a distance below the Body top and follows height edits; false uses the origin-plane coordinate. Default true for top |
sketch |
String | no | Name of a finished face sketch with one unused closed outline; sweeps its drawn shape through the Body, keeping inside and outside as two pieces |
feature |
String | no | Edit an existing Split feature by its History name |
index |
Int | no | Explicit zero-based feature index to edit; overrides feature name |
bodyIndex |
Int | no | Explicit signed Body identity; overrides body name |
sketchIndex |
Int | no | Explicit zero-based face-sketch feature index; overrides sketch name |
gear
Create or edit a native external involute spur gear: fixed 20° pressure angle, zero shift, 10–120 teeth, module 0.5–4 mm, Z0.
-
Use when: rounded toothed mechanisms need real gears; place a train's shafts in its space first with design_recipe {action: layout}. It refuses while a sketch is open: make it before sketching or after that sketch's extrude. New requires teeth/module/thickness/center [x,y], with an optional name; bore is diameter, phase degrees CCW from +X. Edit by feature/index with changed fields only. A flat Z0 crank Add starts on the Top origin plane without offset/outward, not a face with overlap below the bed.
-
Don't: invent internal, helical, bevel, shift or arbitrary pressure-angle options; pattern a Gear source; mistake no collision for engagement or claim printed function without a coupon. Mate at module*(z1+z2)/2 with same module and opposing rotation; per-gear backlash is tangential tooth thinning, pair sum.
-
Returns: one editable named History feature, stable signed Body ID, gear dimensions and solid summary; use ordinary targeted Add/Cut/Holes for bosses and crank arms, and inspect/look/measure to verify.
-
Called as:
edit {tool: "gear", args: "{…}"}
| Argument | Type | Required | Meaning |
|---|---|---|---|
feature |
String | no | Edit an existing Gear feature by name from inspect; omit for a new gear |
index |
Int | no | Explicit zero-based Gear feature index to edit; overrides feature name |
teeth |
Int | no | Integer 10–120 teeth; required for a new gear |
module |
Double | no | Module in mm, 0.5–4; mating gears MUST use the same module; required for new |
thickness |
Double | no | Axial face width in mm, 0.5–30; bottom always Z0; required for new |
bore |
Double | no | Round bore DIAMETER in mm, zero for solid; leave at least 1.6 mm material at root |
backlash |
Double | no | THIS gear's tangential tooth thinning at pitch circle in mm, default 0.05; pair backlash is sum, maximum 0.25*module |
center |
[Double] | no | Centre [x,y] in mm; each >= module*(teeth/2+1), keeping complete gear positive XY; required for new |
phase |
Double | no | Tooth-centre phase in degrees CCW from +X, default 0; equal even-tooth pairs mesh with a half-tooth follower offset at standard spacing |
name |
String | no | Name for a new gear, such as Drive gear; same Undo step |
storage
Create or edit a Gridfinity bin, baseplate or receiver cut, or an openGrid board, snap or socket cut: one editable History feature made to the published dimensions.
-
Use when: a maker wants modular storage: a bin (units_x × units_y cells of 42 mm, height_units of 7 mm, lip, magnets, screws, dividers_x/dividers_y), a baseplate (magnets adds a floor), an openGrid board (28 mm cells, lite for the 4 mm board), a snap (one, lite for 3.4 mm), or a receiver/socket cut down into a Body's flat top face so bins or snaps fit their own part (body or bodyIndex from inspect; origin [x,y,z] is the footprint's lower corner on that face). New pieces start on Z 0 at origin [x,y], beside other Bodies by default. Edit by feature/index with changed fields only.
-
Don't: scale or reshape the system's interface by hand, invent other systems (Multiboard, labels, scoops), or cut a receiver into a face thinner than its depth (4.75 mm Gridfinity, 6.8 or 4 mm openGrid).
-
Returns: one named History feature with its spec and Body ID, or a refusal naming the size, face or overlap to fix with nothing changed; inspect/measure to verify.
-
Called as:
edit {tool: "storage", args: "{…}"}
| Argument | Type | Required | Meaning |
|---|---|---|---|
feature |
String | no | Edit an existing storage feature by name from inspect; omit for a new piece |
index |
Int | no | Explicit zero-based storage feature index to edit; overrides feature name |
kind |
String | no | What to make; required for a new piece |
units_x |
Int | no | Cells along X: Gridfinity 42 mm, openGrid 28 mm; 1–8 (openGrid 1–10) |
units_y |
Int | no | Cells along Y |
height_units |
Int | no | Gridfinity bin height in 7 mm units, 2–20, lip excluded |
lip |
Bool | no | Bin stacking lip, default true |
magnets |
Bool | no | 6 × 2 mm magnet pockets under bin feet, or a magnet baseplate |
screws |
Bool | no | M3 screw holes up into bin feet |
dividers_x |
Int | no | Bin divider walls across X, 0–9 |
dividers_y |
Int | no | Bin divider walls across Y, 0–9 |
lite |
Bool | no | openGrid lite: 4 mm board, 3.4 mm snap, 4 mm socket |
origin |
[Double] | no | Footprint's lower corner [x,y] mm on Z 0; for a receiver or socket [x,y,z] on the Body's top face |
body |
String | no | Receiver or socket: the Body name to cut into |
bodyIndex |
Int | no | Receiver or socket: the signed Body identity from inspect |
name |
String | no | Name for a new piece; same Undo step |
cycloidal_stage
Declare or edit the one supported balanced dual-disc, difference-of-one cycloidal reducer stage from existing native Bodies.
-
Use when: after inspect confirms a housing/ring, input with opposed eccentric journals, two native cycloidal discs, one shared output carrier and any stack hardware. Body identities and assembly centres/Z layers must be explicit.
-
Don't: create serial stages, use a single disc, request profile modification or a tooth-count difference other than one, invent absent Body geometry, or claim load capacity from the declaration.
-
Returns: one atomically saved editable stage declaration; use check_reducer for actual-solid motion, fit, balance and engineering evidence.
-
Called as:
edit {tool: "cycloidal_stage", args: "{…}"}
| Argument | Type | Required | Meaning |
|---|---|---|---|
id |
String | no | Short stable name; omit to keep the saved name or use balanced-stage |
housingBody |
Int | no | Signed housing/ring Body identity from inspect |
inputBody |
Int | no | Signed common input/shaft Body identity with both eccentric journals |
discABody |
Int | no | Signed native Cycloidal Disc A Body identity |
discBBody |
Int | no | Signed native Cycloidal Disc B Body identity |
carrierBody |
Int | no | Signed shared output carrier Body identity |
center |
[Double] | no | Common assembled axis [x,y] in mm |
housingCenter |
[Double] | no | Housing's saved print-layout axis [x,y] in mm |
inputCenter |
[Double] | no | Input's saved print-layout axis [x,y] in mm |
carrierCenter |
[Double] | no | Carrier's saved print-layout axis [x,y] in mm |
eccentricBearingDiameter |
Double | no | Eccentric bearing/journal diameter in mm |
outputPinCount |
Int | no | Installed shared output-pin count, at least 3 |
outputPinCircle |
Double | no | Output-pin pitch-circle radius in mm |
outputPinDiameter |
Double | no | Output-pin diameter in mm |
outputHoleDiameter |
Double | no | Disc output-hole diameter in mm |
maximumProfileClearance |
Double | no | Maximum accepted profile clearance in mm |
maximumOutputRadialClearance |
Double | no | Maximum accepted output radial clearance beyond eccentric travel in mm |
discAZMin |
Double | no | Disc A assembled lower Z in mm |
discBZMin |
Double | no | Disc B assembled lower Z in mm |
discADensity |
Double | no | Disc A material density in a consistent unit |
discBDensity |
Double | no | Disc B material density in the same unit |
maximumBalanceResidual |
Double | no | Maximum eccentric mass-moment residual in density-volume-mm units |
stackBodies |
[CycloidalStackBodyArgs] | no | Every additional stack Body/interface; omit for none |
engineering |
CycloidalEngineeringArgs | no | Optional declared quasi-static evidence. Missing values remain not-rated |
reductionLayout |
String | no | Must be single; serial/multi-stage is refused |
toothCountDifference |
Int | no | Must be 1; other difference counts are unsupported |
profileModification |
String | no | Must be none; modified profiles are unsupported |
component
Place a bought part from one exact catalogue entry where it goes (its mate block, in the same call), move, route a supported open belt, show, hide or remove it.
-
Use when: place with catalog_id, its required parameters and a mate block, one call per part: component {action: place, catalog_id: bearing.mr63, mate: {port: outer_race, to_part: Case, to_port: bearing_seat}} (or to_point [x,y,z] on the partner instead of to_port). Only the ground (the hull patch, a wall) takes a fixed origin. There is no typed target frame: a position worked out from datums is a mate to that datum or planned port. Move a placed part to a new origin/rotation (it keeps its instance id, so checks and mounts that name it still find it; never remove and re-place just to turn it), place with replaces to swap one part for another so earlier checks follow it, or route_belt after placing exact GT2 6 mm belt stock, 20-tooth GT2 pulley and 40-tooth GT2 idler. Routing requires clamp_center, clamp_gap_mm, minimum_clamp_engagement_mm, clamp_capacity_each_mm and tangent_clearance_mm as explicit learner design inputs. It checks exact pitch-arc length and tail capacity, not retention, tension or strength.
-
Don't: type a world position or frame for anything but the ground (use mate), guess interface ids, mate incompatible interfaces, silently choose rail/belt length, depict open stock as a rigid full-length box once routed, claim the route is manufacturing geometry, or infer tension, tooth engagement, clamp strength or minimum bend radius.
-
Returns: a locked reference with resolved placement and source snapshot, or a saved non-manufacturing belt centerline tied to frozen pitch geometry with explicit length validation; or an actionable refusal.
-
Called as:
edit {tool: "component", args: "{…}"}
| Argument | Type | Required | Meaning |
|---|---|---|---|
action |
String | yes | Place, move (keeps its instance id, so checks still find it), route or detach an open belt, remove, show or hide a fixed reference component |
catalog_id |
String | no | Exact stable catalogue id from catalog inspection; required for place |
instance |
String | no | Placed instance id such as component-1; required for move, remove, show or hide |
replaces |
String | no | For place: a placed instance id this part replaces (it is removed, its fits pass on and checks that name it follow the new one) |
origin |
[Double] | no | Fixed placement origin [x,y,z] in millimetres, for the ground only, or move; omit it and mate places the part by its ports |
rotation |
[Double] | no | Optional intrinsic [roll,pitch,yaw] rotation in degrees; defaults to [0,0,0] |
parameters |
[ComponentParameterArgs] | no | Required values named by catalogue inspection; one name/value item per parameter |
mate |
PartMateArgs | no | For place: put it where it goes in the same call, as the mate tool does: its port (a catalogue interface such as shaft_axis or inner_race) on a partner's port, or at to_point on the partner |
source_interface |
String | no | Named interface on the new component, such as mounting_face, to mate it to a placed part in this call; there is no typed target frame (a position from datums is a mate to that datum) |
target_instance |
String | no | Placed component instance to mate to; use with target_interface |
target_interface |
String | no | Named interface on target_instance; use the exact id returned by inspect |
offset |
[Double] | no | Optional [x,y,z] offset in target-interface coordinates, mm |
mate_rotation |
Double | no | Optional rotation in degrees around the target interface Z axis |
reverse_facing |
Bool | no | Flip the source to face the target while preserving a right-handed frame |
belt_instance |
String | no | For route_belt: placed catalogue belt-stock instance |
drive_instance |
String | no | For route_belt: placed exact drive-pulley instance |
idler_instance |
String | no | For route_belt: placed exact toothed-idler instance |
clamp_center |
[Double] | no | For route_belt: model-space point locating the deliberate gap between the two clamp entries |
clamp_gap_mm |
Double | no | For route_belt: required gap between clamp entries in mm; must accommodate both straight tails |
minimum_clamp_engagement_mm |
Double | no | Required route_belt learner design minimum tail engagement, mm; no retention certification |
clamp_capacity_each_mm |
Double | no | Required route_belt actual capacity of each modeled clamp, mm; two capacities must fit the gap |
tangent_clearance_mm |
Double | no | Required route_belt learner design clearance between the clamp gap and each pulley tangent, mm |
component_feature
Generate an ordinary editable feature from a sourced operation on a placed component interface.
-
Use when: inspect the placed component, choose an operation the interface actually lists, target one exact Body, and explicitly choose fabrication diameter for the process. For a placed magnet use magnet_pocket with fit press or glue instead: it sizes the pocket from the magnet and refuses a spot too thin to hold it. For a placed sealed pivot use bearing_seat on seat_face with the fixed Body, then bearing_seat on pivot_axis with the swinging Body: it sizes and builds both sides and mates them, with no fabrication diameter. For a placed screw use screw_hole with fit close, normal, loose, counterbore, countersink or tap: it sizes the hole from the screw's standard plus the printing allowance, so never guess a screw's hole.
-
Don't: invent unsupported counterbores, nut traps or access envelopes; confuse nominal component size with a clearance/press-fit cutter size; generate on a rotated non-origin-plane interface.
-
Returns: an editable Hole feature linked to source component instance, interface, catalog revision and operation, with nominal and fabrication dimensions kept separate.
-
Called as:
edit {tool: "component_feature", args: "{…}"}
| Argument | Type | Required | Meaning |
|---|---|---|---|
instance |
String | yes | Placed component instance from inspect, such as component-1 |
interface |
String | yes | Exact named interface from inspect, such as mounting_face |
operation |
String | yes | A sourced operation listed by inspect |
body |
String | no | Target Body name from inspect |
bodyIndex |
Int | no | Explicit signed target Body identity; takes precedence over body |
fabrication_diameter_mm |
Double | no | Explicit cutter diameter in mm chosen for the material/process; never inferred from nominal catalog size. Required except for magnet_pocket and screw_hole |
fit |
String | no | magnet_pocket: press (snug) or glue (looser, deeper). screw_hole: close, normal, loose (ISO 273 clearances), counterbore (socket heads), countersink (countersunk heads) or tap (tap drill); sizes the hole from the placed screw plus the printing allowance |
through |
Bool | no | true cuts through the Body; defaults true |
depth_mm |
Double | no | Blind depth in mm; use with through false |
Repeat/edit
pattern
Repeat an Extrude, Revolve or Holes source as a linked linear row/grid or circular feature pattern.
-
Use when: copies must follow source edits; count includes original, linear spacing is pitch in mm, circular spacing is sweep in degrees.
-
Don't: repeat Pattern/Mirror sources, exceed 256 total instances or leave positive model space; sourceIndex differs from index of the Pattern being edited.
-
Returns: editable linked copies; New sources create Bodies, Add/Cut/Holes preserve their target.
-
Called as:
edit {tool: "pattern", args: "{…}"}
| Argument | Type | Required | Meaning |
|---|---|---|---|
source |
String | no | Source feature's name from inspect: an Extrude, Revolve, Loft, Holes or Gear feature. Repeats its tool, including subsequent source edits |
feature |
String | no | Edit an existing Pattern by its name from inspect; supply only changed values |
kind |
String | no | linear repeats at equal pitch; circular rotates around an axis |
count |
Int | no | Total instances including the original, 2 to 256 |
spacing |
Double | no | Linear pitch in mm. Circular sweep in degrees: 360 divides the turn evenly; a partial sweep includes both ends |
axis |
String | no | Positive world axis x, y or z |
center |
[Double] | no | Circular centre [x,y,z] in mm |
rows |
Int | no | Linear grid rows including the original row; total instances cannot exceed 256 |
rowSpacing |
Double | no | Linear grid row pitch in mm; second direction is Y, or X when the first axis is Y |
sourceIndex |
Int | no | Explicit zero-based source feature index; takes precedence over source name |
index |
Int | no | Explicit zero-based Pattern index to edit; takes precedence over feature name |
mirror
Replay a supported source feature across an offset Right/X, Front/Y or Top/Z origin plane as linked symmetry.
-
Use when: a mirrored copy must follow its source; choose source/sourceIndex and world plane coordinate, or feature/index to edit the Mirror.
-
Don't: treat offset as translation, leave positive model space or mirror Holes out of their source face.
-
Returns: linked mirrored tool; New makes Bodies and Add/Cut/Holes retain the target.
-
Called as:
edit {tool: "mirror", args: "{…}"}
| Argument | Type | Required | Meaning |
|---|---|---|---|
source |
String | no | Source feature name from inspect: an Extrude, Revolve, Loft, Holes or Gear feature |
feature |
String | no | Edit an existing Mirror by name from inspect; supply only changed values |
plane |
String | no | Mirror plane: right (X), front (Y) or top (Z) |
offset |
Double | no | Plane coordinate in mm along positive X/Y/Z from the origin; choose an offset keeping all copies in positive model space |
sourceIndex |
Int | no | Explicit zero-based source feature index; takes precedence over source name |
index |
Int | no | Explicit zero-based Mirror index to edit; takes precedence over feature name |
name
Rename a sketch or feature with a meaningful saved History label, addressed by feature or explicit zero-based index.
-
Use when: renaming later; a new extrude, revolve or gear takes its own name instead. Re-inspect Body labels after naming their producer.
-
Don't: assume a separate Body-rename API or parse numeric-looking/repeated names as indices.
-
Returns: saved feature name and unchanged geometry.
-
Called as:
edit {tool: "name", args: "{…}"}
| Argument | Type | Required | Meaning |
|---|---|---|---|
feature |
String | no | The sketch or feature's current name from inspect; use index for a number |
name |
String | yes | A short, meaningful name, such as Base, Lid lip or Standoffs; up to 80 characters |
index |
Int | no | The zero-based index in inspect's features; takes precedence over feature |
edit
Call any tool that isn't offered by name: tool names it and args is its JSON arguments as one string. With tool alone it returns that tool's rules and argument schema, changing nothing: read them before the first call of a tool.
- Use when: a change to a part that exists, one feature at a time (sketch, draw, extrude, revolve, hole, shell, fillet, pattern, mirror, split, outline, loft, gear, point, name, appearance, or edit {feature, value} for one number), a learner's question about one, and the tools not offered by name: measure, catalog, component, mechanism, fit_around, fix, heat_insert, assembly, component_feature, cycloidal_stage, enclosure, design_recipe, made_by, print_bed. Example: edit {"tool":"hole","args":"{"plane":"top","offset":6,"outward":1,"centers":[[20,15]],"diameter":3.4,"through":true}"}.
- Don't: build a new part feature by feature (part builds one in a call), guess a tool's arguments (call edit with tool alone to read them), rebuild unrelated learner work, or name a listed tool.
- Returns: the named tool's own result and one undo step when it changes the Part; a numeric edit refuses newly broken features with dependent_feature_failure, and changed:false needs no undo.
| Argument | Type | Required | Meaning |
|---|---|---|---|
feature |
String | no | The feature's name from inspect's features, e.g. "Extrude 2" |
value |
Double | yes | Its new number: an extrusion's distance or a fillet's radius in mm, a revolve's angle in degrees |
index |
Int | no | The zero-based index in inspect's features; takes precedence over feature |
chamfer |
Bool | no | For an existing fillet/chamfer only: true makes a chamfer, false makes a round. Omit to keep its current kind. |
fix
Apply the engine's verified fix for one open finding in the ledger, by its subject.
-
Use when: the ledger lists an open finding with a fix (open: Shaft overlaps component-1 -> fix: fix {"subject":"Shaft overlaps component-1"}). Kinds the engine verifies: move_along_mate (re-mate with an offset that clears the measured overlap along the partner port's axis), rebind_port (bind the hole that realises a port whose hole is gone), add_joint (mate a rotor's bore to the coaxial axis it sits on, where it sits, so the mates' mechanism gets its hinge). The fix runs on a copy first and is kept only when the finding is gone and the brief's rows, every mate, motion and the pair's engagement still hold. Example: fix {"subject":"Shaft overlaps component-1"}.
-
Don't: fix a finding the ledger shows with no fix found (change the design instead), retry a fix that failed with the same Part (the reason names what it broke), or fix the same subject after it is deferred.
-
Returns: subject, applied, fix (its kind), change and held (every requirement rechecked after the fix: the brief's rows, mates resolving, motion, the pair's engagement); one undo step. A fix whose check fails leaves the Part unchanged and returns the finding with why; three failures defer the subject.
-
Called as:
edit {tool: "fix", args: "{…}"}
| Argument | Type | Required | Meaning |
|---|---|---|---|
subject |
String | yes | The finding's subject exactly as the ledger's open: line names it (Shaft overlaps component-1) |
appearance
Set saved sRGB colour as #RRGGBB, opacity 0…1, or reset true alone, for one Body or for many at once with bodies [{body or bodyIndex, colour, opacity, reset}]; omitted components stay unchanged.
-
Use when: colouring inspected Bodies or making a lid translucent: 0 invisible, 0.4 translucent, 1 solid. Colour every Body of a design in one call with bodies, one undo step; finish the sketch first.
-
Don't: alter geometry, hidden/show state, theme, faces or print material; STL/STEP/current 3MF remain geometry-only. Respect native drafts/import/guided guards.
-
Returns: saved RGB/opacity and one Undoable document edit; manufacturing geometry/placement unchanged.
-
Called as:
edit {tool: "appearance", args: "{…}"}
| Argument | Type | Required | Meaning |
|---|---|---|---|
body |
String | no | One Body name from inspect's bodies; omit only when there is one Body |
bodyIndex |
Int | no | Explicit signed Body identity from inspect; overrides body name |
colour |
String | no | sRGB colour as #RRGGBB, such as #007AFF for blue. Omit to keep the current colour |
opacity |
Double | no | Display opacity from 0 (invisible) to 1 (solid); 0.4 is translucent. Omit to keep current opacity |
reset |
Bool | no | true restores the default Body appearance; do not combine with colour or opacity |
bodies |
[BodyAppearanceItem] | no | Several Bodies in one call and one undo step, each with its own body or bodyIndex and colour, opacity or reset; use alone, without the fields above |
undo
Undo one operation, or answer true to revert the previous changed Ask answer's checkpoint.
- Use when: the learner requests reversion or a verified erroneous operation needs correction.
- Don't: claim Redo, arbitrary History deletion, or removal of unrelated earlier learner work.
- Returns: restored Part summary, or an explicit no-earlier-answer/history refusal.
| Argument | Type | Required | Meaning |
|---|---|---|---|
answer |
Bool | no | true to take back everything your previous answer changed (the learner said revert or undo that); omit to undo one step |
point
Inspect a numbered pin in this message, then perform only its checked hole, whole-Shell or pinned-edge fillet edit with value in mm.
-
Use when: editing a learner's pinned target; inspect first and revalidate its session/geometry identity.
-
Don't: guess a hole from a surface point, broaden location scope to wholeShell, use unscoped mutation with pins or reuse a stale target; ask for a re-pick.
-
Returns: resolved target evidence or a scope-safe edit/refusal; wholeShell requires explicit note scope.
-
Called as:
edit {tool: "point", args: "{…}"}
| Argument | Type | Required | Meaning |
|---|---|---|---|
pin |
Int | yes | Number of the learner's pin in this message |
action |
String | yes | Inspect first. hole changes one bore diameter; shell changes ALL walls and floor and requires the learner's wholeShell scope on the note; otherwise ask first. fillet rounds only the pinned edge. |
value |
Double | no | New diameter, wall thickness or edge radius in mm; inspect needs no value |
assembly
Inspect/edit ownership, anchors, live attachments and frozen reusable modules with immutable occurrence UUIDs and pinned revisions.
-
Use when: inspect interfaces; bounded candidates then explicitly chosen candidate_id/place. Browse modules; module_save/place/unique/publish preserve real native Bodies and source provenance (only module_publish requires provenance; the learner's own module_save needs none, and module_place name names the copy). module_update_preview, component_replace_preview and feature_repair_preview return consequence reports; change_accept requires the exact current ticket_id. feature_detach preserves ordinary geometry. fit declares the designed contact between two pieces (between: two Body names or component instance_ids; kind press, thread, bearing_seat, cross_pin, slot_tab or resting; optional allowance_mm up to 1): a printed key pressed in a pocket, a laser-cut plate resting in a slot, a cross pin through a shaft. checkpoint, component_check and check_motion then accept that overlap or zero gap and still flag material deeper than the allowance; unfit removes it. Catalogue hardware, attachments, mates and Connect… declare their own. Native UI and Ask share transactions; revisions never update implicitly. During a new cloud Ask build only, independent with a 10–200 character name records why the brief requests unrelated print-layout items instead of an assembly; this app-owned scope declaration changes no geometry and is never verified assembly evidence.
-
Don't: guess UUIDs, occupy a target twice, create dependency cycles, silently promote fixed mates, or claim nominal compatibility certifies fit. Suppression disables only the relation; the part remains in BOM and checks.
-
Returns: bounded occurrence/children, interfaces, mathematical resolution and separate mechanical review status; each edit is one undo step. Unsupported moved feature/route dependencies retain geometry marked stale.
-
Called as:
edit {tool: "assembly", args: "{…}"}
| Argument | Type | Required | Meaning |
|---|---|---|---|
manufacturing_kind |
String | no | For classify: printed, purchased or reference. A reference Body is a non-printing external fixture but stays in assembly/material checks |
action |
String | yes | Inspect/group/attach, browse frozen modules, save/place/make unique/publish/unpack, or explicitly preview and accept replacement/repair |
between |
[String] | no | For fit/unfit: the two pieces, Body names or placed component instance_id values, e.g. ["Back plate", "Base"] |
kind |
String | no | For fit: the designed contact; checks then accept that overlap or zero gap and flag only material deeper than its allowance |
allowance_mm |
Double | no | For fit: optional allowance in mm, 0 to 1; defaults press 0.3, thread 0.5, bearing_seat 0.2, cross_pin 0.3, slot_tab 0.3, resting 0.05 |
id |
String | no | Exact occurrence UUID from assembly inspection; omit to inspect root |
revision |
String | no | Exact frozen revision hash from modules; place/update never follows latest implicitly |
ticket_id |
String | no | Exact current ticket_id from change preview; stale or foreign tickets are refused |
catalog_id |
String | no | Replacement source-backed catalog id from catalog inspection |
parameters |
[ComponentParameterArgs] | no | Replacement parameters, explicit distinct name/value pairs |
feature_index |
Int | no | Exact feature index from inspection for repair/detach; author may explicitly assign a legacy sketch to the chosen body or shared layout |
overwrite_override |
Bool | no | Explicit acknowledgement to replace learner-edited Hole centers/plane during repair; current fabrication dimensions remain |
scope_id |
String | no | For candidates: exact target scope assembly UUID; defaults to root. Coverage is bounded; narrow the scope if truncated. |
search_radius_mm |
Double | no | For candidates: optional positive nearby radius in millimetres around the moving occurrence. Omit for the whole chosen scope; distant interfaces are not checked. |
candidate_id |
String | no | For place: exact current candidate_id returned by candidates. Explicitly choose among ambiguous targets. Stale tickets are refused. |
occurrences |
[String] | no | For group: up to 256 distinct occurrence UUIDs, without overlapping subtrees |
name |
String | no | For independent: 10–200 character reason the brief requests unrelated items sharing a print layout (not an assembly). For group/rename: group display name, 1 to 100 characters; module_save: module name; module_place: this copy's name, such as Pi sled 2. Bought parts keep their catalogue title and cannot be renamed |
parent_id |
String | no | For group/reparent: exact destination assembly UUID; group defaults to root |
origin |
[Double] | no | For move: replacement local origin [x,y,z] mm in parent coordinates. For author new/layout: the ground's world origin; omit for a part that mate will place |
rotation |
[Double] | no | For move: replacement local [roll,pitch,yaw] degrees, defaults zero |
mode |
String | no | For view: assembly or fabrication. For author: body (occurrence id), new (planned world origin/rotation), layout (shared skeleton), or finish. Choose before sketching or direct creation |
interface |
String | no | Exact source interface id, or stable project anchor id for anchor/remove_anchor |
target_id |
String | no | Exact target occurrence UUID for attach/repair |
target_interface |
String | no | Exact target interface id from inspection |
provenance |
String | no | Required for module_publish and anchor (optional for the learner's own module_save and module_unique): authored provenance or design basis in words, e.g. "Pi 5 sled designed in this Part"; never manufacturer certification |
offset |
[Double] | no | Attachment target-local offset [x,y,z] mm |
angle |
Double | no | Attachment rotation around target Z in degrees |
reverse |
Bool | no | Reverse attachment facing |
suppressed |
Bool | no | Suppress only the relation; physical part stays fixed in ownership, BOM and checks |
preview |
Bool | no | Return affected descendant preview without changing the document |
Clarify
ask_learner
Ask 1–3 material design questions (at most 80 characters each) with 2–4 choices of at most 40 characters, a default list of suggested option indices ([0], or [] for none) and optional multiple selection. When choices are Bodies, pictures gives each option's exact Body name ("" for none) and the app pictures them from the Part.
- Use when: missing information about the learner's intent materially changes the design, never for leave to repair or replace your own failed work (fix it and carry on); after asking stop and wait for the learner's next message.
- Don't: ask whether to model a part the catalogue lacks when the brief gives its numbers (model it: gear for gears), ask the learner to measure a standard board before using reference/catalog, repeat a measurement request after they say to choose, invent sourced dimensions, or make queued edits after asking. Use stated allowances or adjustable geometry for unsourced details.
- Returns: a question card; no design choice is accepted until the learner responds.
| Argument | Type | Required | Meaning |
|---|---|---|---|
replacement_ticket |
String | no | Exact validated replacement ticket; shows its consequences and asks for approval |
questions |
[QuestionArgs] | yes | 1 to 3 questions whose answers change the design |
plan
Keep the learner's live plan, which they watch while you build: an optional one-line goal, the piece you build now and the next piece, each {text, check} (the check that proves it works), and the assumptions you make [{id, text}]; construction {…} saves the construction spec (roles, parameters, datums, ports, joints, passages and zones) that part, mate and fit_around build from, grown a piece at a time; read its fields with edit {tool: construction} before the first draft.
- Use when: a build begins (the first piece, and every size, part or fit you assume that the learner didn't give, as an assumption before the geometry that rests on it) and each time you move to the next piece: a new piece ticks the one before. Always send it in the same reply as another call. Plain maker words; hardware by its standard name. Example: plan {"piece":{"text":"Motor pinion and 54T gear","check":"the 18→54 mesh turns"},"next":{"text":"Carrier on its two bearings","check":"the bearings sit in their seats"},"construction":{"action":"draft","plan":{"name":"Transaxle","parameters":[],"datums":[{"name":"motor_axis","position":["0","0","20"]}],"features":[]}}}.
- Don't: list the whole object's parts or steps up front (plan holds only the piece now and the next), send it in a reply of its own, resend unchanged items, tick required parts or checks (the app ticks those from the Part), or remove an item: drop it with dropped:"<reason>" and it stays struck through. At most 12 assumptions; a piece's text and check share 160 characters.
- Returns: one line (Plan: 4/5 steps, 3 assumptions), or with no arguments the whole plan; a refusal changes nothing.
| Argument | Type | Required | Meaning |
|---|---|---|---|
goal |
String | no | The build in one line, only to restate the learner's request |
piece |
PlanPieceArgs | no | The piece you build now; sending it ticks the piece before |
next |
PlanPieceArgs | no | The piece after this one, grown from it |
steps |
[PlanStepArgs] | no | Tick or drop steps already on the plan by id |
assumptions |
[PlanAssumptionArgs] | no | Only the assumptions that are new or changed |
Answer
finish
End the question with the answer's facts as short plain fields: built, deviations, assumed, risk, skipped, unchecked. deviations is every way the build differs from what was asked; it is never cut from the answer.
- Use when: every question, as the very last call, once the work and its checks are done; leave a field empty when it has nothing to say.
- Don't: call it before the last edit or check, write Markdown or lists in a field, or write an answer after it: reply only Done.
- Returns: an acknowledgement; the app writes the learner's short answer from the fields.
| Argument | Type | Required | Meaning |
|---|---|---|---|
built |
String | yes | One plain sentence: what you made or changed; in a guided project, your coaching |
deviations |
String | no | Every way the build differs from what the learner asked; leave empty when it does not, never write None; always shown |
assumed |
String | yes | One plain sentence: any common part or size you assumed; leave empty when there is nothing, never write None |
risk |
String | yes | One plain sentence: the one key risk; leave empty when there is nothing, never write None |
skipped |
String | yes | One plain sentence: what you left out; leave empty when there is nothing, never write None |
unchecked |
String | yes | A short phrase: what you didn't check; leave empty when there is nothing, never write None |
Mechanism
mechanism
Declare, replace or clear the Part's mechanism: ground Body, revolute joints between declared bores (flat about Z, or a hinge about any axis, such as a lid on its pin), prismatic slides (rod in bore, along Z or in XY) with travel limits, external gear couplings, a rotary or linear driver, transmissions and grip faces.
-
Use when: a design must move. Call mechanism {} with no arguments to inspect the saved record and Ask's retained unsaved proposal/last accepted ideal layout. Repair the named interface, preserving accepted datums; after any joint change rerun preview before detail. Inspect for signed Body IDs and the saved record, then send the WHOLE record with its saved snake_case fields (mm, radians, a Z stack per bore), or clear true alone. A plunger or solenoid drives a slide with min_travel/max_travel in mm; a part carried by it (a pop bumper's ring) is a rigid follower, fastened to it by hardware, whose own rods are slides checked as guides. Mount frames are in the leader Body's own print-layout coordinates. A solenoid's leader is the slide's fixed guide Body and its frame z points against the slide axis (give only origin to derive it). A mounted shaft must span the rod band in its Body's own Z, from source_z_min for z_max - z_min mm. A lid hinge is a revolute about the pin's axis, typically horizontal along the box's back edge: give that joint axis [x,y,z] (the lid opens by positive angles, right hand; a lid on a pin along X at the box's +Y edge opens upward with axis [-1,0,0]), and each side's center [x,y,z] as the same point on the pin's axis in that Body's print layout, its hole diameter and span [from,to] mm along the axis. Print the lid as it sits closed; mount the pin (a catalog shaft) on the base or lid along the axis, through both holes.
-
Don't: invent joint types (cams, springs, belts, internal gears), declare a bore where there is material, mix a vertical slide into a loop of planar joints, let four-bar or parallelogram links line up anywhere in the driver travel (a fold), or treat a saved record as proof it moves; call check_motion next.
-
Returns: the saved record in the Part summary as one undo step, or a refusal naming the Body, joint, slide, bore or face to fix with nothing changed. For an early linkage use preview:true with the whole record and optional wheelbase_mm/steering_lock_deg/wheel_travel_mm/track_mm: unsaved ideal closure, steering and sampled printed-body interference, physical_verified:false. Resolve the full requested ranges before refining a corner or repeating it. Physical spherical joints need hardware.ball_joints [{joint,rod_end,pin,retainer}] and actual mounted captive ball/cup hardware; plate holes are insufficient. Threaded housings also need hardware.thread_connections [{male,female,minimum_engagement_mm}]; frozen catalogue axes, diameter/pitch/hand, available depth and real engagement are checked. Use the components' mating interfaces for full 3D alignment; a rigid follower is not proof of a physical connection.
-
Called as:
edit {tool: "mechanism", args: "{…}"}
| Argument | Type | Required | Meaning |
|---|---|---|---|
preview |
Bool | no | true checks this proposed linkage as an unsaved ideal skeleton over its full ranges, before cutting bores or placing hardware. Returns closure, steering and sampled body interference; never physical verification. Add wheelbase_mm and steering_lock_deg for targets |
track_mm |
Double | no | Required wheel-centre track from the brief, mm; checked against actual geometry within 0.5 mm |
wheelbase_mm |
Double | no | |
steering_lock_deg |
Double | no | |
wheel_travel_mm |
Double | no | Required total wheel-centre suspension travel in mm; each side must reach it independently |
clear |
Bool | no | true alone removes the saved mechanism |
ground_body |
Int | no | Signed Body ID that stays fixed |
revolute_joints |
[MechanismJointArgs] | no | Every revolute joint; the record replaces the saved one whole |
prismatic_joints |
[MechanismSlideArgs] | no | Every prismatic slide (rod in bore along Z, or in XY); a slide on a rigid follower is a checked guide |
gear_couplings |
[MechanismGearArgs] | no | Meshing native Gear pairs, one per mesh. With hinges, each Gear turns on a hinge along its shaft (planets on the carrier), all shafts parallel; the case is the ground |
driver |
MechanismDriverArgs | no | |
ball_joints |
[MechanismBallArgs] | no | Linkage only: ball joints closing loops, such as a tie rod's two ends |
inputs |
[MechanismDriverArgs] | no | Linkage only: inputs beside the driver, each a hinge with min_angle and max_angle (suspension at one lower arm, wheel spin); Play gives each its own control |
transmissions |
[MechanismTransmissionArgs] | no | Optional transmission angles to report |
grip_faces |
[MechanismGripFaceArgs] | no | A gripper's two opposing material-backed pad bands. Default common contact target 20 × 10 mm throughout travel. XY in saved Body coordinates; Z in assembled stack for planar bores, Body-local Z for a spatial linkage. check motion reports actual overlap and opening |
rigid_followers |
[MechanismFollowerArgs] | no | Bodies with no joint of their own fixed to a moving leader, such as a bat on a gear's shaft or a pop bumper's ring on its rods (checked as guides); each must be fastened to its leader by a screw, pin or rod in hardware; preserve saved ones when replacing the record |
hardware |
MechanismHardwareArgs | no | Placed purchased parts carried by Bodies: each mount's frame is the component's frame in its leader Body's print-layout coordinates, so it moves with that Body. Preserve the complete inspected record when replacing |
check_motion
Check the declared mechanism over its driver range: bores and rods, one-DOF motion, slide travel and guide engagement, gear meshing, collisions, grip closing and an optional quasi-static holding force.
-
Use when: after mechanism or any geometry edit; give torque_nmm, friction_coefficient and object_mass_kg together for physics (object_diameters_mm defaults to [20,45]), or none for motion only. A steered linkage also returns steering (each wheel's steer at the driver's ends and rest, inner and outer lock, Ackermann, travel and bump steer at the wheel, and findings), even when a collision fails the check; give wheelbase_mm, steering_lock_deg, wheel_travel_mm and track_mm from the brief to compare. The mechanism is done only at ok:true with the requested objects held; on a motion fold, change link geometry or travel, not just a smaller range that loses the required opening.
-
Don't: claim whole-assembly verification from ok alone. Read coverage, including hidden/unmounted parts; restore required mounts and repair geometry rather than remove a required part from the check. Physics is quasi-static only, without impacts, slip over time or print strength. It changes nothing.
-
Returns: JSON ok with stage/message on failure, dof, poses, driver range, slide travel/clearance, transmission angles, grip gaps and force/hold. coverage lists declared, excluded and missing Bodies/components, checks_completed and complete; drive_verification separately reports a powered drive as verified, not_verified or not_declared.
-
Called as:
check {motion: {…}}
| Argument | Type | Required | Meaning |
|---|---|---|---|
track_mm |
Double | no | Required wheel-centre track from the brief, mm; compared with actual geometry within 0.5 mm |
wheel_travel_mm |
Double | no | Required total wheel-centre suspension travel in mm; compares measured travel and independent left/right inputs |
torque_nmm |
Double | no | Driver torque in N·mm; give with friction_coefficient and object_mass_kg, or omit all for motion only |
friction_coefficient |
Double | no | Jaw-object friction coefficient, such as 0.3 for PLA |
object_mass_kg |
Double | no | Test object's mass in kg |
object_diameters_mm |
[Double] | no | Round test object diameters in mm; default [20, 45] |
wheelbase_mm |
Double | no | A steered car's wheelbase, front to rear axle, in mm: steering compares each lock with Ackermann for it |
steering_lock_deg |
Double | no | The wheel steer angle the brief asks for, in degrees: steering.lock says whether the inner wheel reaches it both ways |
Make
made_by
Set how one Body is made: printed, laser_cut (from a sheet: material, thickness mm, kerf mm; defaults acrylic at the Body's own thickness, 0.15 kerf) or bought.
-
Use when: a flat sheet part (acrylic key, plywood panel, divider) should be laser cut, or a Body is bought hardware; inspect first for its exact name or signed ID.
-
Don't: laser cut a Body that isn't a flat sheet (it refuses steps and sloped edges: keep it printed or flatten it), give a sheet thinner or thicker than the Body, or claim MakerSketch can't make a cut file.
-
Returns: one Undoable change; laser-cut Bodies leave the print plates and nest on A4 sheets, returned as cut_sheets reads them.
-
Called as:
edit {tool: "made_by", args: "{…}"}
| Argument | Type | Required | Meaning |
|---|---|---|---|
body |
String | no | One Body name from inspect's bodies; omit only when there is one Body |
bodyIndex |
Int | no | Explicit signed Body identity from inspect; overrides body name |
method |
String | yes | How the Body is made |
material |
String | no | laser_cut only: sheet material, such as Acrylic or Plywood; default Acrylic |
thickness |
Double | no | laser_cut only: sheet thickness in mm, equal to the Body's; default the Body's own |
kerf |
Double | no | laser_cut only: kerf in mm, the width the laser burns away; default 0.15 |
cut_sheets
Read the A4 sheets the laser-cut Bodies nest on (5 mm margin, 3 mm gap), per material and thickness, and the SVG/DXF cut files they export.
-
Use when: checking a laser-cut part landed on a sheet, how many sheets a set needs, or what the learner exports to the laser.
-
Don't: expect hidden parts: anything too big for A4 or not flat is listed in left_off with the reason to fix.
-
Returns: sets with each part's sheet, size and turn, left_off Bodies with reasons, and the cut file names; read-only.
-
Called as:
inspect {report: "cut_sheets"}
print_bed
Set the learner's 3D printer bed (width and depth in mm) so Make's plates start from their printer, in this Part and the next.
-
Use when: as soon as the learner names their bed or printer size ("my bed is 256 mm"); depth defaults to width for a square bed.
-
Don't: guess a bed the learner didn't give, or set it to make an oversized Body fit: split or turn the Body instead.
-
Returns: one Undoable change; the bed, how many plates and pieces it takes, and too_big Bodies with their size.
-
Called as:
edit {tool: "print_bed", args: "{…}"}
| Argument | Type | Required | Meaning |
|---|---|---|---|
width |
Double | yes | The printer bed's width (X) in mm, as the learner gave it, such as 256 |
depth |
Double | no | The bed's depth (Y) in mm; omit for a square bed |